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