1// Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved.
2// Use of this source code is governed by a MIT license found in the LICENSE file.
3
4package codec
5
6import (
7	"bytes"
8	"encoding/base64"
9	"errors"
10	"fmt"
11	"go/format"
12	"io"
13	"io/ioutil"
14	"math/rand"
15	"reflect"
16	"regexp"
17	"sort"
18	"strconv"
19	"strings"
20	"sync"
21	"text/template"
22	"time"
23	"unicode"
24	"unicode/utf8"
25)
26
27// ---------------------------------------------------
28// codecgen supports the full cycle of reflection-based codec:
29//    - RawExt
30//    - Raw
31//    - Builtins
32//    - Extensions
33//    - (Binary|Text|JSON)(Unm|M)arshal
34//    - generic by-kind
35//
36// This means that, for dynamic things, we MUST use reflection to at least get the reflect.Type.
37// In those areas, we try to only do reflection or interface-conversion when NECESSARY:
38//    - Extensions, only if Extensions are configured.
39//
40// However, codecgen doesn't support the following:
41//   - Canonical option. (codecgen IGNORES it currently)
42//     This is just because it has not been implemented.
43//
44// During encode/decode, Selfer takes precedence.
45// A type implementing Selfer will know how to encode/decode itself statically.
46//
47// The following field types are supported:
48//     array: [n]T
49//     slice: []T
50//     map: map[K]V
51//     primitive: [u]int[n], float(32|64), bool, string
52//     struct
53//
54// ---------------------------------------------------
55// Note that a Selfer cannot call (e|d).(En|De)code on itself,
56// as this will cause a circular reference, as (En|De)code will call Selfer methods.
57// Any type that implements Selfer must implement completely and not fallback to (En|De)code.
58//
59// In addition, code in this file manages the generation of fast-path implementations of
60// encode/decode of slices/maps of primitive keys/values.
61//
62// Users MUST re-generate their implementations whenever the code shape changes.
63// The generated code will panic if it was generated with a version older than the supporting library.
64// ---------------------------------------------------
65//
66// codec framework is very feature rich.
67// When encoding or decoding into an interface, it depends on the runtime type of the interface.
68// The type of the interface may be a named type, an extension, etc.
69// Consequently, we fallback to runtime codec for encoding/decoding interfaces.
70// In addition, we fallback for any value which cannot be guaranteed at runtime.
71// This allows us support ANY value, including any named types, specifically those which
72// do not implement our interfaces (e.g. Selfer).
73//
74// This explains some slowness compared to other code generation codecs (e.g. msgp).
75// This reduction in speed is only seen when your refers to interfaces,
76// e.g. type T struct { A interface{}; B []interface{}; C map[string]interface{} }
77//
78// codecgen will panic if the file was generated with an old version of the library in use.
79//
80// Note:
81//   It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil.
82//   This way, there isn't a function call overhead just to see that we should not enter a block of code.
83
84// GenVersion is the current version of codecgen.
85//
86// NOTE: Increment this value each time codecgen changes fundamentally.
87// Fundamental changes are:
88//   - helper methods change (signature change, new ones added, some removed, etc)
89//   - codecgen command line changes
90//
91// v1: Initial Version
92// v2:
93// v3: Changes for Kubernetes:
94//     changes in signature of some unpublished helper methods and codecgen cmdline arguments.
95// v4: Removed separator support from (en|de)cDriver, and refactored codec(gen)
96// v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections.
97const GenVersion = 5
98
99const (
100	genCodecPkg        = "codec1978"
101	genTempVarPfx      = "yy"
102	genTopLevelVarName = "x"
103
104	// ignore canBeNil parameter, and always set to true.
105	// This is because nil can appear anywhere, so we should always check.
106	genAnythingCanBeNil = true
107
108	// if genUseOneFunctionForDecStructMap, make a single codecDecodeSelferFromMap function;
109	// else make codecDecodeSelferFromMap{LenPrefix,CheckBreak} so that conditionals
110	// are not executed a lot.
111	//
112	// From testing, it didn't make much difference in runtime, so keep as true (one function only)
113	genUseOneFunctionForDecStructMap = true
114)
115
116type genStructMapStyle uint8
117
118const (
119	genStructMapStyleConsolidated genStructMapStyle = iota
120	genStructMapStyleLenPrefix
121	genStructMapStyleCheckBreak
122)
123
124var (
125	genAllTypesSamePkgErr  = errors.New("All types must be in the same package")
126	genExpectArrayOrMapErr = errors.New("unexpected type. Expecting array/map/slice")
127	genBase64enc           = base64.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__")
128	genQNameRegex          = regexp.MustCompile(`[A-Za-z_.]+`)
129	genCheckVendor         bool
130)
131
132// genRunner holds some state used during a Gen run.
133type genRunner struct {
134	w io.Writer      // output
135	c uint64         // counter used for generating varsfx
136	t []reflect.Type // list of types to run selfer on
137
138	tc reflect.Type     // currently running selfer on this type
139	te map[uintptr]bool // types for which the encoder has been created
140	td map[uintptr]bool // types for which the decoder has been created
141	cp string           // codec import path
142
143	im  map[string]reflect.Type // imports to add
144	imn map[string]string       // package names of imports to add
145	imc uint64                  // counter for import numbers
146
147	is map[reflect.Type]struct{} // types seen during import search
148	bp string                    // base PkgPath, for which we are generating for
149
150	cpfx   string // codec package prefix
151	unsafe bool   // is unsafe to be used in generated code?
152
153	tm map[reflect.Type]struct{} // types for which enc/dec must be generated
154	ts []reflect.Type            // types for which enc/dec must be generated
155
156	xs string // top level variable/constant suffix
157	hn string // fn helper type name
158
159	ti *TypeInfos
160	// rr *rand.Rand // random generator for file-specific types
161}
162
163// Gen will write a complete go file containing Selfer implementations for each
164// type passed. All the types must be in the same package.
165//
166// Library users: *DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINOUSLY WITHOUT NOTICE.*
167func Gen(w io.Writer, buildTags, pkgName, uid string, useUnsafe bool, ti *TypeInfos, typ ...reflect.Type) {
168	// All types passed to this method do not have a codec.Selfer method implemented directly.
169	// codecgen already checks the AST and skips any types that define the codec.Selfer methods.
170	// Consequently, there's no need to check and trim them if they implement codec.Selfer
171
172	if len(typ) == 0 {
173		return
174	}
175	x := genRunner{
176		unsafe: useUnsafe,
177		w:      w,
178		t:      typ,
179		te:     make(map[uintptr]bool),
180		td:     make(map[uintptr]bool),
181		im:     make(map[string]reflect.Type),
182		imn:    make(map[string]string),
183		is:     make(map[reflect.Type]struct{}),
184		tm:     make(map[reflect.Type]struct{}),
185		ts:     []reflect.Type{},
186		bp:     genImportPath(typ[0]),
187		xs:     uid,
188		ti:     ti,
189	}
190	if x.ti == nil {
191		x.ti = defTypeInfos
192	}
193	if x.xs == "" {
194		rr := rand.New(rand.NewSource(time.Now().UnixNano()))
195		x.xs = strconv.FormatInt(rr.Int63n(9999), 10)
196	}
197
198	// gather imports first:
199	x.cp = genImportPath(reflect.TypeOf(x))
200	x.imn[x.cp] = genCodecPkg
201	for _, t := range typ {
202		// fmt.Printf("###########: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name())
203		if genImportPath(t) != x.bp {
204			panic(genAllTypesSamePkgErr)
205		}
206		x.genRefPkgs(t)
207	}
208	if buildTags != "" {
209		x.line("// +build " + buildTags)
210		x.line("")
211	}
212	x.line(`
213
214// ************************************************************
215// DO NOT EDIT.
216// THIS FILE IS AUTO-GENERATED BY codecgen.
217// ************************************************************
218
219`)
220	x.line("package " + pkgName)
221	x.line("")
222	x.line("import (")
223	if x.cp != x.bp {
224		x.cpfx = genCodecPkg + "."
225		x.linef("%s \"%s\"", genCodecPkg, x.cp)
226	}
227	// use a sorted set of im keys, so that we can get consistent output
228	imKeys := make([]string, 0, len(x.im))
229	for k, _ := range x.im {
230		imKeys = append(imKeys, k)
231	}
232	sort.Strings(imKeys)
233	for _, k := range imKeys { // for k, _ := range x.im {
234		x.linef("%s \"%s\"", x.imn[k], k)
235	}
236	// add required packages
237	for _, k := range [...]string{"reflect", "unsafe", "runtime", "fmt", "errors"} {
238		if _, ok := x.im[k]; !ok {
239			if k == "unsafe" && !x.unsafe {
240				continue
241			}
242			x.line("\"" + k + "\"")
243		}
244	}
245	x.line(")")
246	x.line("")
247
248	x.line("const (")
249	x.linef("// ----- content types ----")
250	x.linef("codecSelferC_UTF8%s = %v", x.xs, int64(c_UTF8))
251	x.linef("codecSelferC_RAW%s = %v", x.xs, int64(c_RAW))
252	x.linef("// ----- value types used ----")
253	x.linef("codecSelferValueTypeArray%s = %v", x.xs, int64(valueTypeArray))
254	x.linef("codecSelferValueTypeMap%s = %v", x.xs, int64(valueTypeMap))
255	x.linef("// ----- containerStateValues ----")
256	x.linef("codecSelfer_containerMapKey%s = %v", x.xs, int64(containerMapKey))
257	x.linef("codecSelfer_containerMapValue%s = %v", x.xs, int64(containerMapValue))
258	x.linef("codecSelfer_containerMapEnd%s = %v", x.xs, int64(containerMapEnd))
259	x.linef("codecSelfer_containerArrayElem%s = %v", x.xs, int64(containerArrayElem))
260	x.linef("codecSelfer_containerArrayEnd%s = %v", x.xs, int64(containerArrayEnd))
261	x.line(")")
262	x.line("var (")
263	x.line("codecSelferBitsize" + x.xs + " = uint8(reflect.TypeOf(uint(0)).Bits())")
264	x.line("codecSelferOnlyMapOrArrayEncodeToStructErr" + x.xs + " = errors.New(`only encoded map or array can be decoded into a struct`)")
265	x.line(")")
266	x.line("")
267
268	if x.unsafe {
269		x.line("type codecSelferUnsafeString" + x.xs + " struct { Data uintptr; Len int}")
270		x.line("")
271	}
272	x.hn = "codecSelfer" + x.xs
273	x.line("type " + x.hn + " struct{}")
274	x.line("")
275
276	x.varsfxreset()
277	x.line("func init() {")
278	x.linef("if %sGenVersion != %v {", x.cpfx, GenVersion)
279	x.line("_, file, _, _ := runtime.Caller(0)")
280	x.line(`err := fmt.Errorf("codecgen version mismatch: current: %v, need %v. Re-generate file: %v", `)
281	x.linef(`%v, %sGenVersion, file)`, GenVersion, x.cpfx)
282	x.line("panic(err)")
283	x.linef("}")
284	x.line("if false { // reference the types, but skip this branch at build/run time")
285	var n int
286	// for k, t := range x.im {
287	for _, k := range imKeys {
288		t := x.im[k]
289		x.linef("var v%v %s.%s", n, x.imn[k], t.Name())
290		n++
291	}
292	if x.unsafe {
293		x.linef("var v%v unsafe.Pointer", n)
294		n++
295	}
296	if n > 0 {
297		x.out("_")
298		for i := 1; i < n; i++ {
299			x.out(", _")
300		}
301		x.out(" = v0")
302		for i := 1; i < n; i++ {
303			x.outf(", v%v", i)
304		}
305	}
306	x.line("} ") // close if false
307	x.line("}")  // close init
308	x.line("")
309
310	// generate rest of type info
311	for _, t := range typ {
312		x.tc = t
313		x.selfer(true)
314		x.selfer(false)
315	}
316
317	for _, t := range x.ts {
318		rtid := reflect.ValueOf(t).Pointer()
319		// generate enc functions for all these slice/map types.
320		x.varsfxreset()
321		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)
322		x.genRequiredMethodVars(true)
323		switch t.Kind() {
324		case reflect.Array, reflect.Slice, reflect.Chan:
325			x.encListFallback("v", t)
326		case reflect.Map:
327			x.encMapFallback("v", t)
328		default:
329			panic(genExpectArrayOrMapErr)
330		}
331		x.line("}")
332		x.line("")
333
334		// generate dec functions for all these slice/map types.
335		x.varsfxreset()
336		x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx)
337		x.genRequiredMethodVars(false)
338		switch t.Kind() {
339		case reflect.Array, reflect.Slice, reflect.Chan:
340			x.decListFallback("v", rtid, t)
341		case reflect.Map:
342			x.decMapFallback("v", rtid, t)
343		default:
344			panic(genExpectArrayOrMapErr)
345		}
346		x.line("}")
347		x.line("")
348	}
349
350	x.line("")
351}
352
353func (x *genRunner) checkForSelfer(t reflect.Type, varname string) bool {
354	// return varname != genTopLevelVarName && t != x.tc
355	// the only time we checkForSelfer is if we are not at the TOP of the generated code.
356	return varname != genTopLevelVarName
357}
358
359func (x *genRunner) arr2str(t reflect.Type, s string) string {
360	if t.Kind() == reflect.Array {
361		return s
362	}
363	return ""
364}
365
366func (x *genRunner) genRequiredMethodVars(encode bool) {
367	x.line("var h " + x.hn)
368	if encode {
369		x.line("z, r := " + x.cpfx + "GenHelperEncoder(e)")
370	} else {
371		x.line("z, r := " + x.cpfx + "GenHelperDecoder(d)")
372	}
373	x.line("_, _, _ = h, z, r")
374}
375
376func (x *genRunner) genRefPkgs(t reflect.Type) {
377	if _, ok := x.is[t]; ok {
378		return
379	}
380	// fmt.Printf(">>>>>>: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name())
381	x.is[t] = struct{}{}
382	tpkg, tname := genImportPath(t), t.Name()
383	if tpkg != "" && tpkg != x.bp && tpkg != x.cp && tname != "" && tname[0] >= 'A' && tname[0] <= 'Z' {
384		if _, ok := x.im[tpkg]; !ok {
385			x.im[tpkg] = t
386			if idx := strings.LastIndex(tpkg, "/"); idx < 0 {
387				x.imn[tpkg] = tpkg
388			} else {
389				x.imc++
390				x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + genGoIdentifier(tpkg[idx+1:], false)
391			}
392		}
393	}
394	switch t.Kind() {
395	case reflect.Array, reflect.Slice, reflect.Ptr, reflect.Chan:
396		x.genRefPkgs(t.Elem())
397	case reflect.Map:
398		x.genRefPkgs(t.Elem())
399		x.genRefPkgs(t.Key())
400	case reflect.Struct:
401		for i := 0; i < t.NumField(); i++ {
402			if fname := t.Field(i).Name; fname != "" && fname[0] >= 'A' && fname[0] <= 'Z' {
403				x.genRefPkgs(t.Field(i).Type)
404			}
405		}
406	}
407}
408
409func (x *genRunner) line(s string) {
410	x.out(s)
411	if len(s) == 0 || s[len(s)-1] != '\n' {
412		x.out("\n")
413	}
414}
415
416func (x *genRunner) varsfx() string {
417	x.c++
418	return strconv.FormatUint(x.c, 10)
419}
420
421func (x *genRunner) varsfxreset() {
422	x.c = 0
423}
424
425func (x *genRunner) out(s string) {
426	if _, err := io.WriteString(x.w, s); err != nil {
427		panic(err)
428	}
429}
430
431func (x *genRunner) linef(s string, params ...interface{}) {
432	x.line(fmt.Sprintf(s, params...))
433}
434
435func (x *genRunner) outf(s string, params ...interface{}) {
436	x.out(fmt.Sprintf(s, params...))
437}
438
439func (x *genRunner) genTypeName(t reflect.Type) (n string) {
440	// defer func() { fmt.Printf(">>>> ####: genTypeName: t: %v, name: '%s'\n", t, n) }()
441
442	// if the type has a PkgPath, which doesn't match the current package,
443	// then include it.
444	// We cannot depend on t.String() because it includes current package,
445	// or t.PkgPath because it includes full import path,
446	//
447	var ptrPfx string
448	for t.Kind() == reflect.Ptr {
449		ptrPfx += "*"
450		t = t.Elem()
451	}
452	if tn := t.Name(); tn != "" {
453		return ptrPfx + x.genTypeNamePrim(t)
454	}
455	switch t.Kind() {
456	case reflect.Map:
457		return ptrPfx + "map[" + x.genTypeName(t.Key()) + "]" + x.genTypeName(t.Elem())
458	case reflect.Slice:
459		return ptrPfx + "[]" + x.genTypeName(t.Elem())
460	case reflect.Array:
461		return ptrPfx + "[" + strconv.FormatInt(int64(t.Len()), 10) + "]" + x.genTypeName(t.Elem())
462	case reflect.Chan:
463		return ptrPfx + t.ChanDir().String() + " " + x.genTypeName(t.Elem())
464	default:
465		if t == intfTyp {
466			return ptrPfx + "interface{}"
467		} else {
468			return ptrPfx + x.genTypeNamePrim(t)
469		}
470	}
471}
472
473func (x *genRunner) genTypeNamePrim(t reflect.Type) (n string) {
474	if t.Name() == "" {
475		return t.String()
476	} else if genImportPath(t) == "" || genImportPath(t) == genImportPath(x.tc) {
477		return t.Name()
478	} else {
479		return x.imn[genImportPath(t)] + "." + t.Name()
480		// return t.String() // best way to get the package name inclusive
481	}
482}
483
484func (x *genRunner) genZeroValueR(t reflect.Type) string {
485	// if t is a named type, w
486	switch t.Kind() {
487	case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func,
488		reflect.Slice, reflect.Map, reflect.Invalid:
489		return "nil"
490	case reflect.Bool:
491		return "false"
492	case reflect.String:
493		return `""`
494	case reflect.Struct, reflect.Array:
495		return x.genTypeName(t) + "{}"
496	default: // all numbers
497		return "0"
498	}
499}
500
501func (x *genRunner) genMethodNameT(t reflect.Type) (s string) {
502	return genMethodNameT(t, x.tc)
503}
504
505func (x *genRunner) selfer(encode bool) {
506	t := x.tc
507	t0 := t
508	// always make decode use a pointer receiver,
509	// and structs always use a ptr receiver (encode|decode)
510	isptr := !encode || t.Kind() == reflect.Struct
511	x.varsfxreset()
512	fnSigPfx := "func (x "
513	if isptr {
514		fnSigPfx += "*"
515	}
516	fnSigPfx += x.genTypeName(t)
517
518	x.out(fnSigPfx)
519	if isptr {
520		t = reflect.PtrTo(t)
521	}
522	if encode {
523		x.line(") CodecEncodeSelf(e *" + x.cpfx + "Encoder) {")
524		x.genRequiredMethodVars(true)
525		// x.enc(genTopLevelVarName, t)
526		x.encVar(genTopLevelVarName, t)
527	} else {
528		x.line(") CodecDecodeSelf(d *" + x.cpfx + "Decoder) {")
529		x.genRequiredMethodVars(false)
530		// do not use decVar, as there is no need to check TryDecodeAsNil
531		// or way to elegantly handle that, and also setting it to a
532		// non-nil value doesn't affect the pointer passed.
533		// x.decVar(genTopLevelVarName, t, false)
534		x.dec(genTopLevelVarName, t0)
535	}
536	x.line("}")
537	x.line("")
538
539	if encode || t0.Kind() != reflect.Struct {
540		return
541	}
542
543	// write is containerMap
544	if genUseOneFunctionForDecStructMap {
545		x.out(fnSigPfx)
546		x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {")
547		x.genRequiredMethodVars(false)
548		x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleConsolidated)
549		x.line("}")
550		x.line("")
551	} else {
552		x.out(fnSigPfx)
553		x.line(") codecDecodeSelfFromMapLenPrefix(l int, d *" + x.cpfx + "Decoder) {")
554		x.genRequiredMethodVars(false)
555		x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleLenPrefix)
556		x.line("}")
557		x.line("")
558
559		x.out(fnSigPfx)
560		x.line(") codecDecodeSelfFromMapCheckBreak(l int, d *" + x.cpfx + "Decoder) {")
561		x.genRequiredMethodVars(false)
562		x.decStructMap(genTopLevelVarName, "l", reflect.ValueOf(t0).Pointer(), t0, genStructMapStyleCheckBreak)
563		x.line("}")
564		x.line("")
565	}
566
567	// write containerArray
568	x.out(fnSigPfx)
569	x.line(") codecDecodeSelfFromArray(l int, d *" + x.cpfx + "Decoder) {")
570	x.genRequiredMethodVars(false)
571	x.decStructArray(genTopLevelVarName, "l", "return", reflect.ValueOf(t0).Pointer(), t0)
572	x.line("}")
573	x.line("")
574
575}
576
577// used for chan, array, slice, map
578func (x *genRunner) xtraSM(varname string, encode bool, t reflect.Type) {
579	if encode {
580		x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), varname)
581	} else {
582		x.linef("h.dec%s((*%s)(%s), d)", x.genMethodNameT(t), x.genTypeName(t), varname)
583	}
584	x.registerXtraT(t)
585}
586
587func (x *genRunner) registerXtraT(t reflect.Type) {
588	// recursively register the types
589	if _, ok := x.tm[t]; ok {
590		return
591	}
592	var tkey reflect.Type
593	switch t.Kind() {
594	case reflect.Chan, reflect.Slice, reflect.Array:
595	case reflect.Map:
596		tkey = t.Key()
597	default:
598		return
599	}
600	x.tm[t] = struct{}{}
601	x.ts = append(x.ts, t)
602	// check if this refers to any xtra types eg. a slice of array: add the array
603	x.registerXtraT(t.Elem())
604	if tkey != nil {
605		x.registerXtraT(tkey)
606	}
607}
608
609// encVar will encode a variable.
610// The parameter, t, is the reflect.Type of the variable itself
611func (x *genRunner) encVar(varname string, t reflect.Type) {
612	// fmt.Printf(">>>>>> varname: %s, t: %v\n", varname, t)
613	var checkNil bool
614	switch t.Kind() {
615	case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan:
616		checkNil = true
617	}
618	if checkNil {
619		x.linef("if %s == nil { r.EncodeNil() } else { ", varname)
620	}
621	switch t.Kind() {
622	case reflect.Ptr:
623		switch t.Elem().Kind() {
624		case reflect.Struct, reflect.Array:
625			x.enc(varname, genNonPtr(t))
626		default:
627			i := x.varsfx()
628			x.line(genTempVarPfx + i + " := *" + varname)
629			x.enc(genTempVarPfx+i, genNonPtr(t))
630		}
631	case reflect.Struct, reflect.Array:
632		i := x.varsfx()
633		x.line(genTempVarPfx + i + " := &" + varname)
634		x.enc(genTempVarPfx+i, t)
635	default:
636		x.enc(varname, t)
637	}
638
639	if checkNil {
640		x.line("}")
641	}
642
643}
644
645// enc will encode a variable (varname) of type t,
646// except t is of kind reflect.Struct or reflect.Array, wherein varname is of type ptrTo(T) (to prevent copying)
647func (x *genRunner) enc(varname string, t reflect.Type) {
648	rtid := reflect.ValueOf(t).Pointer()
649	// We call CodecEncodeSelf if one of the following are honored:
650	//   - the type already implements Selfer, call that
651	//   - the type has a Selfer implementation just created, use that
652	//   - the type is in the list of the ones we will generate for, but it is not currently being generated
653
654	mi := x.varsfx()
655	tptr := reflect.PtrTo(t)
656	tk := t.Kind()
657	if x.checkForSelfer(t, varname) {
658		if tk == reflect.Array || tk == reflect.Struct { // varname is of type *T
659			if tptr.Implements(selferTyp) || t.Implements(selferTyp) {
660				x.line(varname + ".CodecEncodeSelf(e)")
661				return
662			}
663		} else { // varname is of type T
664			if t.Implements(selferTyp) {
665				x.line(varname + ".CodecEncodeSelf(e)")
666				return
667			} else if tptr.Implements(selferTyp) {
668				x.linef("%ssf%s := &%s", genTempVarPfx, mi, varname)
669				x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi)
670				return
671			}
672		}
673
674		if _, ok := x.te[rtid]; ok {
675			x.line(varname + ".CodecEncodeSelf(e)")
676			return
677		}
678	}
679
680	inlist := false
681	for _, t0 := range x.t {
682		if t == t0 {
683			inlist = true
684			if x.checkForSelfer(t, varname) {
685				x.line(varname + ".CodecEncodeSelf(e)")
686				return
687			}
688			break
689		}
690	}
691
692	var rtidAdded bool
693	if t == x.tc {
694		x.te[rtid] = true
695		rtidAdded = true
696	}
697
698	// check if
699	//   - type is RawExt, Raw
700	//   - the type implements (Text|JSON|Binary)(Unm|M)arshal
701	x.linef("%sm%s := z.EncBinary()", genTempVarPfx, mi)
702	x.linef("_ = %sm%s", genTempVarPfx, mi)
703	x.line("if false {")           //start if block
704	defer func() { x.line("}") }() //end if block
705
706	if t == rawTyp {
707		x.linef("} else { z.EncRaw(%v)", varname)
708		return
709	}
710	if t == rawExtTyp {
711		x.linef("} else { r.EncodeRawExt(%v, e)", varname)
712		return
713	}
714	// HACK: Support for Builtins.
715	//       Currently, only Binc supports builtins, and the only builtin type is time.Time.
716	//       Have a method that returns the rtid for time.Time if Handle is Binc.
717	if t == timeTyp {
718		vrtid := genTempVarPfx + "m" + x.varsfx()
719		x.linef("} else if %s := z.TimeRtidIfBinc(); %s != 0 { ", vrtid, vrtid)
720		x.linef("r.EncodeBuiltin(%s, %s)", vrtid, varname)
721	}
722	// only check for extensions if the type is named, and has a packagePath.
723	if genImportPath(t) != "" && t.Name() != "" {
724		// first check if extensions are configued, before doing the interface conversion
725		x.linef("} else if z.HasExtensions() && z.EncExt(%s) {", varname)
726	}
727	if tk == reflect.Array || tk == reflect.Struct { // varname is of type *T
728		if t.Implements(binaryMarshalerTyp) || tptr.Implements(binaryMarshalerTyp) {
729			x.linef("} else if %sm%s { z.EncBinaryMarshal(%v) ", genTempVarPfx, mi, varname)
730		}
731		if t.Implements(jsonMarshalerTyp) || tptr.Implements(jsonMarshalerTyp) {
732			x.linef("} else if !%sm%s && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", genTempVarPfx, mi, varname)
733		} else if t.Implements(textMarshalerTyp) || tptr.Implements(textMarshalerTyp) {
734			x.linef("} else if !%sm%s { z.EncTextMarshal(%v) ", genTempVarPfx, mi, varname)
735		}
736	} else { // varname is of type T
737		if t.Implements(binaryMarshalerTyp) {
738			x.linef("} else if %sm%s { z.EncBinaryMarshal(%v) ", genTempVarPfx, mi, varname)
739		} else if tptr.Implements(binaryMarshalerTyp) {
740			x.linef("} else if %sm%s { z.EncBinaryMarshal(&%v) ", genTempVarPfx, mi, varname)
741		}
742		if t.Implements(jsonMarshalerTyp) {
743			x.linef("} else if !%sm%s && z.IsJSONHandle() { z.EncJSONMarshal(%v) ", genTempVarPfx, mi, varname)
744		} else if tptr.Implements(jsonMarshalerTyp) {
745			x.linef("} else if !%sm%s && z.IsJSONHandle() { z.EncJSONMarshal(&%v) ", genTempVarPfx, mi, varname)
746		} else if t.Implements(textMarshalerTyp) {
747			x.linef("} else if !%sm%s { z.EncTextMarshal(%v) ", genTempVarPfx, mi, varname)
748		} else if tptr.Implements(textMarshalerTyp) {
749			x.linef("} else if !%sm%s { z.EncTextMarshal(&%v) ", genTempVarPfx, mi, varname)
750		}
751	}
752	x.line("} else {")
753
754	switch t.Kind() {
755	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
756		x.line("r.EncodeInt(int64(" + varname + "))")
757	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
758		x.line("r.EncodeUint(uint64(" + varname + "))")
759	case reflect.Float32:
760		x.line("r.EncodeFloat32(float32(" + varname + "))")
761	case reflect.Float64:
762		x.line("r.EncodeFloat64(float64(" + varname + "))")
763	case reflect.Bool:
764		x.line("r.EncodeBool(bool(" + varname + "))")
765	case reflect.String:
766		x.line("r.EncodeString(codecSelferC_UTF8" + x.xs + ", string(" + varname + "))")
767	case reflect.Chan:
768		x.xtraSM(varname, true, t)
769		// x.encListFallback(varname, rtid, t)
770	case reflect.Array:
771		x.xtraSM(varname, true, t)
772	case reflect.Slice:
773		// if nil, call dedicated function
774		// if a []uint8, call dedicated function
775		// if a known fastpath slice, call dedicated function
776		// else write encode function in-line.
777		// - if elements are primitives or Selfers, call dedicated function on each member.
778		// - else call Encoder.encode(XXX) on it.
779		if rtid == uint8SliceTypId {
780			x.line("r.EncodeStringBytes(codecSelferC_RAW" + x.xs + ", []byte(" + varname + "))")
781		} else if fastpathAV.index(rtid) != -1 {
782			g := x.newGenV(t)
783			x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", false, e)")
784		} else {
785			x.xtraSM(varname, true, t)
786			// x.encListFallback(varname, rtid, t)
787		}
788	case reflect.Map:
789		// if nil, call dedicated function
790		// if a known fastpath map, call dedicated function
791		// else write encode function in-line.
792		// - if elements are primitives or Selfers, call dedicated function on each member.
793		// - else call Encoder.encode(XXX) on it.
794		// x.line("if " + varname + " == nil { \nr.EncodeNil()\n } else { ")
795		if fastpathAV.index(rtid) != -1 {
796			g := x.newGenV(t)
797			x.line("z.F." + g.MethodNamePfx("Enc", false) + "V(" + varname + ", false, e)")
798		} else {
799			x.xtraSM(varname, true, t)
800			// x.encMapFallback(varname, rtid, t)
801		}
802	case reflect.Struct:
803		if !inlist {
804			delete(x.te, rtid)
805			x.line("z.EncFallback(" + varname + ")")
806			break
807		}
808		x.encStruct(varname, rtid, t)
809	default:
810		if rtidAdded {
811			delete(x.te, rtid)
812		}
813		x.line("z.EncFallback(" + varname + ")")
814	}
815}
816
817func (x *genRunner) encZero(t reflect.Type) {
818	switch t.Kind() {
819	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
820		x.line("r.EncodeInt(0)")
821	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
822		x.line("r.EncodeUint(0)")
823	case reflect.Float32:
824		x.line("r.EncodeFloat32(0)")
825	case reflect.Float64:
826		x.line("r.EncodeFloat64(0)")
827	case reflect.Bool:
828		x.line("r.EncodeBool(false)")
829	case reflect.String:
830		x.line("r.EncodeString(codecSelferC_UTF8" + x.xs + `, "")`)
831	default:
832		x.line("r.EncodeNil()")
833	}
834}
835
836func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
837	// Use knowledge from structfieldinfo (mbs, encodable fields. Ignore omitempty. )
838	// replicate code in kStruct i.e. for each field, deref type to non-pointer, and call x.enc on it
839
840	// if t === type currently running selfer on, do for all
841	ti := x.ti.get(rtid, t)
842	i := x.varsfx()
843	sepVarname := genTempVarPfx + "sep" + i
844	numfieldsvar := genTempVarPfx + "q" + i
845	ti2arrayvar := genTempVarPfx + "r" + i
846	struct2arrvar := genTempVarPfx + "2arr" + i
847
848	x.line(sepVarname + " := !z.EncBinary()")
849	x.linef("%s := z.EncBasicHandle().StructToArray", struct2arrvar)
850	tisfi := ti.sfip // always use sequence from file. decStruct expects same thing.
851	// due to omitEmpty, we need to calculate the
852	// number of non-empty things we write out first.
853	// This is required as we need to pre-determine the size of the container,
854	// to support length-prefixing.
855	x.linef("var %s [%v]bool", numfieldsvar, len(tisfi))
856	x.linef("_, _, _ = %s, %s, %s", sepVarname, numfieldsvar, struct2arrvar)
857	x.linef("const %s bool = %v", ti2arrayvar, ti.toArray)
858	nn := 0
859	for j, si := range tisfi {
860		if !si.omitEmpty {
861			nn++
862			continue
863		}
864		var t2 reflect.StructField
865		var omitline string
866		if si.i != -1 {
867			t2 = t.Field(int(si.i))
868		} else {
869			t2typ := t
870			varname3 := varname
871			for _, ix := range si.is {
872				for t2typ.Kind() == reflect.Ptr {
873					t2typ = t2typ.Elem()
874				}
875				t2 = t2typ.Field(ix)
876				t2typ = t2.Type
877				varname3 = varname3 + "." + t2.Name
878				if t2typ.Kind() == reflect.Ptr {
879					omitline += varname3 + " != nil && "
880				}
881			}
882		}
883		// never check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc.
884		// also, for maps/slices/arrays, check if len ! 0 (not if == zero value)
885		switch t2.Type.Kind() {
886		case reflect.Struct:
887			omitline += " true"
888		case reflect.Map, reflect.Slice, reflect.Array, reflect.Chan:
889			omitline += "len(" + varname + "." + t2.Name + ") != 0"
890		default:
891			omitline += varname + "." + t2.Name + " != " + x.genZeroValueR(t2.Type)
892		}
893		x.linef("%s[%v] = %s", numfieldsvar, j, omitline)
894	}
895	x.linef("var %snn%s int", genTempVarPfx, i)
896	x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
897	x.line("r.EncodeArrayStart(" + strconv.FormatInt(int64(len(tisfi)), 10) + ")")
898	x.linef("} else {") // if not ti.toArray
899	x.linef("%snn%s = %v", genTempVarPfx, i, nn)
900	x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i)
901	x.linef("r.EncodeMapStart(%snn%s)", genTempVarPfx, i)
902	x.linef("%snn%s = %v", genTempVarPfx, i, 0)
903	// x.line("r.EncodeMapStart(" + strconv.FormatInt(int64(len(tisfi)), 10) + ")")
904	x.line("}") // close if not StructToArray
905
906	for j, si := range tisfi {
907		i := x.varsfx()
908		isNilVarName := genTempVarPfx + "n" + i
909		var labelUsed bool
910		var t2 reflect.StructField
911		if si.i != -1 {
912			t2 = t.Field(int(si.i))
913		} else {
914			t2typ := t
915			varname3 := varname
916			for _, ix := range si.is {
917				// fmt.Printf("%%%% %v, ix: %v\n", t2typ, ix)
918				for t2typ.Kind() == reflect.Ptr {
919					t2typ = t2typ.Elem()
920				}
921				t2 = t2typ.Field(ix)
922				t2typ = t2.Type
923				varname3 = varname3 + "." + t2.Name
924				if t2typ.Kind() == reflect.Ptr {
925					if !labelUsed {
926						x.line("var " + isNilVarName + " bool")
927					}
928					x.line("if " + varname3 + " == nil { " + isNilVarName + " = true ")
929					x.line("goto LABEL" + i)
930					x.line("}")
931					labelUsed = true
932					// "varname3 = new(" + x.genTypeName(t3.Elem()) + ") }")
933				}
934			}
935			// t2 = t.FieldByIndex(si.is)
936		}
937		if labelUsed {
938			x.line("LABEL" + i + ":")
939		}
940		// if the type of the field is a Selfer, or one of the ones
941
942		x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray
943		if labelUsed {
944			x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
945		}
946		x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
947		if si.omitEmpty {
948			x.linef("if %s[%v] {", numfieldsvar, j)
949		}
950		x.encVar(varname+"."+t2.Name, t2.Type)
951		if si.omitEmpty {
952			x.linef("} else {")
953			x.encZero(t2.Type)
954			x.linef("}")
955		}
956		if labelUsed {
957			x.line("}")
958		}
959
960		x.linef("} else {") // if not ti.toArray
961
962		if si.omitEmpty {
963			x.linef("if %s[%v] {", numfieldsvar, j)
964		}
965		x.linef("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
966		x.line("r.EncodeString(codecSelferC_UTF8" + x.xs + ", string(\"" + si.encName + "\"))")
967		x.linef("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
968		if labelUsed {
969			x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
970			x.encVar(varname+"."+t2.Name, t2.Type)
971			x.line("}")
972		} else {
973			x.encVar(varname+"."+t2.Name, t2.Type)
974		}
975		if si.omitEmpty {
976			x.line("}")
977		}
978		x.linef("} ") // end if/else ti.toArray
979	}
980	x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
981	x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
982	x.line("} else {")
983	x.linef("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
984	x.line("}")
985
986}
987
988func (x *genRunner) encListFallback(varname string, t reflect.Type) {
989	if t.AssignableTo(uint8SliceTyp) {
990		x.linef("r.EncodeStringBytes(codecSelferC_RAW%s, []byte(%s))", x.xs, varname)
991		return
992	}
993	if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
994		x.linef("r.EncodeStringBytes(codecSelferC_RAW%s, ([%v]byte(%s))[:])", x.xs, t.Len(), varname)
995		return
996	}
997	i := x.varsfx()
998	g := genTempVarPfx
999	x.line("r.EncodeArrayStart(len(" + varname + "))")
1000	if t.Kind() == reflect.Chan {
1001		x.linef("for %si%s, %si2%s := 0, len(%s); %si%s < %si2%s; %si%s++ {", g, i, g, i, varname, g, i, g, i, g, i)
1002		x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
1003		x.linef("%sv%s := <-%s", g, i, varname)
1004	} else {
1005		// x.linef("for %si%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
1006		x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname)
1007		x.linef("z.EncSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
1008	}
1009	x.encVar(genTempVarPfx+"v"+i, t.Elem())
1010	x.line("}")
1011	x.linef("z.EncSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
1012}
1013
1014func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
1015	// TODO: expand this to handle canonical.
1016	i := x.varsfx()
1017	x.line("r.EncodeMapStart(len(" + varname + "))")
1018	x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
1019	// x.line("for " + genTempVarPfx + "k" + i + ", " + genTempVarPfx + "v" + i + " := range " + varname + " {")
1020	x.linef("z.EncSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
1021	x.encVar(genTempVarPfx+"k"+i, t.Key())
1022	x.linef("z.EncSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
1023	x.encVar(genTempVarPfx+"v"+i, t.Elem())
1024	x.line("}")
1025	x.linef("z.EncSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
1026}
1027
1028func (x *genRunner) decVar(varname string, t reflect.Type, canBeNil bool) {
1029	// We only encode as nil if a nillable value.
1030	// This removes some of the wasted checks for TryDecodeAsNil.
1031	// We need to think about this more, to see what happens if omitempty, etc
1032	// cause a nil value to be stored when something is expected.
1033	// This could happen when decoding from a struct encoded as an array.
1034	// For that, decVar should be called with canNil=true, to force true as its value.
1035	i := x.varsfx()
1036	if !canBeNil {
1037		canBeNil = genAnythingCanBeNil || !genIsImmutable(t)
1038	}
1039	if canBeNil {
1040		x.line("if r.TryDecodeAsNil() {")
1041		if t.Kind() == reflect.Ptr {
1042			x.line("if " + varname + " != nil { ")
1043
1044			// if varname is a field of a struct (has a dot in it),
1045			// then just set it to nil
1046			if strings.IndexByte(varname, '.') != -1 {
1047				x.line(varname + " = nil")
1048			} else {
1049				x.line("*" + varname + " = " + x.genZeroValueR(t.Elem()))
1050			}
1051			x.line("}")
1052		} else {
1053			x.line(varname + " = " + x.genZeroValueR(t))
1054		}
1055		x.line("} else {")
1056	} else {
1057		x.line("// cannot be nil")
1058	}
1059	if t.Kind() != reflect.Ptr {
1060		if x.decTryAssignPrimitive(varname, t) {
1061			x.line(genTempVarPfx + "v" + i + " := &" + varname)
1062			x.dec(genTempVarPfx+"v"+i, t)
1063		}
1064	} else {
1065		x.linef("if %s == nil { %s = new(%s) }", varname, varname, x.genTypeName(t.Elem()))
1066		// Ensure we set underlying ptr to a non-nil value (so we can deref to it later).
1067		// There's a chance of a **T in here which is nil.
1068		var ptrPfx string
1069		for t = t.Elem(); t.Kind() == reflect.Ptr; t = t.Elem() {
1070			ptrPfx += "*"
1071			x.linef("if %s%s == nil { %s%s = new(%s)}",
1072				ptrPfx, varname, ptrPfx, varname, x.genTypeName(t))
1073		}
1074		// if varname has [ in it, then create temp variable for this ptr thingie
1075		if strings.Index(varname, "[") >= 0 {
1076			varname2 := genTempVarPfx + "w" + i
1077			x.line(varname2 + " := " + varname)
1078			varname = varname2
1079		}
1080
1081		if ptrPfx == "" {
1082			x.dec(varname, t)
1083		} else {
1084			x.line(genTempVarPfx + "z" + i + " := " + ptrPfx + varname)
1085			x.dec(genTempVarPfx+"z"+i, t)
1086		}
1087
1088	}
1089
1090	if canBeNil {
1091		x.line("} ")
1092	}
1093}
1094
1095// dec will decode a variable (varname) of type ptrTo(t).
1096// t is always a basetype (i.e. not of kind reflect.Ptr).
1097func (x *genRunner) dec(varname string, t reflect.Type) {
1098	// assumptions:
1099	//   - the varname is to a pointer already. No need to take address of it
1100	//   - t is always a baseType T (not a *T, etc).
1101	rtid := reflect.ValueOf(t).Pointer()
1102	tptr := reflect.PtrTo(t)
1103	if x.checkForSelfer(t, varname) {
1104		if t.Implements(selferTyp) || tptr.Implements(selferTyp) {
1105			x.line(varname + ".CodecDecodeSelf(d)")
1106			return
1107		}
1108		if _, ok := x.td[rtid]; ok {
1109			x.line(varname + ".CodecDecodeSelf(d)")
1110			return
1111		}
1112	}
1113
1114	inlist := false
1115	for _, t0 := range x.t {
1116		if t == t0 {
1117			inlist = true
1118			if x.checkForSelfer(t, varname) {
1119				x.line(varname + ".CodecDecodeSelf(d)")
1120				return
1121			}
1122			break
1123		}
1124	}
1125
1126	var rtidAdded bool
1127	if t == x.tc {
1128		x.td[rtid] = true
1129		rtidAdded = true
1130	}
1131
1132	// check if
1133	//   - type is Raw, RawExt
1134	//   - the type implements (Text|JSON|Binary)(Unm|M)arshal
1135	mi := x.varsfx()
1136	x.linef("%sm%s := z.DecBinary()", genTempVarPfx, mi)
1137	x.linef("_ = %sm%s", genTempVarPfx, mi)
1138	x.line("if false {")           //start if block
1139	defer func() { x.line("}") }() //end if block
1140
1141	if t == rawTyp {
1142		x.linef("} else { *%v = z.DecRaw()", varname)
1143		return
1144	}
1145	if t == rawExtTyp {
1146		x.linef("} else { r.DecodeExt(%v, 0, nil)", varname)
1147		return
1148	}
1149
1150	// HACK: Support for Builtins.
1151	//       Currently, only Binc supports builtins, and the only builtin type is time.Time.
1152	//       Have a method that returns the rtid for time.Time if Handle is Binc.
1153	if t == timeTyp {
1154		vrtid := genTempVarPfx + "m" + x.varsfx()
1155		x.linef("} else if %s := z.TimeRtidIfBinc(); %s != 0 { ", vrtid, vrtid)
1156		x.linef("r.DecodeBuiltin(%s, %s)", vrtid, varname)
1157	}
1158	// only check for extensions if the type is named, and has a packagePath.
1159	if genImportPath(t) != "" && t.Name() != "" {
1160		// first check if extensions are configued, before doing the interface conversion
1161		x.linef("} else if z.HasExtensions() && z.DecExt(%s) {", varname)
1162	}
1163
1164	if t.Implements(binaryUnmarshalerTyp) || tptr.Implements(binaryUnmarshalerTyp) {
1165		x.linef("} else if %sm%s { z.DecBinaryUnmarshal(%v) ", genTempVarPfx, mi, varname)
1166	}
1167	if t.Implements(jsonUnmarshalerTyp) || tptr.Implements(jsonUnmarshalerTyp) {
1168		x.linef("} else if !%sm%s && z.IsJSONHandle() { z.DecJSONUnmarshal(%v)", genTempVarPfx, mi, varname)
1169	} else if t.Implements(textUnmarshalerTyp) || tptr.Implements(textUnmarshalerTyp) {
1170		x.linef("} else if !%sm%s { z.DecTextUnmarshal(%v)", genTempVarPfx, mi, varname)
1171	}
1172
1173	x.line("} else {")
1174
1175	// Since these are pointers, we cannot share, and have to use them one by one
1176	switch t.Kind() {
1177	case reflect.Int:
1178		x.line("*((*int)(" + varname + ")) = int(r.DecodeInt(codecSelferBitsize" + x.xs + "))")
1179		// x.line("z.DecInt((*int)(" + varname + "))")
1180	case reflect.Int8:
1181		x.line("*((*int8)(" + varname + ")) = int8(r.DecodeInt(8))")
1182		// x.line("z.DecInt8((*int8)(" + varname + "))")
1183	case reflect.Int16:
1184		x.line("*((*int16)(" + varname + ")) = int16(r.DecodeInt(16))")
1185		// x.line("z.DecInt16((*int16)(" + varname + "))")
1186	case reflect.Int32:
1187		x.line("*((*int32)(" + varname + ")) = int32(r.DecodeInt(32))")
1188		// x.line("z.DecInt32((*int32)(" + varname + "))")
1189	case reflect.Int64:
1190		x.line("*((*int64)(" + varname + ")) = int64(r.DecodeInt(64))")
1191		// x.line("z.DecInt64((*int64)(" + varname + "))")
1192
1193	case reflect.Uint:
1194		x.line("*((*uint)(" + varname + ")) = uint(r.DecodeUint(codecSelferBitsize" + x.xs + "))")
1195		// x.line("z.DecUint((*uint)(" + varname + "))")
1196	case reflect.Uint8:
1197		x.line("*((*uint8)(" + varname + ")) = uint8(r.DecodeUint(8))")
1198		// x.line("z.DecUint8((*uint8)(" + varname + "))")
1199	case reflect.Uint16:
1200		x.line("*((*uint16)(" + varname + ")) = uint16(r.DecodeUint(16))")
1201		//x.line("z.DecUint16((*uint16)(" + varname + "))")
1202	case reflect.Uint32:
1203		x.line("*((*uint32)(" + varname + ")) = uint32(r.DecodeUint(32))")
1204		//x.line("z.DecUint32((*uint32)(" + varname + "))")
1205	case reflect.Uint64:
1206		x.line("*((*uint64)(" + varname + ")) = uint64(r.DecodeUint(64))")
1207		//x.line("z.DecUint64((*uint64)(" + varname + "))")
1208	case reflect.Uintptr:
1209		x.line("*((*uintptr)(" + varname + ")) = uintptr(r.DecodeUint(codecSelferBitsize" + x.xs + "))")
1210
1211	case reflect.Float32:
1212		x.line("*((*float32)(" + varname + ")) = float32(r.DecodeFloat(true))")
1213		//x.line("z.DecFloat32((*float32)(" + varname + "))")
1214	case reflect.Float64:
1215		x.line("*((*float64)(" + varname + ")) = float64(r.DecodeFloat(false))")
1216		// x.line("z.DecFloat64((*float64)(" + varname + "))")
1217
1218	case reflect.Bool:
1219		x.line("*((*bool)(" + varname + ")) = r.DecodeBool()")
1220		// x.line("z.DecBool((*bool)(" + varname + "))")
1221	case reflect.String:
1222		x.line("*((*string)(" + varname + ")) = r.DecodeString()")
1223		// x.line("z.DecString((*string)(" + varname + "))")
1224	case reflect.Array, reflect.Chan:
1225		x.xtraSM(varname, false, t)
1226		// x.decListFallback(varname, rtid, true, t)
1227	case reflect.Slice:
1228		// if a []uint8, call dedicated function
1229		// if a known fastpath slice, call dedicated function
1230		// else write encode function in-line.
1231		// - if elements are primitives or Selfers, call dedicated function on each member.
1232		// - else call Encoder.encode(XXX) on it.
1233		if rtid == uint8SliceTypId {
1234			x.line("*" + varname + " = r.DecodeBytes(*(*[]byte)(" + varname + "), false, false)")
1235		} else if fastpathAV.index(rtid) != -1 {
1236			g := x.newGenV(t)
1237			x.line("z.F." + g.MethodNamePfx("Dec", false) + "X(" + varname + ", false, d)")
1238		} else {
1239			x.xtraSM(varname, false, t)
1240			// x.decListFallback(varname, rtid, false, t)
1241		}
1242	case reflect.Map:
1243		// if a known fastpath map, call dedicated function
1244		// else write encode function in-line.
1245		// - if elements are primitives or Selfers, call dedicated function on each member.
1246		// - else call Encoder.encode(XXX) on it.
1247		if fastpathAV.index(rtid) != -1 {
1248			g := x.newGenV(t)
1249			x.line("z.F." + g.MethodNamePfx("Dec", false) + "X(" + varname + ", false, d)")
1250		} else {
1251			x.xtraSM(varname, false, t)
1252			// x.decMapFallback(varname, rtid, t)
1253		}
1254	case reflect.Struct:
1255		if inlist {
1256			x.decStruct(varname, rtid, t)
1257		} else {
1258			// delete(x.td, rtid)
1259			x.line("z.DecFallback(" + varname + ", false)")
1260		}
1261	default:
1262		if rtidAdded {
1263			delete(x.te, rtid)
1264		}
1265		x.line("z.DecFallback(" + varname + ", true)")
1266	}
1267}
1268
1269func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type) (tryAsPtr bool) {
1270	// This should only be used for exact primitives (ie un-named types).
1271	// Named types may be implementations of Selfer, Unmarshaler, etc.
1272	// They should be handled by dec(...)
1273
1274	if t.Name() != "" {
1275		tryAsPtr = true
1276		return
1277	}
1278
1279	switch t.Kind() {
1280	case reflect.Int:
1281		x.linef("%s = r.DecodeInt(codecSelferBitsize%s)", varname, x.xs)
1282	case reflect.Int8:
1283		x.linef("%s = r.DecodeInt(8)", varname)
1284	case reflect.Int16:
1285		x.linef("%s = r.DecodeInt(16)", varname)
1286	case reflect.Int32:
1287		x.linef("%s = r.DecodeInt(32)", varname)
1288	case reflect.Int64:
1289		x.linef("%s = r.DecodeInt(64)", varname)
1290
1291	case reflect.Uint:
1292		x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
1293	case reflect.Uint8:
1294		x.linef("%s = r.DecodeUint(8)", varname)
1295	case reflect.Uint16:
1296		x.linef("%s = r.DecodeUint(16)", varname)
1297	case reflect.Uint32:
1298		x.linef("%s = r.DecodeUint(32)", varname)
1299	case reflect.Uint64:
1300		x.linef("%s = r.DecodeUint(64)", varname)
1301	case reflect.Uintptr:
1302		x.linef("%s = r.DecodeUint(codecSelferBitsize%s)", varname, x.xs)
1303
1304	case reflect.Float32:
1305		x.linef("%s = r.DecodeFloat(true)", varname)
1306	case reflect.Float64:
1307		x.linef("%s = r.DecodeFloat(false)", varname)
1308
1309	case reflect.Bool:
1310		x.linef("%s = r.DecodeBool()", varname)
1311	case reflect.String:
1312		x.linef("%s = r.DecodeString()", varname)
1313	default:
1314		tryAsPtr = true
1315	}
1316	return
1317}
1318
1319func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) {
1320	if t.AssignableTo(uint8SliceTyp) {
1321		x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false, false)")
1322		return
1323	}
1324	if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
1325		x.linef("r.DecodeBytes( ((*[%s]byte)(%s))[:], false, true)", t.Len(), varname)
1326		return
1327	}
1328	type tstruc struct {
1329		TempVar   string
1330		Rand      string
1331		Varname   string
1332		CTyp      string
1333		Typ       string
1334		Immutable bool
1335		Size      int
1336	}
1337	telem := t.Elem()
1338	ts := tstruc{genTempVarPfx, x.varsfx(), varname, x.genTypeName(t), x.genTypeName(telem), genIsImmutable(telem), int(telem.Size())}
1339
1340	funcs := make(template.FuncMap)
1341
1342	funcs["decLineVar"] = func(varname string) string {
1343		x.decVar(varname, telem, false)
1344		return ""
1345	}
1346	funcs["decLine"] = func(pfx string) string {
1347		x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(telem), false)
1348		return ""
1349	}
1350	funcs["var"] = func(s string) string {
1351		return ts.TempVar + s + ts.Rand
1352	}
1353	funcs["zero"] = func() string {
1354		return x.genZeroValueR(telem)
1355	}
1356	funcs["isArray"] = func() bool {
1357		return t.Kind() == reflect.Array
1358	}
1359	funcs["isSlice"] = func() bool {
1360		return t.Kind() == reflect.Slice
1361	}
1362	funcs["isChan"] = func() bool {
1363		return t.Kind() == reflect.Chan
1364	}
1365	tm, err := template.New("").Funcs(funcs).Parse(genDecListTmpl)
1366	if err != nil {
1367		panic(err)
1368	}
1369	if err = tm.Execute(x.w, &ts); err != nil {
1370		panic(err)
1371	}
1372}
1373
1374func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) {
1375	type tstruc struct {
1376		TempVar string
1377		Sfx     string
1378		Rand    string
1379		Varname string
1380		KTyp    string
1381		Typ     string
1382		Size    int
1383	}
1384	telem := t.Elem()
1385	tkey := t.Key()
1386	ts := tstruc{
1387		genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey),
1388		x.genTypeName(telem), int(telem.Size() + tkey.Size()),
1389	}
1390
1391	funcs := make(template.FuncMap)
1392	funcs["decElemZero"] = func() string {
1393		return x.genZeroValueR(telem)
1394	}
1395	funcs["decElemKindImmutable"] = func() bool {
1396		return genIsImmutable(telem)
1397	}
1398	funcs["decElemKindPtr"] = func() bool {
1399		return telem.Kind() == reflect.Ptr
1400	}
1401	funcs["decElemKindIntf"] = func() bool {
1402		return telem.Kind() == reflect.Interface
1403	}
1404	funcs["decLineVarK"] = func(varname string) string {
1405		x.decVar(varname, tkey, false)
1406		return ""
1407	}
1408	funcs["decLineVar"] = func(varname string) string {
1409		x.decVar(varname, telem, false)
1410		return ""
1411	}
1412	funcs["decLineK"] = func(pfx string) string {
1413		x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(tkey), false)
1414		return ""
1415	}
1416	funcs["decLine"] = func(pfx string) string {
1417		x.decVar(ts.TempVar+pfx+ts.Rand, reflect.PtrTo(telem), false)
1418		return ""
1419	}
1420	funcs["var"] = func(s string) string {
1421		return ts.TempVar + s + ts.Rand
1422	}
1423
1424	tm, err := template.New("").Funcs(funcs).Parse(genDecMapTmpl)
1425	if err != nil {
1426		panic(err)
1427	}
1428	if err = tm.Execute(x.w, &ts); err != nil {
1429		panic(err)
1430	}
1431}
1432
1433func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintptr, t reflect.Type) {
1434	ti := x.ti.get(rtid, t)
1435	tisfi := ti.sfip // always use sequence from file. decStruct expects same thing.
1436	x.line("switch (" + kName + ") {")
1437	for _, si := range tisfi {
1438		x.line("case \"" + si.encName + "\":")
1439		var t2 reflect.StructField
1440		if si.i != -1 {
1441			t2 = t.Field(int(si.i))
1442		} else {
1443			//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
1444			// t2 = t.FieldByIndex(si.is)
1445			t2typ := t
1446			varname3 := varname
1447			for _, ix := range si.is {
1448				for t2typ.Kind() == reflect.Ptr {
1449					t2typ = t2typ.Elem()
1450				}
1451				t2 = t2typ.Field(ix)
1452				t2typ = t2.Type
1453				varname3 = varname3 + "." + t2.Name
1454				if t2typ.Kind() == reflect.Ptr {
1455					x.linef("if %s == nil { %s = new(%s) }", varname3, varname3, x.genTypeName(t2typ.Elem()))
1456				}
1457			}
1458		}
1459		x.decVar(varname+"."+t2.Name, t2.Type, false)
1460	}
1461	x.line("default:")
1462	// pass the slice here, so that the string will not escape, and maybe save allocation
1463	x.line("z.DecStructFieldNotFound(-1, " + kName + ")")
1464	x.line("} // end switch " + kName)
1465}
1466
1467func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) {
1468	tpfx := genTempVarPfx
1469	i := x.varsfx()
1470	kName := tpfx + "s" + i
1471
1472	// We thought to use ReadStringAsBytes, as go compiler might optimize the copy out.
1473	// However, using that was more expensive, as it seems that the switch expression
1474	// is evaluated each time.
1475	//
1476	// We could depend on decodeString using a temporary/shared buffer internally.
1477	// However, this model of creating a byte array, and using explicitly is faster,
1478	// and allows optional use of unsafe []byte->string conversion without alloc.
1479
1480	// Also, ensure that the slice array doesn't escape.
1481	// That will help escape analysis prevent allocation when it gets better.
1482
1483	// x.line("var " + kName + "Arr = [32]byte{} // default string to decode into")
1484	// x.line("var " + kName + "Slc = " + kName + "Arr[:] // default slice to decode into")
1485	// use the scratch buffer to avoid allocation (most field names are < 32).
1486
1487	x.line("var " + kName + "Slc = z.DecScratchBuffer() // default slice to decode into")
1488
1489	x.line("_ = " + kName + "Slc")
1490	switch style {
1491	case genStructMapStyleLenPrefix:
1492		x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i)
1493	case genStructMapStyleCheckBreak:
1494		x.linef("for %sj%s := 0; !r.CheckBreak(); %sj%s++ {", tpfx, i, tpfx, i)
1495	default: // 0, otherwise.
1496		x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
1497		x.linef("for %sj%s := 0; ; %sj%s++ {", tpfx, i, tpfx, i)
1498		x.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname)
1499		x.line("} else { if r.CheckBreak() { break }; }")
1500	}
1501	x.linef("z.DecSendContainerState(codecSelfer_containerMapKey%s)", x.xs)
1502	x.line(kName + "Slc = r.DecodeBytes(" + kName + "Slc, true, true)")
1503	// let string be scoped to this loop alone, so it doesn't escape.
1504	if x.unsafe {
1505		x.line(kName + "SlcHdr := codecSelferUnsafeString" + x.xs + "{uintptr(unsafe.Pointer(&" +
1506			kName + "Slc[0])), len(" + kName + "Slc)}")
1507		x.line(kName + " := *(*string)(unsafe.Pointer(&" + kName + "SlcHdr))")
1508	} else {
1509		x.line(kName + " := string(" + kName + "Slc)")
1510	}
1511	x.linef("z.DecSendContainerState(codecSelfer_containerMapValue%s)", x.xs)
1512	x.decStructMapSwitch(kName, varname, rtid, t)
1513
1514	x.line("} // end for " + tpfx + "j" + i)
1515	x.linef("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
1516}
1517
1518func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) {
1519	tpfx := genTempVarPfx
1520	i := x.varsfx()
1521	ti := x.ti.get(rtid, t)
1522	tisfi := ti.sfip // always use sequence from file. decStruct expects same thing.
1523	x.linef("var %sj%s int", tpfx, i)
1524	x.linef("var %sb%s bool", tpfx, i)                        // break
1525	x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
1526	for _, si := range tisfi {
1527		var t2 reflect.StructField
1528		if si.i != -1 {
1529			t2 = t.Field(int(si.i))
1530		} else {
1531			//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
1532			// t2 = t.FieldByIndex(si.is)
1533			t2typ := t
1534			varname3 := varname
1535			for _, ix := range si.is {
1536				for t2typ.Kind() == reflect.Ptr {
1537					t2typ = t2typ.Elem()
1538				}
1539				t2 = t2typ.Field(ix)
1540				t2typ = t2.Type
1541				varname3 = varname3 + "." + t2.Name
1542				if t2typ.Kind() == reflect.Ptr {
1543					x.linef("if %s == nil { %s = new(%s) }", varname3, varname3, x.genTypeName(t2typ.Elem()))
1544				}
1545			}
1546		}
1547
1548		x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }",
1549			tpfx, i, tpfx, i, tpfx, i,
1550			tpfx, i, lenvarname, tpfx, i)
1551		x.linef("if %sb%s { z.DecSendContainerState(codecSelfer_containerArrayEnd%s); %s }",
1552			tpfx, i, x.xs, breakString)
1553		x.linef("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
1554		x.decVar(varname+"."+t2.Name, t2.Type, true)
1555	}
1556	// read remaining values and throw away.
1557	x.line("for {")
1558	x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }",
1559		tpfx, i, tpfx, i, tpfx, i,
1560		tpfx, i, lenvarname, tpfx, i)
1561	x.linef("if %sb%s { break }", tpfx, i)
1562	x.linef("z.DecSendContainerState(codecSelfer_containerArrayElem%s)", x.xs)
1563	x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i)
1564	x.line("}")
1565	x.linef("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
1566}
1567
1568func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
1569	// if container is map
1570	i := x.varsfx()
1571	x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i)
1572	x.linef("if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs)
1573	x.line(genTempVarPfx + "l" + i + " := r.ReadMapStart()")
1574	x.linef("if %sl%s == 0 {", genTempVarPfx, i)
1575	x.linef("z.DecSendContainerState(codecSelfer_containerMapEnd%s)", x.xs)
1576	if genUseOneFunctionForDecStructMap {
1577		x.line("} else { ")
1578		x.linef("x.codecDecodeSelfFromMap(%sl%s, d)", genTempVarPfx, i)
1579	} else {
1580		x.line("} else if " + genTempVarPfx + "l" + i + " > 0 { ")
1581		x.line("x.codecDecodeSelfFromMapLenPrefix(" + genTempVarPfx + "l" + i + ", d)")
1582		x.line("} else {")
1583		x.line("x.codecDecodeSelfFromMapCheckBreak(" + genTempVarPfx + "l" + i + ", d)")
1584	}
1585	x.line("}")
1586
1587	// else if container is array
1588	x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs)
1589	x.line(genTempVarPfx + "l" + i + " := r.ReadArrayStart()")
1590	x.linef("if %sl%s == 0 {", genTempVarPfx, i)
1591	x.linef("z.DecSendContainerState(codecSelfer_containerArrayEnd%s)", x.xs)
1592	x.line("} else { ")
1593	x.linef("x.codecDecodeSelfFromArray(%sl%s, d)", genTempVarPfx, i)
1594	x.line("}")
1595	// else panic
1596	x.line("} else { ")
1597	x.line("panic(codecSelferOnlyMapOrArrayEncodeToStructErr" + x.xs + ")")
1598	x.line("} ")
1599}
1600
1601// --------
1602
1603type genV struct {
1604	// genV is either a primitive (Primitive != "") or a map (MapKey != "") or a slice
1605	MapKey    string
1606	Elem      string
1607	Primitive string
1608	Size      int
1609}
1610
1611func (x *genRunner) newGenV(t reflect.Type) (v genV) {
1612	switch t.Kind() {
1613	case reflect.Slice, reflect.Array:
1614		te := t.Elem()
1615		v.Elem = x.genTypeName(te)
1616		v.Size = int(te.Size())
1617	case reflect.Map:
1618		te, tk := t.Elem(), t.Key()
1619		v.Elem = x.genTypeName(te)
1620		v.MapKey = x.genTypeName(tk)
1621		v.Size = int(te.Size() + tk.Size())
1622	default:
1623		panic("unexpected type for newGenV. Requires map or slice type")
1624	}
1625	return
1626}
1627
1628func (x *genV) MethodNamePfx(prefix string, prim bool) string {
1629	var name []byte
1630	if prefix != "" {
1631		name = append(name, prefix...)
1632	}
1633	if prim {
1634		name = append(name, genTitleCaseName(x.Primitive)...)
1635	} else {
1636		if x.MapKey == "" {
1637			name = append(name, "Slice"...)
1638		} else {
1639			name = append(name, "Map"...)
1640			name = append(name, genTitleCaseName(x.MapKey)...)
1641		}
1642		name = append(name, genTitleCaseName(x.Elem)...)
1643	}
1644	return string(name)
1645
1646}
1647
1648// genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise.
1649//
1650// This handles the misbehaviour that occurs when 1.5-style vendoring is enabled,
1651// where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped.
1652// We strip it here.
1653func genImportPath(t reflect.Type) (s string) {
1654	s = t.PkgPath()
1655	if genCheckVendor {
1656		// HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
1657		// if s contains /vendor/ OR startsWith vendor/, then return everything after it.
1658		const vendorStart = "vendor/"
1659		const vendorInline = "/vendor/"
1660		if i := strings.LastIndex(s, vendorInline); i >= 0 {
1661			s = s[i+len(vendorInline):]
1662		} else if strings.HasPrefix(s, vendorStart) {
1663			s = s[len(vendorStart):]
1664		}
1665	}
1666	return
1667}
1668
1669// A go identifier is (letter|_)[letter|number|_]*
1670func genGoIdentifier(s string, checkFirstChar bool) string {
1671	b := make([]byte, 0, len(s))
1672	t := make([]byte, 4)
1673	var n int
1674	for i, r := range s {
1675		if checkFirstChar && i == 0 && !unicode.IsLetter(r) {
1676			b = append(b, '_')
1677		}
1678		// r must be unicode_letter, unicode_digit or _
1679		if unicode.IsLetter(r) || unicode.IsDigit(r) {
1680			n = utf8.EncodeRune(t, r)
1681			b = append(b, t[:n]...)
1682		} else {
1683			b = append(b, '_')
1684		}
1685	}
1686	return string(b)
1687}
1688
1689func genNonPtr(t reflect.Type) reflect.Type {
1690	for t.Kind() == reflect.Ptr {
1691		t = t.Elem()
1692	}
1693	return t
1694}
1695
1696func genTitleCaseName(s string) string {
1697	switch s {
1698	case "interface{}", "interface {}":
1699		return "Intf"
1700	default:
1701		return strings.ToUpper(s[0:1]) + s[1:]
1702	}
1703}
1704
1705func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) {
1706	var ptrPfx string
1707	for t.Kind() == reflect.Ptr {
1708		ptrPfx += "Ptrto"
1709		t = t.Elem()
1710	}
1711	tstr := t.String()
1712	if tn := t.Name(); tn != "" {
1713		if tRef != nil && genImportPath(t) == genImportPath(tRef) {
1714			return ptrPfx + tn
1715		} else {
1716			if genQNameRegex.MatchString(tstr) {
1717				return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
1718			} else {
1719				return ptrPfx + genCustomTypeName(tstr)
1720			}
1721		}
1722	}
1723	switch t.Kind() {
1724	case reflect.Map:
1725		return ptrPfx + "Map" + genMethodNameT(t.Key(), tRef) + genMethodNameT(t.Elem(), tRef)
1726	case reflect.Slice:
1727		return ptrPfx + "Slice" + genMethodNameT(t.Elem(), tRef)
1728	case reflect.Array:
1729		return ptrPfx + "Array" + strconv.FormatInt(int64(t.Len()), 10) + genMethodNameT(t.Elem(), tRef)
1730	case reflect.Chan:
1731		var cx string
1732		switch t.ChanDir() {
1733		case reflect.SendDir:
1734			cx = "ChanSend"
1735		case reflect.RecvDir:
1736			cx = "ChanRecv"
1737		default:
1738			cx = "Chan"
1739		}
1740		return ptrPfx + cx + genMethodNameT(t.Elem(), tRef)
1741	default:
1742		if t == intfTyp {
1743			return ptrPfx + "Interface"
1744		} else {
1745			if tRef != nil && genImportPath(t) == genImportPath(tRef) {
1746				if t.Name() != "" {
1747					return ptrPfx + t.Name()
1748				} else {
1749					return ptrPfx + genCustomTypeName(tstr)
1750				}
1751			} else {
1752				// best way to get the package name inclusive
1753				// return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
1754				// return ptrPfx + genBase64enc.EncodeToString([]byte(tstr))
1755				if t.Name() != "" && genQNameRegex.MatchString(tstr) {
1756					return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
1757				} else {
1758					return ptrPfx + genCustomTypeName(tstr)
1759				}
1760			}
1761		}
1762	}
1763}
1764
1765// genCustomNameForType base64encodes the t.String() value in such a way
1766// that it can be used within a function name.
1767func genCustomTypeName(tstr string) string {
1768	len2 := genBase64enc.EncodedLen(len(tstr))
1769	bufx := make([]byte, len2)
1770	genBase64enc.Encode(bufx, []byte(tstr))
1771	for i := len2 - 1; i >= 0; i-- {
1772		if bufx[i] == '=' {
1773			len2--
1774		} else {
1775			break
1776		}
1777	}
1778	return string(bufx[:len2])
1779}
1780
1781func genIsImmutable(t reflect.Type) (v bool) {
1782	return isImmutableKind(t.Kind())
1783}
1784
1785type genInternal struct {
1786	Values []genV
1787	Unsafe bool
1788}
1789
1790func (x genInternal) FastpathLen() (l int) {
1791	for _, v := range x.Values {
1792		if v.Primitive == "" {
1793			l++
1794		}
1795	}
1796	return
1797}
1798
1799func genInternalZeroValue(s string) string {
1800	switch s {
1801	case "interface{}", "interface {}":
1802		return "nil"
1803	case "bool":
1804		return "false"
1805	case "string":
1806		return `""`
1807	default:
1808		return "0"
1809	}
1810}
1811
1812func genInternalEncCommandAsString(s string, vname string) string {
1813	switch s {
1814	case "uint", "uint8", "uint16", "uint32", "uint64":
1815		return "ee.EncodeUint(uint64(" + vname + "))"
1816	case "int", "int8", "int16", "int32", "int64":
1817		return "ee.EncodeInt(int64(" + vname + "))"
1818	case "string":
1819		return "ee.EncodeString(c_UTF8, " + vname + ")"
1820	case "float32":
1821		return "ee.EncodeFloat32(" + vname + ")"
1822	case "float64":
1823		return "ee.EncodeFloat64(" + vname + ")"
1824	case "bool":
1825		return "ee.EncodeBool(" + vname + ")"
1826	case "symbol":
1827		return "ee.EncodeSymbol(" + vname + ")"
1828	default:
1829		return "e.encode(" + vname + ")"
1830	}
1831}
1832
1833func genInternalDecCommandAsString(s string) string {
1834	switch s {
1835	case "uint":
1836		return "uint(dd.DecodeUint(uintBitsize))"
1837	case "uint8":
1838		return "uint8(dd.DecodeUint(8))"
1839	case "uint16":
1840		return "uint16(dd.DecodeUint(16))"
1841	case "uint32":
1842		return "uint32(dd.DecodeUint(32))"
1843	case "uint64":
1844		return "dd.DecodeUint(64)"
1845	case "uintptr":
1846		return "uintptr(dd.DecodeUint(uintBitsize))"
1847	case "int":
1848		return "int(dd.DecodeInt(intBitsize))"
1849	case "int8":
1850		return "int8(dd.DecodeInt(8))"
1851	case "int16":
1852		return "int16(dd.DecodeInt(16))"
1853	case "int32":
1854		return "int32(dd.DecodeInt(32))"
1855	case "int64":
1856		return "dd.DecodeInt(64)"
1857
1858	case "string":
1859		return "dd.DecodeString()"
1860	case "float32":
1861		return "float32(dd.DecodeFloat(true))"
1862	case "float64":
1863		return "dd.DecodeFloat(false)"
1864	case "bool":
1865		return "dd.DecodeBool()"
1866	default:
1867		panic(errors.New("gen internal: unknown type for decode: " + s))
1868	}
1869}
1870
1871func genInternalSortType(s string, elem bool) string {
1872	for _, v := range [...]string{"int", "uint", "float", "bool", "string"} {
1873		if strings.HasPrefix(s, v) {
1874			if elem {
1875				if v == "int" || v == "uint" || v == "float" {
1876					return v + "64"
1877				} else {
1878					return v
1879				}
1880			}
1881			return v + "Slice"
1882		}
1883	}
1884	panic("sorttype: unexpected type: " + s)
1885}
1886
1887// var genInternalMu sync.Mutex
1888var genInternalV genInternal
1889var genInternalTmplFuncs template.FuncMap
1890var genInternalOnce sync.Once
1891
1892func genInternalInit() {
1893	types := [...]string{
1894		"interface{}",
1895		"string",
1896		"float32",
1897		"float64",
1898		"uint",
1899		"uint8",
1900		"uint16",
1901		"uint32",
1902		"uint64",
1903		"uintptr",
1904		"int",
1905		"int8",
1906		"int16",
1907		"int32",
1908		"int64",
1909		"bool",
1910	}
1911	// keep as slice, so it is in specific iteration order.
1912	// Initial order was uint64, string, interface{}, int, int64
1913	mapvaltypes := [...]string{
1914		"interface{}",
1915		"string",
1916		"uint",
1917		"uint8",
1918		"uint16",
1919		"uint32",
1920		"uint64",
1921		"uintptr",
1922		"int",
1923		"int8",
1924		"int16",
1925		"int32",
1926		"int64",
1927		"float32",
1928		"float64",
1929		"bool",
1930	}
1931	wordSizeBytes := int(intBitsize) / 8
1932
1933	mapvaltypes2 := map[string]int{
1934		"interface{}": 2 * wordSizeBytes,
1935		"string":      2 * wordSizeBytes,
1936		"uint":        1 * wordSizeBytes,
1937		"uint8":       1,
1938		"uint16":      2,
1939		"uint32":      4,
1940		"uint64":      8,
1941		"uintptr":     1 * wordSizeBytes,
1942		"int":         1 * wordSizeBytes,
1943		"int8":        1,
1944		"int16":       2,
1945		"int32":       4,
1946		"int64":       8,
1947		"float32":     4,
1948		"float64":     8,
1949		"bool":        1,
1950	}
1951	var gt genInternal
1952
1953	// For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function
1954	for _, s := range types {
1955		gt.Values = append(gt.Values, genV{Primitive: s, Size: mapvaltypes2[s]})
1956		if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already.
1957			gt.Values = append(gt.Values, genV{Elem: s, Size: mapvaltypes2[s]})
1958		}
1959		if _, ok := mapvaltypes2[s]; !ok {
1960			gt.Values = append(gt.Values, genV{MapKey: s, Elem: s, Size: 2 * mapvaltypes2[s]})
1961		}
1962		for _, ms := range mapvaltypes {
1963			gt.Values = append(gt.Values, genV{MapKey: s, Elem: ms, Size: mapvaltypes2[s] + mapvaltypes2[ms]})
1964		}
1965	}
1966
1967	funcs := make(template.FuncMap)
1968	// funcs["haspfx"] = strings.HasPrefix
1969	funcs["encmd"] = genInternalEncCommandAsString
1970	funcs["decmd"] = genInternalDecCommandAsString
1971	funcs["zerocmd"] = genInternalZeroValue
1972	funcs["hasprefix"] = strings.HasPrefix
1973	funcs["sorttype"] = genInternalSortType
1974
1975	genInternalV = gt
1976	genInternalTmplFuncs = funcs
1977}
1978
1979// genInternalGoFile is used to generate source files from templates.
1980// It is run by the program author alone.
1981// Unfortunately, it has to be exported so that it can be called from a command line tool.
1982// *** DO NOT USE ***
1983func genInternalGoFile(r io.Reader, w io.Writer, safe bool) (err error) {
1984	genInternalOnce.Do(genInternalInit)
1985
1986	gt := genInternalV
1987	gt.Unsafe = !safe
1988
1989	t := template.New("").Funcs(genInternalTmplFuncs)
1990
1991	tmplstr, err := ioutil.ReadAll(r)
1992	if err != nil {
1993		return
1994	}
1995
1996	if t, err = t.Parse(string(tmplstr)); err != nil {
1997		return
1998	}
1999
2000	var out bytes.Buffer
2001	err = t.Execute(&out, gt)
2002	if err != nil {
2003		return
2004	}
2005
2006	bout, err := format.Source(out.Bytes())
2007	if err != nil {
2008		w.Write(out.Bytes()) // write out if error, so we can still see.
2009		// w.Write(bout) // write out if error, as much as possible, so we can still see.
2010		return
2011	}
2012	w.Write(bout)
2013	return
2014}
2015