func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool,
	jsonOnlyWhen, toArrayWhen, omitEmptyWhen *bool,
	ti *TypeInfos, types ...reflect.Type) (warnings []string) {
	if len(types) == 0 {
		return
	}
	x := genRunner{
		w:             w,
		t:             types,
		te:            make(map[uintptr]bool),
		td:            make(map[uintptr]bool),
		tz:            make(map[uintptr]bool),
		im:            make(map[string]reflect.Type),
		imn:           make(map[string]string),
		is:            make(map[reflect.Type]struct{}),
		tm:            make(map[reflect.Type]struct{}),
		ty:            make(map[reflect.Type]struct{}),
		ts:            []reflect.Type{},
		bp:            genImportPath(types[0]),
		xs:            uid,
		ti:            ti,
		jsonOnlyWhen:  jsonOnlyWhen,
		toArrayWhen:   toArrayWhen,
		omitEmptyWhen: omitEmptyWhen,
		nx: noExtensions,
	}
	if x.ti == nil {
		x.ti = defTypeInfos
	}
	if x.xs == "" {
		rr := rand.New(rand.NewSource(time.Now().UnixNano()))
		x.xs = strconv.FormatInt(rr.Int63n(9999), 10)
	}
	x.cp = genImportPath(reflect.TypeOf(x))
	x.imn[x.cp] = genCodecPkg
	for i := 0; i < len(x.t); {
		t := x.t[i]
		if genImportPath(t) != x.bp {
			halt.onerror(errGenAllTypesSamePkg)
		}
		ti1 := x.ti.get(rt2id(t), t)
		if ti1.flagMissingFielder || ti1.flagMissingFielderPtr {
			warnings = append(warnings, fmt.Sprintf("type: '%v' not generated; implements codec.MissingFielder", t))
			copy(x.t[i:], x.t[i+1:])
			x.t = x.t[:len(x.t)-1]
			continue
		}
		x.genRefPkgs(t)
		i++
	}
	x.line("// +build go1.6")
	if buildTags != "" {
		x.line("// +build " + buildTags)
	}
	x.line(`
`)
	x.line("package " + pkgName)
	x.line("")
	x.line("import (")
	if x.cp != x.bp {
		x.cpfx = genCodecPkg + "."
		x.linef("%s \"%s\"", genCodecPkg, x.cp)
	}
	imKeys := make([]string, 0, len(x.im))
	for k := range x.im {
		imKeys = append(imKeys, k)
	}
	sort.Strings(imKeys)
	for _, k := range imKeys {  
		if k == x.imn[k] {
			x.linef("\"%s\"", k)
		} else {
			x.linef("%s \"%s\"", x.imn[k], k)
		}
	}
	for _, k := range [...]string{"runtime", "errors", "strconv"} {  
		if _, ok := x.im[k]; !ok {
			x.line("\"" + k + "\"")
		}
	}
	x.line(")")
	x.line("")
	x.line("const (")
	x.linef("// ----- content types ----")
	x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8))
	x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW))
	x.linef("// ----- value types used ----")
	for _, vt := range [...]valueType{
		valueTypeArray, valueTypeMap, valueTypeString,
		valueTypeInt, valueTypeUint, valueTypeFloat,
		valueTypeNil,
	} {
		x.linef("codecSelferValueType%s%s = %v", vt.String(), x.xs, int64(vt))
	}
	x.linef("codecSelferBitsize%s = uint8(32 << (^uint(0) >> 63))", x.xs)
	x.linef("codecSelferDecContainerLenNil%s = %d", x.xs, int64(containerLenNil))
	x.line(")")
	x.line("var (")
	x.line("errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + " = " + "errors.New(`only encoded map or array can be decoded into a struct`)")
	x.line(")")
	x.line("")
	x.hn = "codecSelfer" + x.xs
	x.line("type " + x.hn + " struct{}")
	x.line("")
	x.linef("func %sFalse() bool { return false }", x.hn)
	x.linef("func %sTrue() bool { return true }", x.hn)
	x.line("")
	x.varsfxreset()
	x.line("func init() {")
	x.linef("if %sGenVersion != %v {", x.cpfx, genVersion)
	x.line("_, file, _, _ := runtime.Caller(0)")
	x.linef("ver := strconv.FormatInt(int64(%sGenVersion), 10)", x.cpfx)
	x.outf(`panic(errors.New("codecgen version mismatch: current: %v, need " + ver + ". Re-generate file: " + file))`, genVersion)
	x.linef("}")
	if len(imKeys) > 0 {
		x.line("if false { // reference the types, but skip this branch at build/run time")
		for _, k := range imKeys {
			t := x.im[k]
			x.linef("var _ %s.%s", x.imn[k], t.Name())
		}
		x.line("} ")  
	}
	x.line("}")  
	x.line("")
	for _, t := range x.t {
		x.tc = t
		x.linef("func (%s) codecSelferViaCodecgen() {}", x.genTypeName(t))
		x.selfer(true)
		x.selfer(false)
		x.tryGenIsZero(t)
	}
	for _, t := range x.ts {
		rtid := rt2id(t)
		x.varsfxreset()
		x.linef("func (x %s) enc%s(v %s%s, e *%sEncoder) {", x.hn, x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), x.cpfx)
		x.genRequiredMethodVars(true)
		switch t.Kind() {
		case reflect.Array, reflect.Slice, reflect.Chan:
			x.encListFallback("v", t)
		case reflect.Map:
			x.encMapFallback("v", t)
		default:
			halt.onerror(errGenExpectArrayOrMap)
		}
		x.line("}")
		x.line("")
		x.varsfxreset()
		x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx)
		x.genRequiredMethodVars(false)
		switch t.Kind() {
		case reflect.Array, reflect.Slice, reflect.Chan:
			x.decListFallback("v", rtid, t)
		case reflect.Map:
			x.decMapFallback("v", rtid, t)
		default:
			halt.onerror(errGenExpectArrayOrMap)
		}
		x.line("}")
		x.line("")
	}
	for t := range x.ty {
		x.tryGenIsZero(t)
		x.line("")
	}
	x.line("")
	return
}
Gen will write a complete go file containing Selfer implementations for each
type passed. All the types must be in the same package.

Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINUOUSLY WITHOUT NOTICE.
package codec
import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"go/format"
	"io"
	"io/ioutil"
	"math/rand"
	"os"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"sync"
	"text/template"
	"time"
	"unicode"
	"unicode/utf8"
)
const genVersion = 25
const (
	genCodecPkg        = "codec1978"  
	genTempVarPfx      = "yy"
	genTopLevelVarName = "x"
	genAnythingCanBeNil = true
	genUseOneFunctionForDecStructMap = true
	genStructCanonical = false
	genFastpathCanonical = true
	genFastpathTrimTypes = true
	genDecStructArrayInlineLoopCheck = true
)
type genStructMapStyle uint8
type genStringDecAsBytes string
type genStringDecZC string
var genStringDecAsBytesTyp = reflect.TypeOf(genStringDecAsBytes(""))
var genStringDecZCTyp = reflect.TypeOf(genStringDecZC(""))
var genFormats = []string{"Json", "Cbor", "Msgpack", "Binc", "Simple"}
const (
	genStructMapStyleConsolidated genStructMapStyle = iota
	genStructMapStyleLenPrefix
	genStructMapStyleCheckBreak
)
var (
	errGenAllTypesSamePkg        = errors.New("All types must be in the same package")
	errGenExpectArrayOrMap       = errors.New("unexpected type - expecting array/map/slice")
	errGenUnexpectedTypeFastpath = errors.New("fast-path: unexpected type - requires map or slice")
	genBase64enc  = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__")
	genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`)
)
type genBuf struct {
	buf []byte
}
func (x *genBuf) sIf(b bool, s, t string) *genBuf {
	if b {
		x.buf = append(x.buf, s...)
	} else {
		x.buf = append(x.buf, t...)
	}
	return x
}
func (x *genBuf) s(s string) *genBuf              { x.buf = append(x.buf, s...); return x }
func (x *genBuf) b(s []byte) *genBuf              { x.buf = append(x.buf, s...); return x }
func (x *genBuf) v() string                       { return string(x.buf) }
func (x *genBuf) f(s string, args ...interface{}) { x.s(fmt.Sprintf(s, args...)) }
func (x *genBuf) reset() {
	if x.buf != nil {
		x.buf = x.buf[:0]
	}
}
type genRunner struct {
	w io.Writer  
	c uint64     
	f uint64     
	t  []reflect.Type    
	tc reflect.Type      
	te map[uintptr]bool  
	td map[uintptr]bool  
	tz map[uintptr]bool  
	cp string  
	im  map[string]reflect.Type  
	imn map[string]string        
	imc uint64                   
	is map[reflect.Type]struct{}  
	bp string                     
	cpfx string  
	ty map[reflect.Type]struct{}  
	tm map[reflect.Type]struct{}  
	ts []reflect.Type             
	xs string  
	hn string  
	ti *TypeInfos
	jsonOnlyWhen, toArrayWhen, omitEmptyWhen *bool
	nx bool  
}
type genIfClause struct {
	hasIf bool
}
func (g *genIfClause) end(x *genRunner) {
	if g.hasIf {
		x.line("}")
	}
}
func (g *genIfClause) c(last bool) (v string) {
	if last {
		if g.hasIf {
			v = " } else { "
		}
	} else if g.hasIf {
		v = " } else if "
	} else {
		v = "if "
		g.hasIf = true
	}
	return
}