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