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