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.linef("if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw(z.BytesView(string(%s))) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, string(%s)) }", varname, x.xs, 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.linef(`if z.EncBasicHandle().StringToRaw { r.EncodeStringBytesRaw([]byte{}) } else { r.EncodeStringEnc(codecSelferCcUTF8%s, "") }`, 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		// emulate EncStructFieldKey
1055		switch ti.keyType {
1056		case valueTypeInt:
1057			x.linef("r.EncodeInt(z.M.Int(strconv.ParseInt(`%s`, 10, 64)))", si.encName)
1058		case valueTypeUint:
1059			x.linef("r.EncodeUint(z.M.Uint(strconv.ParseUint(`%s`, 10, 64)))", si.encName)
1060		case valueTypeFloat:
1061			x.linef("r.EncodeFloat64(z.M.Float(strconv.ParseFloat(`%s`, 64)))", si.encName)
1062		default: // string
1063			if si.encNameAsciiAlphaNum {
1064				x.linef(`if z.IsJSONHandle() { z.WriteStr("\"%s\"") } else { `, si.encName)
1065			}
1066			x.linef("r.EncodeStringEnc(codecSelferCcUTF8%s, `%s`)", x.xs, si.encName)
1067			if si.encNameAsciiAlphaNum {
1068				x.linef("}")
1069			}
1070		}
1071		// x.linef("r.EncStructFieldKey(codecSelferValueType%s%s, `%s`)", ti.keyType.String(), x.xs, si.encName)
1072		x.line("r.WriteMapElemValue()")
1073		if labelUsed {
1074			x.line("if " + isNilVarName + " { r.EncodeNil() } else { ")
1075			x.encVar(varname+"."+t2.Name, t2.Type)
1076			x.line("}")
1077		} else {
1078			x.encVar(varname+"."+t2.Name, t2.Type)
1079		}
1080		if si.omitEmpty() {
1081			x.line("}")
1082		}
1083		x.linef("} ") // end if/else ti.toArray
1084	}
1085	x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray {
1086	x.line("r.WriteArrayEnd()")
1087	x.line("} else {")
1088	x.line("r.WriteMapEnd()")
1089	x.line("}")
1090
1091}
1092
1093func (x *genRunner) encListFallback(varname string, t reflect.Type) {
1094	elemBytes := t.Elem().Kind() == reflect.Uint8
1095	if t.AssignableTo(uint8SliceTyp) {
1096		x.linef("r.EncodeStringBytesRaw([]byte(%s))", varname)
1097		return
1098	}
1099	if t.Kind() == reflect.Array && elemBytes {
1100		x.linef("r.EncodeStringBytesRaw(((*[%d]byte)(%s))[:])", t.Len(), varname)
1101		return
1102	}
1103	i := x.varsfx()
1104	if t.Kind() == reflect.Chan {
1105		type ts struct {
1106			Label, Chan, Slice, Sfx string
1107		}
1108		tm, err := template.New("").Parse(genEncChanTmpl)
1109		if err != nil {
1110			panic(err)
1111		}
1112		x.linef("if %s == nil { r.EncodeNil() } else { ", varname)
1113		x.linef("var sch%s []%s", i, x.genTypeName(t.Elem()))
1114		err = tm.Execute(x.w, &ts{"Lsch" + i, varname, "sch" + i, i})
1115		if err != nil {
1116			panic(err)
1117		}
1118		// x.linef("%s = sch%s", varname, i)
1119		if elemBytes {
1120			x.linef("r.EncodeStringBytesRaw([]byte(%s))", "sch"+i)
1121			x.line("}")
1122			return
1123		}
1124		varname = "sch" + i
1125	}
1126
1127	x.line("r.WriteArrayStart(len(" + varname + "))")
1128	x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname)
1129	x.line("r.WriteArrayElem()")
1130
1131	x.encVar(genTempVarPfx+"v"+i, t.Elem())
1132	x.line("}")
1133	x.line("r.WriteArrayEnd()")
1134	if t.Kind() == reflect.Chan {
1135		x.line("}")
1136	}
1137}
1138
1139func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
1140	// TODO: expand this to handle canonical.
1141	i := x.varsfx()
1142	x.line("r.WriteMapStart(len(" + varname + "))")
1143	x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
1144	x.line("r.WriteMapElemKey()")
1145	x.encVar(genTempVarPfx+"k"+i, t.Key())
1146	x.line("r.WriteMapElemValue()")
1147	x.encVar(genTempVarPfx+"v"+i, t.Elem())
1148	x.line("}")
1149	x.line("r.WriteMapEnd()")
1150}
1151
1152func (x *genRunner) decVarInitPtr(varname, nilvar string, t reflect.Type, si *structFieldInfo,
1153	newbuf, nilbuf *genBuf) (t2 reflect.StructField) {
1154	//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
1155	// t2 = t.FieldByIndex(si.is)
1156	t2typ := t
1157	varname3 := varname
1158	t2kind := t2typ.Kind()
1159	var nilbufed bool
1160	if si != nil {
1161		for ij, ix := range si.is {
1162			if uint8(ij) == si.nis {
1163				break
1164			}
1165			for t2typ.Kind() == reflect.Ptr {
1166				t2typ = t2typ.Elem()
1167			}
1168			t2 = t2typ.Field(int(ix))
1169			t2typ = t2.Type
1170			varname3 = varname3 + "." + t2.Name
1171			t2kind = t2typ.Kind()
1172			if t2kind != reflect.Ptr {
1173				continue
1174			}
1175			if newbuf != nil {
1176				newbuf.f("if %s == nil { %s = new(%s) }\n", varname3, varname3, x.genTypeName(t2typ.Elem()))
1177			}
1178			if nilbuf != nil {
1179				if !nilbufed {
1180					nilbuf.s("if true")
1181					nilbufed = true
1182				}
1183				nilbuf.s(" && ").s(varname3).s(" != nil")
1184			}
1185		}
1186	}
1187	// if t2typ.Kind() == reflect.Ptr {
1188	// 	varname3 = varname3 + t2.Name
1189	// }
1190	if nilbuf != nil {
1191		if nilbufed {
1192			nilbuf.s(" { ")
1193		}
1194		if nilvar != "" {
1195			nilbuf.s(nilvar).s(" = true")
1196		} else if tk := t2typ.Kind(); tk == reflect.Ptr {
1197			if strings.IndexByte(varname3, '.') != -1 || strings.IndexByte(varname3, '[') != -1 {
1198				nilbuf.s(varname3).s(" = nil")
1199			} else {
1200				nilbuf.s("*").s(varname3).s(" = ").s(x.genZeroValueR(t2typ.Elem()))
1201			}
1202		} else {
1203			nilbuf.s(varname3).s(" = ").s(x.genZeroValueR(t2typ))
1204		}
1205		if nilbufed {
1206			nilbuf.s("}")
1207		}
1208	}
1209	return t2
1210}
1211
1212// decVar takes a variable called varname, of type t
1213func (x *genRunner) decVarMain(varname, rand string, t reflect.Type, checkNotNil bool) {
1214	// We only encode as nil if a nillable value.
1215	// This removes some of the wasted checks for TryDecodeAsNil.
1216	// We need to think about this more, to see what happens if omitempty, etc
1217	// cause a nil value to be stored when something is expected.
1218	// This could happen when decoding from a struct encoded as an array.
1219	// For that, decVar should be called with canNil=true, to force true as its value.
1220	var varname2 string
1221	if t.Kind() != reflect.Ptr {
1222		if t.PkgPath() != "" || !x.decTryAssignPrimitive(varname, t, false) {
1223			x.dec(varname, t, false)
1224		}
1225	} else {
1226		if checkNotNil {
1227			x.linef("if %s == nil { %s = new(%s) }", varname, varname, x.genTypeName(t.Elem()))
1228		}
1229		// Ensure we set underlying ptr to a non-nil value (so we can deref to it later).
1230		// There's a chance of a **T in here which is nil.
1231		var ptrPfx string
1232		for t = t.Elem(); t.Kind() == reflect.Ptr; t = t.Elem() {
1233			ptrPfx += "*"
1234			if checkNotNil {
1235				x.linef("if %s%s == nil { %s%s = new(%s)}",
1236					ptrPfx, varname, ptrPfx, varname, x.genTypeName(t))
1237			}
1238		}
1239		// Should we create temp var if a slice/map indexing? No. dec(...) can now handle it.
1240
1241		if ptrPfx == "" {
1242			x.dec(varname, t, true)
1243		} else {
1244			varname2 = genTempVarPfx + "z" + rand
1245			x.line(varname2 + " := " + ptrPfx + varname)
1246			x.dec(varname2, t, true)
1247		}
1248	}
1249}
1250
1251// decVar takes a variable called varname, of type t
1252func (x *genRunner) decVar(varname, nilvar string, t reflect.Type, canBeNil, checkNotNil bool) {
1253	i := x.varsfx()
1254
1255	// We only encode as nil if a nillable value.
1256	// This removes some of the wasted checks for TryDecodeAsNil.
1257	// We need to think about this more, to see what happens if omitempty, etc
1258	// cause a nil value to be stored when something is expected.
1259	// This could happen when decoding from a struct encoded as an array.
1260	// For that, decVar should be called with canNil=true, to force true as its value.
1261
1262	if !canBeNil {
1263		canBeNil = genAnythingCanBeNil || !genIsImmutable(t)
1264	}
1265
1266	if canBeNil {
1267		var buf genBuf
1268		x.decVarInitPtr(varname, nilvar, t, nil, nil, &buf)
1269		x.linef("if r.TryDecodeAsNil() { %s } else {", buf.buf)
1270	} else {
1271		x.line("// cannot be nil")
1272	}
1273
1274	x.decVarMain(varname, i, t, checkNotNil)
1275
1276	if canBeNil {
1277		x.line("} ")
1278	}
1279}
1280
1281// dec will decode a variable (varname) of type t or ptrTo(t) if isptr==true.
1282// t is always a basetype (i.e. not of kind reflect.Ptr).
1283func (x *genRunner) dec(varname string, t reflect.Type, isptr bool) {
1284	// assumptions:
1285	//   - the varname is to a pointer already. No need to take address of it
1286	//   - t is always a baseType T (not a *T, etc).
1287	rtid := rt2id(t)
1288	ti2 := x.ti.get(rtid, t)
1289	// tptr := reflect.PtrTo(t)
1290	if x.checkForSelfer(t, varname) {
1291		if ti2.cs || ti2.csp { // t.Implements(selferTyp) || tptr.Implements(selferTyp) {
1292			x.line(varname + ".CodecDecodeSelf(d)")
1293			return
1294		}
1295		if _, ok := x.td[rtid]; ok {
1296			x.line(varname + ".CodecDecodeSelf(d)")
1297			return
1298		}
1299	}
1300
1301	inlist := false
1302	for _, t0 := range x.t {
1303		if t == t0 {
1304			inlist = true
1305			if x.checkForSelfer(t, varname) {
1306				x.line(varname + ".CodecDecodeSelf(d)")
1307				return
1308			}
1309			break
1310		}
1311	}
1312
1313	var rtidAdded bool
1314	if t == x.tc {
1315		x.td[rtid] = true
1316		rtidAdded = true
1317	}
1318
1319	// check if
1320	//   - type is time.Time, Raw, RawExt
1321	//   - the type implements (Text|JSON|Binary)(Unm|M)arshal
1322
1323	mi := x.varsfx()
1324	// x.linef("%sm%s := z.DecBinary()", genTempVarPfx, mi)
1325	// x.linef("_ = %sm%s", genTempVarPfx, mi)
1326	x.line("if false {")           //start if block
1327	defer func() { x.line("}") }() //end if block
1328
1329	var ptrPfx, addrPfx string
1330	if isptr {
1331		ptrPfx = "*"
1332	} else {
1333		addrPfx = "&"
1334	}
1335	if t == timeTyp {
1336		x.linef("} else if !z.DecBasicHandle().TimeNotBuiltin { %s%v = r.DecodeTime()", ptrPfx, varname)
1337		// return
1338	}
1339	if t == rawTyp {
1340		x.linef("} else { %s%v = z.DecRaw()", ptrPfx, varname)
1341		return
1342	}
1343
1344	if t == rawExtTyp {
1345		x.linef("} else { r.DecodeExt(%s%v, 0, nil)", addrPfx, varname)
1346		return
1347	}
1348
1349	// only check for extensions if the type is named, and has a packagePath.
1350	if !x.nx && genImportPath(t) != "" && t.Name() != "" {
1351		// first check if extensions are configued, before doing the interface conversion
1352		// x.linef("} else if z.HasExtensions() && z.DecExt(%s) {", varname)
1353		yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi)
1354		x.linef("} else if %s := z.Extension(z.I2Rtid(%s)); %s != nil { z.DecExtension(%s, %s) ", yy, varname, yy, varname, yy)
1355	}
1356
1357	if ti2.bu || ti2.bup { // t.Implements(binaryUnmarshalerTyp) || tptr.Implements(binaryUnmarshalerTyp) {
1358		x.linef("} else if z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", addrPfx, varname)
1359	}
1360	if ti2.ju || ti2.jup { // t.Implements(jsonUnmarshalerTyp) || tptr.Implements(jsonUnmarshalerTyp) {
1361		x.linef("} else if !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", addrPfx, varname)
1362	} else if ti2.tu || ti2.tup { // t.Implements(textUnmarshalerTyp) || tptr.Implements(textUnmarshalerTyp) {
1363		x.linef("} else if !z.DecBinary() { z.DecTextUnmarshal(%s%v)", addrPfx, varname)
1364	}
1365
1366	x.line("} else {")
1367
1368	if x.decTryAssignPrimitive(varname, t, isptr) {
1369		return
1370	}
1371
1372	switch t.Kind() {
1373	case reflect.Array, reflect.Chan:
1374		x.xtraSM(varname, t, false, isptr)
1375	case reflect.Slice:
1376		// if a []uint8, call dedicated function
1377		// if a known fastpath slice, call dedicated function
1378		// else write encode function in-line.
1379		// - if elements are primitives or Selfers, call dedicated function on each member.
1380		// - else call Encoder.encode(XXX) on it.
1381		if rtid == uint8SliceTypId {
1382			x.linef("%s%s = r.DecodeBytes(%s(%s[]byte)(%s), false)",
1383				ptrPfx, varname, ptrPfx, ptrPfx, varname)
1384		} else if fastpathAV.index(rtid) != -1 {
1385			g := x.newGenV(t)
1386			x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
1387		} else {
1388			x.xtraSM(varname, t, false, isptr)
1389			// x.decListFallback(varname, rtid, false, t)
1390		}
1391	case reflect.Map:
1392		// if a known fastpath map, call dedicated function
1393		// else write encode function in-line.
1394		// - if elements are primitives or Selfers, call dedicated function on each member.
1395		// - else call Encoder.encode(XXX) on it.
1396		if fastpathAV.index(rtid) != -1 {
1397			g := x.newGenV(t)
1398			x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
1399		} else {
1400			x.xtraSM(varname, t, false, isptr)
1401			// x.decMapFallback(varname, rtid, t)
1402		}
1403	case reflect.Struct:
1404		if inlist {
1405			// no need to create temp variable if isptr, or x.F or x[F]
1406			if isptr || strings.IndexByte(varname, '.') != -1 || strings.IndexByte(varname, '[') != -1 {
1407				x.decStruct(varname, rtid, t)
1408			} else {
1409				varname2 := genTempVarPfx + "j" + mi
1410				x.line(varname2 + " := &" + varname)
1411				x.decStruct(varname2, rtid, t)
1412			}
1413		} else {
1414			// delete(x.td, rtid)
1415			x.line("z.DecFallback(" + addrPfx + varname + ", false)")
1416		}
1417	default:
1418		if rtidAdded {
1419			delete(x.te, rtid)
1420		}
1421		x.line("z.DecFallback(" + addrPfx + varname + ", true)")
1422	}
1423}
1424
1425func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type, isptr bool) (done bool) {
1426	// This should only be used for exact primitives (ie un-named types).
1427	// Named types may be implementations of Selfer, Unmarshaler, etc.
1428	// They should be handled by dec(...)
1429
1430	var ptr string
1431	if isptr {
1432		ptr = "*"
1433	}
1434	switch t.Kind() {
1435	case reflect.Int:
1436		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
1437	case reflect.Int8:
1438		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 8))", ptr, varname, x.genTypeName(t))
1439	case reflect.Int16:
1440		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 16))", ptr, varname, x.genTypeName(t))
1441	case reflect.Int32:
1442		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 32))", ptr, varname, x.genTypeName(t))
1443	case reflect.Int64:
1444		x.linef("%s%s = (%s)(r.DecodeInt64())", ptr, varname, x.genTypeName(t))
1445
1446	case reflect.Uint:
1447		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
1448	case reflect.Uint8:
1449		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 8))", ptr, varname, x.genTypeName(t))
1450	case reflect.Uint16:
1451		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 16))", ptr, varname, x.genTypeName(t))
1452	case reflect.Uint32:
1453		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 32))", ptr, varname, x.genTypeName(t))
1454	case reflect.Uint64:
1455		x.linef("%s%s = (%s)(r.DecodeUint64())", ptr, varname, x.genTypeName(t))
1456	case reflect.Uintptr:
1457		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
1458
1459	case reflect.Float32:
1460		x.linef("%s%s = (%s)(r.DecodeFloat32As64())", ptr, varname, x.genTypeName(t))
1461	case reflect.Float64:
1462		x.linef("%s%s = (%s)(r.DecodeFloat64())", ptr, varname, x.genTypeName(t))
1463
1464	case reflect.Bool:
1465		x.linef("%s%s = (%s)(r.DecodeBool())", ptr, varname, x.genTypeName(t))
1466	case reflect.String:
1467		x.linef("%s%s = (%s)(r.DecodeString())", ptr, varname, x.genTypeName(t))
1468	default:
1469		return false
1470	}
1471	return true
1472}
1473
1474func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) {
1475	if t.AssignableTo(uint8SliceTyp) {
1476		x.line("*" + varname + " = r.DecodeBytes(*((*[]byte)(" + varname + ")), false)")
1477		return
1478	}
1479	if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
1480		x.linef("r.DecodeBytes( ((*[%d]byte)(%s))[:], true)", t.Len(), varname)
1481		return
1482	}
1483	type tstruc struct {
1484		TempVar   string
1485		Rand      string
1486		Varname   string
1487		CTyp      string
1488		Typ       string
1489		Immutable bool
1490		Size      int
1491	}
1492	telem := t.Elem()
1493	ts := tstruc{genTempVarPfx, x.varsfx(), varname, x.genTypeName(t), x.genTypeName(telem), genIsImmutable(telem), int(telem.Size())}
1494
1495	funcs := make(template.FuncMap)
1496
1497	funcs["decLineVar"] = func(varname string) string {
1498		x.decVar(varname, "", telem, false, true)
1499		return ""
1500	}
1501	funcs["var"] = func(s string) string {
1502		return ts.TempVar + s + ts.Rand
1503	}
1504	funcs["zero"] = func() string {
1505		return x.genZeroValueR(telem)
1506	}
1507	funcs["isArray"] = func() bool {
1508		return t.Kind() == reflect.Array
1509	}
1510	funcs["isSlice"] = func() bool {
1511		return t.Kind() == reflect.Slice
1512	}
1513	funcs["isChan"] = func() bool {
1514		return t.Kind() == reflect.Chan
1515	}
1516	tm, err := template.New("").Funcs(funcs).Parse(genDecListTmpl)
1517	if err != nil {
1518		panic(err)
1519	}
1520	if err = tm.Execute(x.w, &ts); err != nil {
1521		panic(err)
1522	}
1523}
1524
1525func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) {
1526	type tstruc struct {
1527		TempVar string
1528		Sfx     string
1529		Rand    string
1530		Varname string
1531		KTyp    string
1532		Typ     string
1533		Size    int
1534	}
1535	telem := t.Elem()
1536	tkey := t.Key()
1537	ts := tstruc{
1538		genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey),
1539		x.genTypeName(telem), int(telem.Size() + tkey.Size()),
1540	}
1541
1542	funcs := make(template.FuncMap)
1543	funcs["decElemZero"] = func() string {
1544		return x.genZeroValueR(telem)
1545	}
1546	funcs["decElemKindImmutable"] = func() bool {
1547		return genIsImmutable(telem)
1548	}
1549	funcs["decElemKindPtr"] = func() bool {
1550		return telem.Kind() == reflect.Ptr
1551	}
1552	funcs["decElemKindIntf"] = func() bool {
1553		return telem.Kind() == reflect.Interface
1554	}
1555	funcs["decLineVarK"] = func(varname string) string {
1556		x.decVar(varname, "", tkey, false, true)
1557		return ""
1558	}
1559	funcs["decLineVar"] = func(varname, decodedNilVarname string) string {
1560		x.decVar(varname, decodedNilVarname, telem, false, true)
1561		return ""
1562	}
1563	funcs["var"] = func(s string) string {
1564		return ts.TempVar + s + ts.Rand
1565	}
1566
1567	tm, err := template.New("").Funcs(funcs).Parse(genDecMapTmpl)
1568	if err != nil {
1569		panic(err)
1570	}
1571	if err = tm.Execute(x.w, &ts); err != nil {
1572		panic(err)
1573	}
1574}
1575
1576func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintptr, t reflect.Type) {
1577	ti := x.ti.get(rtid, t)
1578	tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing.
1579	x.line("switch (" + kName + ") {")
1580	var newbuf, nilbuf genBuf
1581	for _, si := range tisfi {
1582		x.line("case \"" + si.encName + "\":")
1583		newbuf.reset()
1584		nilbuf.reset()
1585		t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
1586		x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
1587		x.decVarMain(varname+"."+t2.Name, x.varsfx(), t2.Type, false)
1588		x.line("}")
1589	}
1590	x.line("default:")
1591	// pass the slice here, so that the string will not escape, and maybe save allocation
1592	x.line("z.DecStructFieldNotFound(-1, " + kName + ")")
1593	x.line("} // end switch " + kName)
1594}
1595
1596func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type, style genStructMapStyle) {
1597	tpfx := genTempVarPfx
1598	ti := x.ti.get(rtid, t)
1599	i := x.varsfx()
1600	kName := tpfx + "s" + i
1601
1602	switch style {
1603	case genStructMapStyleLenPrefix:
1604		x.linef("for %sj%s := 0; %sj%s < %s; %sj%s++ {", tpfx, i, tpfx, i, lenvarname, tpfx, i)
1605	case genStructMapStyleCheckBreak:
1606		x.linef("for %sj%s := 0; !r.CheckBreak(); %sj%s++ {", tpfx, i, tpfx, i)
1607	default: // 0, otherwise.
1608		x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
1609		x.linef("for %sj%s := 0; ; %sj%s++ {", tpfx, i, tpfx, i)
1610		x.linef("if %shl%s { if %sj%s >= %s { break }", tpfx, i, tpfx, i, lenvarname)
1611		x.line("} else { if r.CheckBreak() { break }; }")
1612	}
1613	x.line("r.ReadMapElemKey()")
1614
1615	// emulate decstructfieldkey
1616	switch ti.keyType {
1617	case valueTypeInt:
1618		x.linef("%s := z.StringView(strconv.AppendInt(z.DecScratchArrayBuffer()[:0], r.DecodeInt64(), 10))", kName)
1619	case valueTypeUint:
1620		x.linef("%s := z.StringView(strconv.AppendUint(z.DecScratchArrayBuffer()[:0], r.DecodeUint64(), 10))", kName)
1621	case valueTypeFloat:
1622		x.linef("%s := z.StringView(strconv.AppendFloat(z.DecScratchArrayBuffer()[:0], r.DecodeFloat64(), 'f', -1, 64))", kName)
1623	default: // string
1624		x.linef("%s := z.StringView(r.DecodeStringAsBytes())", kName)
1625	}
1626	// x.linef("%s := z.StringView(r.DecStructFieldKey(codecSelferValueType%s%s, z.DecScratchArrayBuffer()))", kName, ti.keyType.String(), x.xs)
1627
1628	x.line("r.ReadMapElemValue()")
1629	x.decStructMapSwitch(kName, varname, rtid, t)
1630
1631	x.line("} // end for " + tpfx + "j" + i)
1632	x.line("r.ReadMapEnd()")
1633}
1634
1635func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) {
1636	tpfx := genTempVarPfx
1637	i := x.varsfx()
1638	ti := x.ti.get(rtid, t)
1639	tisfi := ti.sfiSrc // always use sequence from file. decStruct expects same thing.
1640	x.linef("var %sj%s int", tpfx, i)
1641	x.linef("var %sb%s bool", tpfx, i)                        // break
1642	x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
1643	var newbuf, nilbuf genBuf
1644	for _, si := range tisfi {
1645		x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }",
1646			tpfx, i, tpfx, i, tpfx, i,
1647			tpfx, i, lenvarname, tpfx, i)
1648		x.linef("if %sb%s { r.ReadArrayEnd(); %s }", tpfx, i, breakString)
1649		x.line("r.ReadArrayElem()")
1650		newbuf.reset()
1651		nilbuf.reset()
1652		t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
1653		x.linef("if r.TryDecodeAsNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
1654		x.decVarMain(varname+"."+t2.Name, x.varsfx(), t2.Type, false)
1655		x.line("}")
1656	}
1657	// read remaining values and throw away.
1658	x.line("for {")
1659	x.linef("%sj%s++; if %shl%s { %sb%s = %sj%s > %s } else { %sb%s = r.CheckBreak() }",
1660		tpfx, i, tpfx, i, tpfx, i,
1661		tpfx, i, lenvarname, tpfx, i)
1662	x.linef("if %sb%s { break }", tpfx, i)
1663	x.line("r.ReadArrayElem()")
1664	x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i)
1665	x.line("}")
1666	x.line("r.ReadArrayEnd()")
1667}
1668
1669func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
1670	// varname MUST be a ptr, or a struct field or a slice element.
1671	i := x.varsfx()
1672	x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i)
1673	x.linef("if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs)
1674	x.line(genTempVarPfx + "l" + i + " := r.ReadMapStart()")
1675	x.linef("if %sl%s == 0 {", genTempVarPfx, i)
1676	x.line("r.ReadMapEnd()")
1677	if genUseOneFunctionForDecStructMap {
1678		x.line("} else { ")
1679		x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i)
1680	} else {
1681		x.line("} else if " + genTempVarPfx + "l" + i + " > 0 { ")
1682		x.line(varname + ".codecDecodeSelfFromMapLenPrefix(" + genTempVarPfx + "l" + i + ", d)")
1683		x.line("} else {")
1684		x.line(varname + ".codecDecodeSelfFromMapCheckBreak(" + genTempVarPfx + "l" + i + ", d)")
1685	}
1686	x.line("}")
1687
1688	// else if container is array
1689	x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs)
1690	x.line(genTempVarPfx + "l" + i + " := r.ReadArrayStart()")
1691	x.linef("if %sl%s == 0 {", genTempVarPfx, i)
1692	x.line("r.ReadArrayEnd()")
1693	x.line("} else { ")
1694	x.linef("%s.codecDecodeSelfFromArray(%sl%s, d)", varname, genTempVarPfx, i)
1695	x.line("}")
1696	// else panic
1697	x.line("} else { ")
1698	x.line("panic(errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + ")")
1699	x.line("} ")
1700}
1701
1702// --------
1703
1704type genV struct {
1705	// genV is either a primitive (Primitive != "") or a map (MapKey != "") or a slice
1706	MapKey    string
1707	Elem      string
1708	Primitive string
1709	Size      int
1710}
1711
1712func (x *genRunner) newGenV(t reflect.Type) (v genV) {
1713	switch t.Kind() {
1714	case reflect.Slice, reflect.Array:
1715		te := t.Elem()
1716		v.Elem = x.genTypeName(te)
1717		v.Size = int(te.Size())
1718	case reflect.Map:
1719		te, tk := t.Elem(), t.Key()
1720		v.Elem = x.genTypeName(te)
1721		v.MapKey = x.genTypeName(tk)
1722		v.Size = int(te.Size() + tk.Size())
1723	default:
1724		panic("unexpected type for newGenV. Requires map or slice type")
1725	}
1726	return
1727}
1728
1729func (x *genV) MethodNamePfx(prefix string, prim bool) string {
1730	var name []byte
1731	if prefix != "" {
1732		name = append(name, prefix...)
1733	}
1734	if prim {
1735		name = append(name, genTitleCaseName(x.Primitive)...)
1736	} else {
1737		if x.MapKey == "" {
1738			name = append(name, "Slice"...)
1739		} else {
1740			name = append(name, "Map"...)
1741			name = append(name, genTitleCaseName(x.MapKey)...)
1742		}
1743		name = append(name, genTitleCaseName(x.Elem)...)
1744	}
1745	return string(name)
1746
1747}
1748
1749// genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise.
1750//
1751// This handles the misbehaviour that occurs when 1.5-style vendoring is enabled,
1752// where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped.
1753// We strip it here.
1754func genImportPath(t reflect.Type) (s string) {
1755	s = t.PkgPath()
1756	if genCheckVendor {
1757		// HACK: always handle vendoring. It should be typically on in go 1.6, 1.7
1758		s = genStripVendor(s)
1759	}
1760	return
1761}
1762
1763// A go identifier is (letter|_)[letter|number|_]*
1764func genGoIdentifier(s string, checkFirstChar bool) string {
1765	b := make([]byte, 0, len(s))
1766	t := make([]byte, 4)
1767	var n int
1768	for i, r := range s {
1769		if checkFirstChar && i == 0 && !unicode.IsLetter(r) {
1770			b = append(b, '_')
1771		}
1772		// r must be unicode_letter, unicode_digit or _
1773		if unicode.IsLetter(r) || unicode.IsDigit(r) {
1774			n = utf8.EncodeRune(t, r)
1775			b = append(b, t[:n]...)
1776		} else {
1777			b = append(b, '_')
1778		}
1779	}
1780	return string(b)
1781}
1782
1783func genNonPtr(t reflect.Type) reflect.Type {
1784	for t.Kind() == reflect.Ptr {
1785		t = t.Elem()
1786	}
1787	return t
1788}
1789
1790func genTitleCaseName(s string) string {
1791	switch s {
1792	case "interface{}", "interface {}":
1793		return "Intf"
1794	default:
1795		return strings.ToUpper(s[0:1]) + s[1:]
1796	}
1797}
1798
1799func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) {
1800	var ptrPfx string
1801	for t.Kind() == reflect.Ptr {
1802		ptrPfx += "Ptrto"
1803		t = t.Elem()
1804	}
1805	tstr := t.String()
1806	if tn := t.Name(); tn != "" {
1807		if tRef != nil && genImportPath(t) == genImportPath(tRef) {
1808			return ptrPfx + tn
1809		} else {
1810			if genQNameRegex.MatchString(tstr) {
1811				return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
1812			} else {
1813				return ptrPfx + genCustomTypeName(tstr)
1814			}
1815		}
1816	}
1817	switch t.Kind() {
1818	case reflect.Map:
1819		return ptrPfx + "Map" + genMethodNameT(t.Key(), tRef) + genMethodNameT(t.Elem(), tRef)
1820	case reflect.Slice:
1821		return ptrPfx + "Slice" + genMethodNameT(t.Elem(), tRef)
1822	case reflect.Array:
1823		return ptrPfx + "Array" + strconv.FormatInt(int64(t.Len()), 10) + genMethodNameT(t.Elem(), tRef)
1824	case reflect.Chan:
1825		var cx string
1826		switch t.ChanDir() {
1827		case reflect.SendDir:
1828			cx = "ChanSend"
1829		case reflect.RecvDir:
1830			cx = "ChanRecv"
1831		default:
1832			cx = "Chan"
1833		}
1834		return ptrPfx + cx + genMethodNameT(t.Elem(), tRef)
1835	default:
1836		if t == intfTyp {
1837			return ptrPfx + "Interface"
1838		} else {
1839			if tRef != nil && genImportPath(t) == genImportPath(tRef) {
1840				if t.Name() != "" {
1841					return ptrPfx + t.Name()
1842				} else {
1843					return ptrPfx + genCustomTypeName(tstr)
1844				}
1845			} else {
1846				// best way to get the package name inclusive
1847				// return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
1848				// return ptrPfx + genBase64enc.EncodeToString([]byte(tstr))
1849				if t.Name() != "" && genQNameRegex.MatchString(tstr) {
1850					return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
1851				} else {
1852					return ptrPfx + genCustomTypeName(tstr)
1853				}
1854			}
1855		}
1856	}
1857}
1858
1859// genCustomNameForType base64encodes the t.String() value in such a way
1860// that it can be used within a function name.
1861func genCustomTypeName(tstr string) string {
1862	len2 := genBase64enc.EncodedLen(len(tstr))
1863	bufx := make([]byte, len2)
1864	genBase64enc.Encode(bufx, []byte(tstr))
1865	for i := len2 - 1; i >= 0; i-- {
1866		if bufx[i] == '=' {
1867			len2--
1868		} else {
1869			break
1870		}
1871	}
1872	return string(bufx[:len2])
1873}
1874
1875func genIsImmutable(t reflect.Type) (v bool) {
1876	return isImmutableKind(t.Kind())
1877}
1878
1879type genInternal struct {
1880	Version int
1881	Values  []genV
1882}
1883
1884func (x genInternal) FastpathLen() (l int) {
1885	for _, v := range x.Values {
1886		if v.Primitive == "" && !(v.MapKey == "" && v.Elem == "uint8") {
1887			l++
1888		}
1889	}
1890	return
1891}
1892
1893func genInternalZeroValue(s string) string {
1894	switch s {
1895	case "interface{}", "interface {}":
1896		return "nil"
1897	case "bool":
1898		return "false"
1899	case "string":
1900		return `""`
1901	default:
1902		return "0"
1903	}
1904}
1905
1906var genInternalNonZeroValueIdx [5]uint64
1907var genInternalNonZeroValueStrs = [2][5]string{
1908	{`"string-is-an-interface"`, "true", `"some-string"`, "11.1", "33"},
1909	{`"string-is-an-interface-2"`, "true", `"some-string-2"`, "22.2", "44"},
1910}
1911
1912func genInternalNonZeroValue(s string) string {
1913	switch s {
1914	case "interface{}", "interface {}":
1915		genInternalNonZeroValueIdx[0]++
1916		return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[0]%2][0] // return string, to remove ambiguity
1917	case "bool":
1918		genInternalNonZeroValueIdx[1]++
1919		return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[1]%2][1]
1920	case "string":
1921		genInternalNonZeroValueIdx[2]++
1922		return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[2]%2][2]
1923	case "float32", "float64", "float", "double":
1924		genInternalNonZeroValueIdx[3]++
1925		return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[3]%2][3]
1926	default:
1927		genInternalNonZeroValueIdx[4]++
1928		return genInternalNonZeroValueStrs[genInternalNonZeroValueIdx[4]%2][4]
1929	}
1930}
1931
1932func genInternalEncCommandAsString(s string, vname string) string {
1933	switch s {
1934	case "uint", "uint8", "uint16", "uint32", "uint64":
1935		return "ee.EncodeUint(uint64(" + vname + "))"
1936	case "int", "int8", "int16", "int32", "int64":
1937		return "ee.EncodeInt(int64(" + vname + "))"
1938	case "string":
1939		return "if e.h.StringToRaw { ee.EncodeStringBytesRaw(bytesView(" + vname + ")) " +
1940			"} else { 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