github.com/ugorji/go/codec@v1.2.13-0.20240307214044-07c54c229a5a/gen.go (about)

     1  // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
     2  // Use of this source code is governed by a MIT license found in the LICENSE file.
     3  
     4  //go:build codecgen.exec
     5  // +build codecgen.exec
     6  
     7  package codec
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/base32"
    12  	"errors"
    13  	"fmt"
    14  	"go/format"
    15  	"io"
    16  	"io/ioutil"
    17  	"math/rand"
    18  	"os"
    19  	"reflect"
    20  	"regexp"
    21  	"sort"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  	"text/template"
    26  	"time"
    27  	// "ugorji.net/zz"
    28  	"unicode"
    29  	"unicode/utf8"
    30  )
    31  
    32  // ---------------------------------------------------
    33  // codecgen supports the full cycle of reflection-based codec:
    34  //    - RawExt
    35  //    - Raw
    36  //    - Extensions
    37  //    - (Binary|Text|JSON)(Unm|M)arshal
    38  //    - generic by-kind
    39  //
    40  // This means that, for dynamic things, we MUST use reflection to at least get the reflect.Type.
    41  // In those areas, we try to only do reflection or interface-conversion when NECESSARY:
    42  //    - Extensions, only if Extensions are configured.
    43  //
    44  // However, note following codecgen caveats:
    45  //   - Canonical option.
    46  //     If Canonical=true, codecgen'ed code may delegate encoding maps to reflection-based code.
    47  //     This is due to the runtime work needed to marshal a map in canonical mode.
    48  //     However, if map key is a pre-defined/builtin numeric or string type, codecgen
    49  //     will try to write it out itself
    50  //   - CheckCircularRef option.
    51  //     When encoding a struct, a circular reference can lead to a stack overflow.
    52  //     If CheckCircularRef=true, codecgen'ed code will delegate encoding structs to reflection-based code.
    53  //   - MissingFielder implementation.
    54  //     If a type implements MissingFielder, a Selfer is not generated (with a warning message).
    55  //     Statically reproducing the runtime work needed to extract the missing fields and marshal them
    56  //     along with the struct fields, while handling the Canonical=true special case, was onerous to implement.
    57  //
    58  // During encode/decode, Selfer takes precedence.
    59  // A type implementing Selfer will know how to encode/decode itself statically.
    60  //
    61  // The following field types are supported:
    62  //     array: [n]T
    63  //     slice: []T
    64  //     map: map[K]V
    65  //     primitive: [u]int[n], float(32|64), bool, string
    66  //     struct
    67  //
    68  // ---------------------------------------------------
    69  // Note that a Selfer cannot call (e|d).(En|De)code on itself,
    70  // as this will cause a circular reference, as (En|De)code will call Selfer methods.
    71  // Any type that implements Selfer must implement completely and not fallback to (En|De)code.
    72  //
    73  // In addition, code in this file manages the generation of fast-path implementations of
    74  // encode/decode of slices/maps of primitive keys/values.
    75  //
    76  // Users MUST re-generate their implementations whenever the code shape changes.
    77  // The generated code will panic if it was generated with a version older than the supporting library.
    78  // ---------------------------------------------------
    79  //
    80  // codec framework is very feature rich.
    81  // When encoding or decoding into an interface, it depends on the runtime type of the interface.
    82  // The type of the interface may be a named type, an extension, etc.
    83  // Consequently, we fallback to runtime codec for encoding/decoding interfaces.
    84  // In addition, we fallback for any value which cannot be guaranteed at runtime.
    85  // This allows us support ANY value, including any named types, specifically those which
    86  // do not implement our interfaces (e.g. Selfer).
    87  //
    88  // This explains some slowness compared to other code generation codecs (e.g. msgp).
    89  // This reduction in speed is only seen when your refers to interfaces,
    90  // e.g. type T struct { A interface{}; B []interface{}; C map[string]interface{} }
    91  //
    92  // codecgen will panic if the file was generated with an old version of the library in use.
    93  //
    94  // Note:
    95  //   It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil.
    96  //   This way, there isn't a function call overhead just to see that we should not enter a block of code.
    97  //
    98  // Note:
    99  //   codecgen-generated code depends on the variables defined by fast-path.generated.go.
   100  //   consequently, you cannot run with tags "codecgen codec.notfastpath".
   101  //
   102  // Note:
   103  //   genInternalXXX functions are used for generating fast-path and other internally generated
   104  //   files, and not for use in codecgen.
   105  
   106  // Size of a struct or value is not portable across machines, especially across 32-bit vs 64-bit
   107  // operating systems. This is due to types like int, uintptr, pointers, (and derived types like slice), etc
   108  // which use the natural word size on those machines, which may be 4 bytes (on 32-bit) or 8 bytes (on 64-bit).
   109  //
   110  // Within decInferLen calls, we may generate an explicit size of the entry.
   111  // We do this because decInferLen values are expected to be approximate,
   112  // and serve as a good hint on the size of the elements or key+value entry.
   113  //
   114  // Since development is done on 64-bit machines, the sizes will be roughly correctly
   115  // on 64-bit OS, and slightly larger than expected on 32-bit OS.
   116  // This is ok.
   117  //
   118  // For reference, look for 'Size' in fast-path.go.tmpl, gen-dec-(array|map).go.tmpl and gen.go (this file).
   119  
   120  // GenVersion is the current version of codecgen.
   121  //
   122  // MARKER: Increment this value each time codecgen changes fundamentally.
   123  // Also update codecgen/gen.go (minimumCodecVersion, genVersion, etc).
   124  // Fundamental changes are:
   125  //   - helper methods change (signature change, new ones added, some removed, etc)
   126  //   - codecgen command line changes
   127  //
   128  // v1: Initial Version
   129  // v2: -
   130  // v3: For Kubernetes: changes in signature of some unpublished helper methods and codecgen cmdline arguments.
   131  // v4: Removed separator support from (en|de)cDriver, and refactored codec(gen)
   132  // v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections.
   133  // v6: removed unsafe from gen, and now uses codecgen.exec tag
   134  // v7: -
   135  // v8: current - we now maintain compatibility with old generated code.
   136  // v9: - skipped
   137  // v10: modified encDriver and decDriver interfaces.
   138  // v11: remove deprecated methods of encDriver and decDriver.
   139  // v12: removed deprecated methods from genHelper and changed container tracking logic
   140  // v13: 20190603 removed DecodeString - use DecodeStringAsBytes instead
   141  // v14: 20190611 refactored nil handling: TryDecodeAsNil -> selective TryNil, etc
   142  // v15: 20190626 encDriver.EncodeString handles StringToRaw flag inside handle
   143  // v16: 20190629 refactoring for v1.1.6
   144  // v17: 20200911 reduce number of types for which we generate fast path functions (v1.1.8)
   145  // v18: 20201004 changed definition of genHelper...Extension (to take interface{}) and eliminated I2Rtid method
   146  // v19: 20201115 updated codecgen cmdline flags and optimized output
   147  // v20: 20201120 refactored GenHelper to one exported function
   148  // v21: 20210104 refactored generated code to honor ZeroCopy=true for more efficiency
   149  // v22: 20210118 fixed issue in generated code when encoding a type which is also a codec.Selfer
   150  // v23: 20210203 changed slice/map types for which we generate fast-path functions
   151  // v24: 20210226 robust handling for Canonical|CheckCircularRef flags and MissingFielder implementations
   152  // v25: 20210406 pass base reflect.Type to side(En|De)code and (En|De)codeExt calls
   153  // v26: 20230201 genHelper changes for more inlining and consequent performance
   154  // v27: 20230219 fix error decoding struct from array - due to misplaced counter increment
   155  // v28: 20230224  fix decoding missing fields of struct from array, due to double counter increment
   156  const genVersion = 28
   157  
   158  const (
   159  	genCodecPkg        = "codec1978" // MARKER: keep in sync with codecgen/gen.go
   160  	genTempVarPfx      = "yy"
   161  	genTopLevelVarName = "x"
   162  
   163  	// ignore canBeNil parameter, and always set to true.
   164  	// This is because nil can appear anywhere, so we should always check.
   165  	genAnythingCanBeNil = true
   166  
   167  	// genStructCanonical configures whether we generate 2 paths based on Canonical flag
   168  	// when encoding struct fields.
   169  	genStructCanonical = true
   170  
   171  	// genFastpathCanonical configures whether we support Canonical in fast path.
   172  	// The savings is not much.
   173  	//
   174  	// MARKER: This MUST ALWAYS BE TRUE. fast-path.go.tmp doesn't handle it being false.
   175  	genFastpathCanonical = true
   176  
   177  	// genFastpathTrimTypes configures whether we trim uncommon fastpath types.
   178  	genFastpathTrimTypes = true
   179  )
   180  
   181  type genStringDecAsBytes string
   182  type genStringDecZC string
   183  
   184  var genStringDecAsBytesTyp = reflect.TypeOf(genStringDecAsBytes(""))
   185  var genStringDecZCTyp = reflect.TypeOf(genStringDecZC(""))
   186  var genFormats = []string{"Json", "Cbor", "Msgpack", "Binc", "Simple"}
   187  
   188  var (
   189  	errGenAllTypesSamePkg        = errors.New("All types must be in the same package")
   190  	errGenExpectArrayOrMap       = errors.New("unexpected type - expecting array/map/slice")
   191  	errGenUnexpectedTypeFastpath = errors.New("fast-path: unexpected type - requires map or slice")
   192  
   193  	// don't use base64, only 63 characters allowed in valid go identifiers
   194  	// ie ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_
   195  	//
   196  	// don't use numbers, as a valid go identifer must start with a letter.
   197  	genTypenameEnc  = base32.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
   198  	genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`)
   199  )
   200  
   201  type genBuf struct {
   202  	buf []byte
   203  }
   204  
   205  func (x *genBuf) sIf(b bool, s, t string) *genBuf {
   206  	if b {
   207  		x.buf = append(x.buf, s...)
   208  	} else {
   209  		x.buf = append(x.buf, t...)
   210  	}
   211  	return x
   212  }
   213  func (x *genBuf) s(s string) *genBuf              { x.buf = append(x.buf, s...); return x }
   214  func (x *genBuf) b(s []byte) *genBuf              { x.buf = append(x.buf, s...); return x }
   215  func (x *genBuf) v() string                       { return string(x.buf) }
   216  func (x *genBuf) f(s string, args ...interface{}) { x.s(fmt.Sprintf(s, args...)) }
   217  func (x *genBuf) reset() {
   218  	if x.buf != nil {
   219  		x.buf = x.buf[:0]
   220  	}
   221  }
   222  
   223  // genRunner holds some state used during a Gen run.
   224  type genRunner struct {
   225  	w io.Writer // output
   226  	c uint64    // counter used for generating varsfx
   227  	f uint64    // counter used for saying false
   228  
   229  	t  []reflect.Type   // list of types to run selfer on
   230  	tc reflect.Type     // currently running selfer on this type
   231  	te map[uintptr]bool // types for which the encoder has been created
   232  	td map[uintptr]bool // types for which the decoder has been created
   233  	tz map[uintptr]bool // types for which GenIsZero has been created
   234  
   235  	cp string // codec import path
   236  
   237  	im  map[string]reflect.Type // imports to add
   238  	imn map[string]string       // package names of imports to add
   239  	imc uint64                  // counter for import numbers
   240  
   241  	is map[reflect.Type]struct{} // types seen during import search
   242  	bp string                    // base PkgPath, for which we are generating for
   243  
   244  	cpfx string // codec package prefix
   245  
   246  	ty map[reflect.Type]struct{} // types for which GenIsZero *should* be created
   247  	tm map[reflect.Type]struct{} // types for which enc/dec must be generated
   248  	ts []reflect.Type            // types for which enc/dec must be generated
   249  
   250  	xs string // top level variable/constant suffix
   251  	hn string // fn helper type name
   252  
   253  	ti *TypeInfos
   254  	// rr *rand.Rand // random generator for file-specific types
   255  
   256  	jsonOnlyWhen, toArrayWhen, omitEmptyWhen *bool
   257  
   258  	nx bool // no extensions
   259  }
   260  
   261  type genIfClause struct {
   262  	hasIf bool
   263  }
   264  
   265  func (g *genIfClause) end(x *genRunner) {
   266  	if g.hasIf {
   267  		x.line("}")
   268  	}
   269  }
   270  
   271  func (g *genIfClause) c(last bool) (v string) {
   272  	if last {
   273  		if g.hasIf {
   274  			v = " } else { "
   275  		}
   276  	} else if g.hasIf {
   277  		v = " } else if "
   278  	} else {
   279  		v = "if "
   280  		g.hasIf = true
   281  	}
   282  	return
   283  }
   284  
   285  // Gen will write a complete go file containing Selfer implementations for each
   286  // type passed. All the types must be in the same package.
   287  //
   288  // Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINUOUSLY WITHOUT NOTICE.
   289  func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool,
   290  	jsonOnlyWhen, toArrayWhen, omitEmptyWhen *bool,
   291  	ti *TypeInfos, types ...reflect.Type) (warnings []string) {
   292  	// All types passed to this method do not have a codec.Selfer method implemented directly.
   293  	// codecgen already checks the AST and skips any types that define the codec.Selfer methods.
   294  	// Consequently, there's no need to check and trim them if they implement codec.Selfer
   295  
   296  	if len(types) == 0 {
   297  		return
   298  	}
   299  	x := genRunner{
   300  		w:             w,
   301  		t:             types,
   302  		te:            make(map[uintptr]bool),
   303  		td:            make(map[uintptr]bool),
   304  		tz:            make(map[uintptr]bool),
   305  		im:            make(map[string]reflect.Type),
   306  		imn:           make(map[string]string),
   307  		is:            make(map[reflect.Type]struct{}),
   308  		tm:            make(map[reflect.Type]struct{}),
   309  		ty:            make(map[reflect.Type]struct{}),
   310  		ts:            []reflect.Type{},
   311  		bp:            genImportPath(types[0]),
   312  		xs:            uid,
   313  		ti:            ti,
   314  		jsonOnlyWhen:  jsonOnlyWhen,
   315  		toArrayWhen:   toArrayWhen,
   316  		omitEmptyWhen: omitEmptyWhen,
   317  
   318  		nx: noExtensions,
   319  	}
   320  	if x.ti == nil {
   321  		x.ti = defTypeInfos
   322  	}
   323  	if x.xs == "" {
   324  		rr := rand.New(rand.NewSource(time.Now().UnixNano()))
   325  		x.xs = strconv.FormatInt(rr.Int63n(9999), 10)
   326  	}
   327  
   328  	// gather imports first:
   329  	x.cp = genImportPath(reflect.TypeOf(x))
   330  	x.imn[x.cp] = genCodecPkg
   331  
   332  	// iterate, check if all in same package, and remove any missingfielders
   333  	for i := 0; i < len(x.t); {
   334  		t := x.t[i]
   335  		// xdebugf("###########: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name())
   336  		if genImportPath(t) != x.bp {
   337  			halt.onerror(errGenAllTypesSamePkg)
   338  		}
   339  		ti1 := x.ti.get(rt2id(t), t)
   340  		if ti1.flagMissingFielder || ti1.flagMissingFielderPtr {
   341  			// output diagnostic message  - that nothing generated for this type
   342  			warnings = append(warnings, fmt.Sprintf("type: '%v' not generated; implements codec.MissingFielder", t))
   343  			copy(x.t[i:], x.t[i+1:])
   344  			x.t = x.t[:len(x.t)-1]
   345  			continue
   346  		}
   347  		x.genRefPkgs(t)
   348  		i++
   349  	}
   350  
   351  	x.line("// +build go1.6")
   352  	if buildTags != "" {
   353  		x.line("// +build " + buildTags)
   354  	}
   355  	x.line(`
   356  
   357  // Code generated by codecgen - DO NOT EDIT.
   358  
   359  `)
   360  	x.line("package " + pkgName)
   361  	x.line("")
   362  	x.line("import (")
   363  	if x.cp != x.bp {
   364  		x.cpfx = genCodecPkg + "."
   365  		x.linef("%s \"%s\"", genCodecPkg, x.cp)
   366  	}
   367  	// use a sorted set of im keys, so that we can get consistent output
   368  	imKeys := make([]string, 0, len(x.im))
   369  	for k := range x.im {
   370  		imKeys = append(imKeys, k)
   371  	}
   372  	sort.Strings(imKeys)
   373  	for _, k := range imKeys { // for k, _ := range x.im {
   374  		if k == x.imn[k] {
   375  			x.linef("\"%s\"", k)
   376  		} else {
   377  			x.linef("%s \"%s\"", x.imn[k], k)
   378  		}
   379  	}
   380  	// add required packages
   381  	for _, k := range [...]string{"runtime", "errors", "strconv", "sort"} { // "reflect", "fmt"
   382  		if _, ok := x.im[k]; !ok {
   383  			x.line("\"" + k + "\"")
   384  		}
   385  	}
   386  	x.line(")")
   387  	x.line("")
   388  
   389  	x.line("const (")
   390  	x.linef("// ----- content types ----")
   391  	x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8))
   392  	x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW))
   393  	x.linef("// ----- value types used ----")
   394  	for _, vt := range [...]valueType{
   395  		valueTypeArray, valueTypeMap, valueTypeString,
   396  		valueTypeInt, valueTypeUint, valueTypeFloat,
   397  		valueTypeNil,
   398  	} {
   399  		x.linef("codecSelferValueType%s%s = %v", vt.String(), x.xs, int64(vt))
   400  	}
   401  
   402  	x.linef("codecSelferBitsize%s = uint8(32 << (^uint(0) >> 63))", x.xs)
   403  	x.linef("codecSelferDecContainerLenNil%s = %d", x.xs, int64(containerLenNil))
   404  	x.line(")")
   405  	x.line("var (")
   406  	x.line("errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + " = " + "errors.New(`only encoded map or array can be decoded into a struct`)")
   407  	x.line("_ sort.Interface = nil")
   408  	x.line(")")
   409  	x.line("")
   410  
   411  	x.hn = "codecSelfer" + x.xs
   412  	x.line("type " + x.hn + " struct{}")
   413  	x.line("")
   414  	x.linef("func %sFalse() bool { return false }", x.hn)
   415  	x.linef("func %sTrue() bool { return true }", x.hn)
   416  	x.line("")
   417  
   418  	// add types for sorting canonical
   419  	for _, s := range []string{"string", "uint64", "int64", "float64"} {
   420  		x.linef("type %s%sSlice []%s", x.hn, s, s)
   421  		x.linef("func (p %s%sSlice) Len() int      { return len(p) }", x.hn, s)
   422  		x.linef("func (p %s%sSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }", x.hn, s)
   423  		x.linef("func (p %s%sSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] }", x.hn, s)
   424  	}
   425  
   426  	x.line("")
   427  	x.varsfxreset()
   428  	x.line("func init() {")
   429  	x.linef("if %sGenVersion != %v {", x.cpfx, genVersion)
   430  	x.line("_, file, _, _ := runtime.Caller(0)")
   431  	x.linef("ver := strconv.FormatInt(int64(%sGenVersion), 10)", x.cpfx)
   432  	x.outf(`panic(errors.New("codecgen version mismatch: current: %v, need " + ver + ". Re-generate file: " + file))`, genVersion)
   433  	x.linef("}")
   434  	if len(imKeys) > 0 {
   435  		x.line("if false { // reference the types, but skip this branch at build/run time")
   436  		for _, k := range imKeys {
   437  			t := x.im[k]
   438  			x.linef("var _ %s.%s", x.imn[k], t.Name())
   439  		}
   440  		x.line("} ") // close if false
   441  	}
   442  	x.line("}") // close init
   443  	x.line("")
   444  
   445  	// generate rest of type info
   446  	for _, t := range x.t {
   447  		x.tc = t
   448  		x.linef("func (%s) codecSelferViaCodecgen() {}", x.genTypeName(t))
   449  		x.selfer(true)
   450  		x.selfer(false)
   451  		x.tryGenIsZero(t)
   452  	}
   453  
   454  	for _, t := range x.ts {
   455  		rtid := rt2id(t)
   456  		// generate enc functions for all these slice/map types.
   457  		x.varsfxreset()
   458  		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)
   459  		x.genRequiredMethodVars(true)
   460  		switch t.Kind() {
   461  		case reflect.Array, reflect.Slice, reflect.Chan:
   462  			x.encListFallback("v", t)
   463  		case reflect.Map:
   464  			x.encMapFallback("v", t)
   465  		default:
   466  			halt.onerror(errGenExpectArrayOrMap)
   467  		}
   468  		x.line("}")
   469  		x.line("")
   470  
   471  		// generate dec functions for all these slice/map types.
   472  		x.varsfxreset()
   473  		x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx)
   474  		x.genRequiredMethodVars(false)
   475  		switch t.Kind() {
   476  		case reflect.Array, reflect.Slice, reflect.Chan:
   477  			x.decListFallback("v", rtid, t)
   478  		case reflect.Map:
   479  			x.decMapFallback("v", rtid, t)
   480  		default:
   481  			halt.onerror(errGenExpectArrayOrMap)
   482  		}
   483  		x.line("}")
   484  		x.line("")
   485  	}
   486  
   487  	for t := range x.ty {
   488  		x.tryGenIsZero(t)
   489  		x.line("")
   490  	}
   491  
   492  	x.line("")
   493  	return
   494  }
   495  
   496  func (x *genRunner) checkForSelfer(t reflect.Type, varname string) bool {
   497  	// return varname != genTopLevelVarName && t != x.tc
   498  	// the only time we checkForSelfer is if we are not at the TOP of the generated code.
   499  	return varname != genTopLevelVarName
   500  }
   501  
   502  func (x *genRunner) arr2str(t reflect.Type, s string) string {
   503  	if t.Kind() == reflect.Array {
   504  		return s
   505  	}
   506  	return ""
   507  }
   508  
   509  func (x *genRunner) genRequiredMethodVars(encode bool) {
   510  	x.line("var h " + x.hn)
   511  	if encode {
   512  		x.line("z, r := " + x.cpfx + "GenHelper().Encoder(e)")
   513  	} else {
   514  		x.line("z, r := " + x.cpfx + "GenHelper().Decoder(d)")
   515  	}
   516  	x.line("_, _, _ = h, z, r")
   517  }
   518  
   519  func (x *genRunner) genRefPkgs(t reflect.Type) {
   520  	if _, ok := x.is[t]; ok {
   521  		return
   522  	}
   523  	x.is[t] = struct{}{}
   524  	tpkg, tname := genImportPath(t), t.Name()
   525  	if tpkg != "" && tpkg != x.bp && tpkg != x.cp && tname != "" && tname[0] >= 'A' && tname[0] <= 'Z' {
   526  		if _, ok := x.im[tpkg]; !ok {
   527  			x.im[tpkg] = t
   528  			if idx := strings.LastIndex(tpkg, "/"); idx < 0 {
   529  				x.imn[tpkg] = tpkg
   530  			} else {
   531  				x.imc++
   532  				x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + genGoIdentifier(tpkg[idx+1:], false)
   533  			}
   534  		}
   535  	}
   536  	switch t.Kind() {
   537  	case reflect.Array, reflect.Slice, reflect.Ptr, reflect.Chan:
   538  		x.genRefPkgs(t.Elem())
   539  	case reflect.Map:
   540  		x.genRefPkgs(t.Elem())
   541  		x.genRefPkgs(t.Key())
   542  	case reflect.Struct:
   543  		for i := 0; i < t.NumField(); i++ {
   544  			if fname := t.Field(i).Name; fname != "" && fname[0] >= 'A' && fname[0] <= 'Z' {
   545  				x.genRefPkgs(t.Field(i).Type)
   546  			}
   547  		}
   548  	}
   549  }
   550  
   551  // sayFalse will either say "false" or use a function call that returns false.
   552  func (x *genRunner) sayFalse() string {
   553  	x.f++
   554  	if x.f%2 == 0 {
   555  		return x.hn + "False()"
   556  	}
   557  	return "false"
   558  }
   559  
   560  // sayFalse will either say "true" or use a function call that returns true.
   561  func (x *genRunner) sayTrue() string {
   562  	x.f++
   563  	if x.f%2 == 0 {
   564  		return x.hn + "True()"
   565  	}
   566  	return "true"
   567  }
   568  
   569  func (x *genRunner) varsfx() string {
   570  	x.c++
   571  	return strconv.FormatUint(x.c, 10)
   572  }
   573  
   574  func (x *genRunner) varsfxreset() {
   575  	x.c = 0
   576  }
   577  
   578  func (x *genRunner) out(s string) {
   579  	_, err := io.WriteString(x.w, s)
   580  	genCheckErr(err)
   581  }
   582  
   583  func (x *genRunner) outf(s string, params ...interface{}) {
   584  	_, err := fmt.Fprintf(x.w, s, params...)
   585  	genCheckErr(err)
   586  }
   587  
   588  func (x *genRunner) line(s string) {
   589  	x.out(s)
   590  	if len(s) == 0 || s[len(s)-1] != '\n' {
   591  		x.out("\n")
   592  	}
   593  }
   594  
   595  func (x *genRunner) lineIf(s string) {
   596  	if s != "" {
   597  		x.line(s)
   598  	}
   599  }
   600  
   601  func (x *genRunner) linef(s string, params ...interface{}) {
   602  	x.outf(s, params...)
   603  	if len(s) == 0 || s[len(s)-1] != '\n' {
   604  		x.out("\n")
   605  	}
   606  }
   607  
   608  func (x *genRunner) genTypeName(t reflect.Type) (n string) {
   609  	// if the type has a PkgPath, which doesn't match the current package,
   610  	// then include it.
   611  	// We cannot depend on t.String() because it includes current package,
   612  	// or t.PkgPath because it includes full import path,
   613  	//
   614  	var ptrPfx string
   615  	for t.Kind() == reflect.Ptr {
   616  		ptrPfx += "*"
   617  		t = t.Elem()
   618  	}
   619  	if tn := t.Name(); tn != "" {
   620  		return ptrPfx + x.genTypeNamePrim(t)
   621  	}
   622  	switch t.Kind() {
   623  	case reflect.Map:
   624  		return ptrPfx + "map[" + x.genTypeName(t.Key()) + "]" + x.genTypeName(t.Elem())
   625  	case reflect.Slice:
   626  		return ptrPfx + "[]" + x.genTypeName(t.Elem())
   627  	case reflect.Array:
   628  		return ptrPfx + "[" + strconv.FormatInt(int64(t.Len()), 10) + "]" + x.genTypeName(t.Elem())
   629  	case reflect.Chan:
   630  		return ptrPfx + t.ChanDir().String() + " " + x.genTypeName(t.Elem())
   631  	default:
   632  		if t == intfTyp {
   633  			return ptrPfx + "interface{}"
   634  		} else {
   635  			return ptrPfx + x.genTypeNamePrim(t)
   636  		}
   637  	}
   638  }
   639  
   640  func (x *genRunner) genTypeNamePrim(t reflect.Type) (n string) {
   641  	if t.Name() == "" {
   642  		return t.String()
   643  	} else if genImportPath(t) == "" || genImportPath(t) == genImportPath(x.tc) {
   644  		return t.Name()
   645  	} else {
   646  		return x.imn[genImportPath(t)] + "." + t.Name()
   647  		// return t.String() // best way to get the package name inclusive
   648  	}
   649  }
   650  
   651  func (x *genRunner) genZeroValueR(t reflect.Type) string {
   652  	// if t is a named type, w
   653  	switch t.Kind() {
   654  	case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func,
   655  		reflect.Slice, reflect.Map, reflect.Invalid:
   656  		return "nil"
   657  	case reflect.Bool:
   658  		return "false"
   659  	case reflect.String:
   660  		return `""`
   661  	case reflect.Struct, reflect.Array:
   662  		return x.genTypeName(t) + "{}"
   663  	default: // all numbers
   664  		return "0"
   665  	}
   666  }
   667  
   668  func (x *genRunner) genMethodNameT(t reflect.Type) (s string) {
   669  	return genMethodNameT(t, x.tc)
   670  }
   671  
   672  func (x *genRunner) tryGenIsZero(t reflect.Type) (done bool) {
   673  	if t.Kind() != reflect.Struct || t.Implements(isCodecEmptyerTyp) {
   674  		return
   675  	}
   676  
   677  	rtid := rt2id(t)
   678  
   679  	if _, ok := x.tz[rtid]; ok {
   680  		delete(x.ty, t)
   681  		return
   682  	}
   683  
   684  	x.tz[rtid] = true
   685  	delete(x.ty, t)
   686  
   687  	ti := x.ti.get(rtid, t)
   688  	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
   689  	varname := genTopLevelVarName
   690  
   691  	x.linef("func (%s *%s) IsCodecEmpty() bool {", varname, x.genTypeName(t))
   692  
   693  	anonSeen := make(map[reflect.Type]bool)
   694  	var omitline genBuf
   695  	for _, si := range tisfi {
   696  		if si.path.parent != nil {
   697  			root := si.path.root()
   698  			if anonSeen[root.typ] {
   699  				continue
   700  			}
   701  			anonSeen[root.typ] = true
   702  		}
   703  		t2 := genOmitEmptyLinePreChecks(varname, t, si, &omitline, true)
   704  		// if Ptr, we already checked if nil above
   705  		if t2.Type.Kind() != reflect.Ptr {
   706  			x.doEncOmitEmptyLine(t2, varname, &omitline)
   707  			omitline.s(" || ")
   708  		}
   709  	}
   710  	omitline.s(" false")
   711  	x.linef("return !(%s)", omitline.v())
   712  
   713  	x.line("}")
   714  	x.line("")
   715  	return true
   716  }
   717  
   718  func (x *genRunner) selfer(encode bool) {
   719  	t := x.tc
   720  	// ti := x.ti.get(rt2id(t), t)
   721  	t0 := t
   722  	// always make decode use a pointer receiver,
   723  	// and structs/arrays always use a ptr receiver (encode|decode)
   724  	isptr := !encode || t.Kind() == reflect.Array || (t.Kind() == reflect.Struct && t != timeTyp)
   725  	x.varsfxreset()
   726  
   727  	fnSigPfx := "func (" + genTopLevelVarName + " "
   728  	if isptr {
   729  		fnSigPfx += "*"
   730  	}
   731  	fnSigPfx += x.genTypeName(t)
   732  	x.out(fnSigPfx)
   733  
   734  	if isptr {
   735  		t = reflect.PtrTo(t)
   736  	}
   737  	if encode {
   738  		x.line(") CodecEncodeSelf(e *" + x.cpfx + "Encoder) {")
   739  		x.genRequiredMethodVars(true)
   740  		if t0.Kind() == reflect.Struct {
   741  			x.linef("if z.EncBasicHandle().CheckCircularRef { z.EncEncode(%s); return }", genTopLevelVarName)
   742  		}
   743  		x.encVar(genTopLevelVarName, t)
   744  	} else {
   745  		x.line(") CodecDecodeSelf(d *" + x.cpfx + "Decoder) {")
   746  		x.genRequiredMethodVars(false)
   747  		// do not use decVar, as there is no need to check TryDecodeAsNil
   748  		// or way to elegantly handle that, and also setting it to a
   749  		// non-nil value doesn't affect the pointer passed.
   750  		// x.decVar(genTopLevelVarName, t, false)
   751  		x.dec(genTopLevelVarName, t0, true)
   752  	}
   753  	x.line("}")
   754  	x.line("")
   755  
   756  	if encode || t0.Kind() != reflect.Struct {
   757  		return
   758  	}
   759  
   760  	// write is containerMap
   761  	x.out(fnSigPfx)
   762  	x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {")
   763  	x.genRequiredMethodVars(false)
   764  	x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0)
   765  	x.line("}")
   766  	x.line("")
   767  
   768  	// write containerArray
   769  	x.out(fnSigPfx)
   770  	x.line(") codecDecodeSelfFromArray(l int, d *" + x.cpfx + "Decoder) {")
   771  	x.genRequiredMethodVars(false)
   772  	x.decStructArray(genTopLevelVarName, "l", "return", rt2id(t0), t0)
   773  	x.line("}")
   774  	x.line("")
   775  
   776  }
   777  
   778  // used for chan, array, slice, map
   779  func (x *genRunner) xtraSM(varname string, t reflect.Type, ti *typeInfo, encode, isptr bool) {
   780  	var ptrPfx, addrPfx string
   781  	if isptr {
   782  		ptrPfx = "*"
   783  	} else {
   784  		addrPfx = "&"
   785  	}
   786  	if encode {
   787  		x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), ptrPfx, x.genTypeName(t), varname)
   788  	} else {
   789  		x.linef("h.dec%s((*%s)(%s%s), d)", x.genMethodNameT(t), x.genTypeName(t), addrPfx, varname)
   790  	}
   791  	x.registerXtraT(t, ti)
   792  }
   793  
   794  func (x *genRunner) registerXtraT(t reflect.Type, ti *typeInfo) {
   795  	// recursively register the types
   796  	tk := t.Kind()
   797  	if tk == reflect.Ptr {
   798  		x.registerXtraT(t.Elem(), nil)
   799  		return
   800  	}
   801  	if _, ok := x.tm[t]; ok {
   802  		return
   803  	}
   804  
   805  	switch tk {
   806  	case reflect.Chan, reflect.Slice, reflect.Array, reflect.Map:
   807  	default:
   808  		return
   809  	}
   810  	// only register the type if it will not default to a fast-path
   811  	if ti == nil {
   812  		ti = x.ti.get(rt2id(t), t)
   813  	}
   814  	if _, rtidu := genFastpathUnderlying(t, ti.rtid, ti); fastpathAvIndex(rtidu) != -1 {
   815  		return
   816  	}
   817  	x.tm[t] = struct{}{}
   818  	x.ts = append(x.ts, t)
   819  	// check if this refers to any xtra types eg. a slice of array: add the array
   820  	x.registerXtraT(t.Elem(), nil)
   821  	if tk == reflect.Map {
   822  		x.registerXtraT(t.Key(), nil)
   823  	}
   824  }
   825  
   826  // encVar will encode a variable.
   827  // The parameter, t, is the reflect.Type of the variable itself
   828  func (x *genRunner) encVar(varname string, t reflect.Type) {
   829  	var checkNil bool
   830  	// case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan:
   831  	// do not include checkNil for slice and maps, as we already checkNil below it
   832  	switch t.Kind() {
   833  	case reflect.Ptr, reflect.Interface, reflect.Chan:
   834  		checkNil = true
   835  	}
   836  	x.encVarChkNil(varname, t, checkNil)
   837  }
   838  
   839  func (x *genRunner) encVarChkNil(varname string, t reflect.Type, checkNil bool) {
   840  	if checkNil {
   841  		x.linef("if %s == nil { r.EncodeNil() } else {", varname)
   842  	}
   843  
   844  	switch t.Kind() {
   845  	case reflect.Ptr:
   846  		telem := t.Elem()
   847  		tek := telem.Kind()
   848  		if tek == reflect.Array || (tek == reflect.Struct && telem != timeTyp) {
   849  			x.enc(varname, genNonPtr(t), true)
   850  			break
   851  		}
   852  		i := x.varsfx()
   853  		x.line(genTempVarPfx + i + " := *" + varname)
   854  		x.enc(genTempVarPfx+i, genNonPtr(t), false)
   855  	case reflect.Struct, reflect.Array:
   856  		if t == timeTyp {
   857  			x.enc(varname, t, false)
   858  			break
   859  		}
   860  		i := x.varsfx()
   861  		x.line(genTempVarPfx + i + " := &" + varname)
   862  		x.enc(genTempVarPfx+i, t, true)
   863  	default:
   864  		x.enc(varname, t, false)
   865  	}
   866  
   867  	if checkNil {
   868  		x.line("}")
   869  	}
   870  }
   871  
   872  // enc will encode a variable (varname) of type t, where t represents T.
   873  // if t is !time.Time and t is of kind reflect.Struct or reflect.Array, varname is of type *T
   874  // (to prevent copying),
   875  // else t is of type T
   876  func (x *genRunner) enc(varname string, t reflect.Type, isptr bool) {
   877  	rtid := rt2id(t)
   878  	ti2 := x.ti.get(rtid, t)
   879  	// We call CodecEncodeSelf if one of the following are honored:
   880  	//   - the type already implements Selfer, call that
   881  	//   - the type has a Selfer implementation just created, use that
   882  	//   - the type is in the list of the ones we will generate for, but it is not currently being generated
   883  
   884  	mi := x.varsfx()
   885  	// tptr := reflect.PtrTo(t)
   886  	// tk := t.Kind()
   887  
   888  	// check if
   889  	//   - type is time.Time, RawExt, Raw
   890  	//   - the type implements (Text|JSON|Binary)(Unm|M)arshal
   891  
   892  	var hasIf genIfClause
   893  	defer hasIf.end(x) // end if block (if necessary)
   894  
   895  	var ptrPfx, addrPfx string
   896  	if isptr {
   897  		ptrPfx = "*"
   898  	} else {
   899  		addrPfx = "&"
   900  	}
   901  
   902  	if t == timeTyp {
   903  		x.linef("%s z.EncBasicHandle().TimeBuiltin() { r.EncodeTime(%s%s)", hasIf.c(false), ptrPfx, varname)
   904  		// return
   905  	}
   906  	if t == rawTyp {
   907  		x.linef("%s z.EncRaw(%s%s)", hasIf.c(true), ptrPfx, varname)
   908  		return
   909  	}
   910  	if t == rawExtTyp {
   911  		x.linef("%s r.EncodeRawExt(%s%s)", hasIf.c(true), addrPfx, varname)
   912  		return
   913  	}
   914  	// only check for extensions if extensions are configured,
   915  	// and the type is named, and has a packagePath,
   916  	// and this is not the CodecEncodeSelf or CodecDecodeSelf method (i.e. it is not a Selfer)
   917  	if !x.nx && varname != genTopLevelVarName && t != genStringDecAsBytesTyp &&
   918  		t != genStringDecZCTyp && genImportPath(t) != "" && t.Name() != "" {
   919  		yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi)
   920  		x.linef("%s %s := z.Extension(%s); %s != nil { z.EncExtension(%s, %s) ",
   921  			hasIf.c(false), yy, varname, yy, varname, yy)
   922  	}
   923  
   924  	if x.checkForSelfer(t, varname) {
   925  		if ti2.flagSelfer {
   926  			x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
   927  			return
   928  		}
   929  		if ti2.flagSelferPtr {
   930  			if isptr {
   931  				x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
   932  			} else {
   933  				x.linef("%s %ssf%s := &%s", hasIf.c(true), genTempVarPfx, mi, varname)
   934  				x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi)
   935  			}
   936  			return
   937  		}
   938  
   939  		if _, ok := x.te[rtid]; ok {
   940  			x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
   941  			return
   942  		}
   943  	}
   944  
   945  	inlist := false
   946  	for _, t0 := range x.t {
   947  		if t == t0 {
   948  			inlist = true
   949  			if x.checkForSelfer(t, varname) {
   950  				x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
   951  				return
   952  			}
   953  			break
   954  		}
   955  	}
   956  
   957  	var rtidAdded bool
   958  	if t == x.tc {
   959  		x.te[rtid] = true
   960  		rtidAdded = true
   961  	}
   962  
   963  	if ti2.flagBinaryMarshaler {
   964  		x.linef("%s z.EncBinary() { z.EncBinaryMarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
   965  	} else if ti2.flagBinaryMarshalerPtr {
   966  		x.linef("%s z.EncBinary() { z.EncBinaryMarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
   967  	}
   968  
   969  	if ti2.flagJsonMarshaler {
   970  		x.linef("%s !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
   971  	} else if ti2.flagJsonMarshalerPtr {
   972  		x.linef("%s !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
   973  	} else if ti2.flagTextMarshaler {
   974  		x.linef("%s !z.EncBinary() { z.EncTextMarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
   975  	} else if ti2.flagTextMarshalerPtr {
   976  		x.linef("%s !z.EncBinary() { z.EncTextMarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
   977  	}
   978  
   979  	x.lineIf(hasIf.c(true))
   980  
   981  	switch t.Kind() {
   982  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   983  		x.line("r.EncodeInt(int64(" + varname + "))")
   984  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   985  		x.line("r.EncodeUint(uint64(" + varname + "))")
   986  	case reflect.Float32:
   987  		x.line("r.EncodeFloat32(float32(" + varname + "))")
   988  	case reflect.Float64:
   989  		x.line("r.EncodeFloat64(float64(" + varname + "))")
   990  	case reflect.Complex64:
   991  		x.linef("z.EncEncodeComplex64(complex64(%s))", varname)
   992  	case reflect.Complex128:
   993  		x.linef("z.EncEncodeComplex128(complex128(%s))", varname)
   994  	case reflect.Bool:
   995  		x.line("r.EncodeBool(bool(" + varname + "))")
   996  	case reflect.String:
   997  		x.linef("r.EncodeString(string(%s))", varname)
   998  	case reflect.Chan:
   999  		x.xtraSM(varname, t, ti2, true, false)
  1000  		// x.encListFallback(varname, rtid, t)
  1001  	case reflect.Array:
  1002  		_, rtidu := genFastpathUnderlying(t, rtid, ti2)
  1003  		if fastpathAvIndex(rtidu) != -1 {
  1004  			g := x.newFastpathGenV(ti2.key)
  1005  			x.linef("z.F.%sV((%s)(%s[:]), e)", g.MethodNamePfx("Enc", false), x.genTypeName(ti2.key), varname)
  1006  		} else {
  1007  			x.xtraSM(varname, t, ti2, true, true)
  1008  		}
  1009  	case reflect.Slice:
  1010  		// if nil, call dedicated function
  1011  		// if a []byte, call dedicated function
  1012  		// if a known fastpath slice, call dedicated function
  1013  		// else write encode function in-line.
  1014  		// - if elements are primitives or Selfers, call dedicated function on each member.
  1015  		// - else call Encoder.encode(XXX) on it.
  1016  
  1017  		x.linef("if %s == nil { r.EncodeNil() } else {", varname)
  1018  		if rtid == uint8SliceTypId {
  1019  			x.line("r.EncodeStringBytesRaw([]byte(" + varname + "))")
  1020  		} else {
  1021  			tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
  1022  			if fastpathAvIndex(rtidu) != -1 {
  1023  				g := x.newFastpathGenV(tu)
  1024  				if rtid == rtidu {
  1025  					x.linef("z.F.%sV(%s, e)", g.MethodNamePfx("Enc", false), varname)
  1026  				} else {
  1027  					x.linef("z.F.%sV((%s)(%s), e)", g.MethodNamePfx("Enc", false), x.genTypeName(tu), varname)
  1028  				}
  1029  			} else {
  1030  				x.xtraSM(varname, t, ti2, true, false)
  1031  			}
  1032  		}
  1033  		x.linef("} // end block: if %s slice == nil", varname)
  1034  	case reflect.Map:
  1035  		// if nil, call dedicated function
  1036  		// if a known fastpath map, call dedicated function
  1037  		// else write encode function in-line.
  1038  		// - if elements are primitives or Selfers, call dedicated function on each member.
  1039  		// - else call Encoder.encode(XXX) on it.
  1040  		x.linef("if %s == nil { r.EncodeNil() } else {", varname)
  1041  		tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
  1042  		if fastpathAvIndex(rtidu) != -1 {
  1043  			g := x.newFastpathGenV(tu)
  1044  			if rtid == rtidu {
  1045  				x.linef("z.F.%sV(%s, e)", g.MethodNamePfx("Enc", false), varname)
  1046  			} else {
  1047  				x.linef("z.F.%sV((%s)(%s), e)", g.MethodNamePfx("Enc", false), x.genTypeName(tu), varname)
  1048  			}
  1049  		} else {
  1050  			x.xtraSM(varname, t, ti2, true, false)
  1051  		}
  1052  		x.linef("} // end block: if %s map == nil", varname)
  1053  	case reflect.Struct:
  1054  		if !inlist {
  1055  			delete(x.te, rtid)
  1056  			x.line("z.EncFallback(" + varname + ")")
  1057  			break
  1058  		}
  1059  		x.encStruct(varname, rtid, t)
  1060  	default:
  1061  		if rtidAdded {
  1062  			delete(x.te, rtid)
  1063  		}
  1064  		x.line("z.EncFallback(" + varname + ")")
  1065  	}
  1066  }
  1067  
  1068  func (x *genRunner) encZero(t reflect.Type) {
  1069  	switch t.Kind() {
  1070  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  1071  		x.line("r.EncodeInt(0)")
  1072  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  1073  		x.line("r.EncodeUint(0)")
  1074  	case reflect.Float32:
  1075  		x.line("r.EncodeFloat32(0)")
  1076  	case reflect.Float64:
  1077  		x.line("r.EncodeFloat64(0)")
  1078  	case reflect.Complex64:
  1079  		x.line("z.EncEncodeComplex64(0)")
  1080  	case reflect.Complex128:
  1081  		x.line("z.EncEncodeComplex128(0)")
  1082  	case reflect.Bool:
  1083  		x.line("r.EncodeBool(false)")
  1084  	case reflect.String:
  1085  		x.linef(`r.EncodeString("")`)
  1086  	default:
  1087  		x.line("r.EncodeNil()")
  1088  	}
  1089  }
  1090  
  1091  func genOmitEmptyLinePreChecks(varname string, t reflect.Type, si *structFieldInfo, omitline *genBuf, oneLevel bool) (t2 reflect.StructField) {
  1092  	// xdebug2f("calling genOmitEmptyLinePreChecks on: %v", t)
  1093  	t2typ := t
  1094  	varname3 := varname
  1095  	// go through the loop, record the t2 field explicitly,
  1096  	// and gather the omit line if embedded in pointers.
  1097  	fullpath := si.path.fullpath()
  1098  	for i, path := range fullpath {
  1099  		for t2typ.Kind() == reflect.Ptr {
  1100  			t2typ = t2typ.Elem()
  1101  		}
  1102  		t2 = t2typ.Field(int(path.index))
  1103  		t2typ = t2.Type
  1104  		varname3 = varname3 + "." + t2.Name
  1105  		// do not include actual field in the omit line.
  1106  		// that is done subsequently (right after - below).
  1107  		if i+1 < len(fullpath) && t2typ.Kind() == reflect.Ptr {
  1108  			omitline.s(varname3).s(" != nil && ")
  1109  		}
  1110  		if oneLevel {
  1111  			break
  1112  		}
  1113  	}
  1114  	return
  1115  }
  1116  
  1117  func (x *genRunner) doEncOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) {
  1118  	x.f = 0
  1119  	x.encOmitEmptyLine(t2, varname, buf)
  1120  }
  1121  
  1122  func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) {
  1123  	// xdebugf("calling encOmitEmptyLine on: %v", t2.Type)
  1124  	// smartly check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc.
  1125  	// also, for maps/slices, check if len ! 0 (not if == zero value)
  1126  	varname2 := varname + "." + t2.Name
  1127  	switch t2.Type.Kind() {
  1128  	case reflect.Struct:
  1129  		rtid2 := rt2id(t2.Type)
  1130  		ti2 := x.ti.get(rtid2, t2.Type)
  1131  		// xdebugf(">>>> structfield: omitempty: type: %s, field: %s\n", t2.Type.Name(), t2.Name)
  1132  		if ti2.rtid == timeTypId {
  1133  			buf.s("!(").s(varname2).s(".IsZero())")
  1134  			break
  1135  		}
  1136  		if ti2.flagIsZeroerPtr || ti2.flagIsZeroer {
  1137  			buf.s("!(").s(varname2).s(".IsZero())")
  1138  			break
  1139  		}
  1140  		if t2.Type.Implements(isCodecEmptyerTyp) {
  1141  			buf.s("!(").s(varname2).s(".IsCodecEmpty())")
  1142  			break
  1143  		}
  1144  		_, ok := x.tz[rtid2]
  1145  		if ok {
  1146  			buf.s("!(").s(varname2).s(".IsCodecEmpty())")
  1147  			break
  1148  		}
  1149  		// if we *should* create a IsCodecEmpty for it, but haven't yet, add it here
  1150  		// _, ok = x.ty[rtid2]
  1151  		if genImportPath(t2.Type) == x.bp {
  1152  			x.ty[t2.Type] = struct{}{}
  1153  			buf.s("!(").s(varname2).s(".IsCodecEmpty())")
  1154  			break
  1155  		}
  1156  		if ti2.flagComparable {
  1157  			buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
  1158  			break
  1159  		}
  1160  		// buf.s("(")
  1161  		buf.s(x.sayFalse()) // buf.s("false")
  1162  		var wrote bool
  1163  		for i, n := 0, t2.Type.NumField(); i < n; i++ {
  1164  			f := t2.Type.Field(i)
  1165  			if f.PkgPath != "" { // unexported
  1166  				continue
  1167  			}
  1168  			buf.s(" || ")
  1169  			x.encOmitEmptyLine(f, varname2, buf)
  1170  			wrote = true
  1171  		}
  1172  		if !wrote {
  1173  			buf.s(" || ").s(x.sayTrue())
  1174  		}
  1175  		//buf.s(")")
  1176  	case reflect.Bool:
  1177  		buf.s("bool(").s(varname2).s(")")
  1178  	case reflect.Map, reflect.Slice, reflect.Chan:
  1179  		buf.s("len(").s(varname2).s(") != 0")
  1180  	case reflect.Array:
  1181  		tlen := t2.Type.Len()
  1182  		if tlen == 0 {
  1183  			buf.s(x.sayFalse())
  1184  		} else if t2.Type.Comparable() {
  1185  			buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
  1186  		} else { // then we cannot even compare the individual values
  1187  			// TODO use playground to check if you can compare to a
  1188  			// zero value of an array, even if array not comparable.
  1189  			buf.s(x.sayTrue())
  1190  		}
  1191  	default:
  1192  		buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
  1193  	}
  1194  }
  1195  
  1196  func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
  1197  	// Use knowledge from structfieldinfo (mbs, encodable fields. Ignore omitempty. )
  1198  	// replicate code in kStruct i.e. for each field, deref type to non-pointer, and call x.enc on it
  1199  
  1200  	// if t === type currently running selfer on, do for all
  1201  	ti := x.ti.get(rtid, t)
  1202  	i := x.varsfx()
  1203  	// sepVarname := genTempVarPfx + "sep" + i
  1204  	numfieldsvar := genTempVarPfx + "q" + i
  1205  	ti2arrayvar := genTempVarPfx + "r" + i
  1206  	struct2arrvar := genTempVarPfx + "2arr" + i
  1207  
  1208  	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
  1209  
  1210  	type genFQN struct {
  1211  		i       string
  1212  		fqname  string
  1213  		nilLine genBuf
  1214  		nilVar  string
  1215  		canNil  bool
  1216  		sf      reflect.StructField
  1217  	}
  1218  
  1219  	genFQNs := make([]genFQN, len(tisfi))
  1220  	si2Pos := make(map[*structFieldInfo]int) // stores position in sorted structFieldInfos
  1221  
  1222  	for j, si := range tisfi {
  1223  		si2Pos[si] = j
  1224  		q := &genFQNs[j]
  1225  		q.i = x.varsfx()
  1226  		q.nilVar = genTempVarPfx + "n" + q.i
  1227  		q.canNil = false
  1228  		q.fqname = varname
  1229  		{
  1230  			t2typ := t
  1231  			fullpath := si.path.fullpath()
  1232  			for _, path := range fullpath {
  1233  				for t2typ.Kind() == reflect.Ptr {
  1234  					t2typ = t2typ.Elem()
  1235  				}
  1236  				q.sf = t2typ.Field(int(path.index))
  1237  				t2typ = q.sf.Type
  1238  				q.fqname += "." + q.sf.Name
  1239  				if t2typ.Kind() == reflect.Ptr {
  1240  					if !q.canNil {
  1241  						q.nilLine.f("%s == nil", q.fqname)
  1242  						q.canNil = true
  1243  					} else {
  1244  						q.nilLine.f(" || %s == nil", q.fqname)
  1245  					}
  1246  				}
  1247  			}
  1248  		}
  1249  	}
  1250  
  1251  	// x.line(sepVarname + " := !z.EncBinary()")
  1252  	x.linef("%s := z.EncBasicHandle().StructToArray", struct2arrvar)
  1253  	// x.linef("_, _ = %s, %s", sepVarname, struct2arrvar)
  1254  	x.linef("_ = %s", struct2arrvar)
  1255  	x.linef("const %s bool = %v // struct tag has 'toArray'", ti2arrayvar, ti.toArray)
  1256  
  1257  	for j := range genFQNs {
  1258  		q := &genFQNs[j]
  1259  		if q.canNil {
  1260  			x.linef("var %s bool = %s", q.nilVar, q.nilLine.v())
  1261  		}
  1262  	}
  1263  
  1264  	// var nn int
  1265  	// due to omitEmpty, we need to calculate the
  1266  	// number of non-empty things we write out first.
  1267  	// This is required as we need to pre-determine the size of the container,
  1268  	// to support length-prefixing.
  1269  	omitEmptySometimes := x.omitEmptyWhen == nil
  1270  	omitEmptyAlways := (x.omitEmptyWhen != nil && *(x.omitEmptyWhen))
  1271  	// omitEmptyNever := (x.omitEmptyWhen != nil && !*(x.omitEmptyWhen))
  1272  
  1273  	toArraySometimes := x.toArrayWhen == nil
  1274  	toArrayAlways := (x.toArrayWhen != nil && *(x.toArrayWhen))
  1275  	toArrayNever := (x.toArrayWhen != nil && !(*(x.toArrayWhen)))
  1276  
  1277  	if (omitEmptySometimes && ti.anyOmitEmpty) || omitEmptyAlways {
  1278  		x.linef("var %s = [%v]bool{ // should field at this index be written?", numfieldsvar, len(tisfi))
  1279  
  1280  		for _, si := range tisfi {
  1281  			if omitEmptySometimes && !si.path.omitEmpty {
  1282  				x.linef("true, // %s", si.encName) // si.fieldName)
  1283  				continue
  1284  			}
  1285  			var omitline genBuf
  1286  			t2 := genOmitEmptyLinePreChecks(varname, t, si, &omitline, false)
  1287  			x.doEncOmitEmptyLine(t2, varname, &omitline)
  1288  			x.linef("%s, // %s", omitline.v(), si.encName) // si.fieldName)
  1289  		}
  1290  		x.line("}")
  1291  		x.linef("_ = %s", numfieldsvar)
  1292  	}
  1293  
  1294  	if toArraySometimes {
  1295  		x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray
  1296  	}
  1297  	if toArraySometimes || toArrayAlways {
  1298  		x.linef("z.EncWriteArrayStart(%d)", len(tisfi))
  1299  
  1300  		for j, si := range tisfi {
  1301  			doOmitEmptyCheck := (omitEmptySometimes && si.path.omitEmpty) || omitEmptyAlways
  1302  			q := &genFQNs[j]
  1303  			// if the type of the field is a Selfer, or one of the ones
  1304  			if q.canNil {
  1305  				x.linef("if %s { z.EncWriteArrayElem(); r.EncodeNil() } else { ", q.nilVar)
  1306  			}
  1307  			x.linef("z.EncWriteArrayElem()")
  1308  			if doOmitEmptyCheck {
  1309  				x.linef("if %s[%v] {", numfieldsvar, j)
  1310  			}
  1311  			x.encVarChkNil(q.fqname, q.sf.Type, false)
  1312  			if doOmitEmptyCheck {
  1313  				x.linef("} else {")
  1314  				x.encZero(q.sf.Type)
  1315  				x.linef("}")
  1316  			}
  1317  			if q.canNil {
  1318  				x.line("}")
  1319  			}
  1320  		}
  1321  
  1322  		x.line("z.EncWriteArrayEnd()")
  1323  	}
  1324  	if toArraySometimes {
  1325  		x.linef("} else {") // if not ti.toArray
  1326  	}
  1327  	if toArraySometimes || toArrayNever {
  1328  		if (omitEmptySometimes && ti.anyOmitEmpty) || omitEmptyAlways {
  1329  			x.linef("var %snn%s int", genTempVarPfx, i)
  1330  			x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i)
  1331  			x.linef("z.EncWriteMapStart(%snn%s)", genTempVarPfx, i)
  1332  			x.linef("%snn%s = %v", genTempVarPfx, i, 0)
  1333  		} else {
  1334  			x.linef("z.EncWriteMapStart(%d)", len(tisfi))
  1335  		}
  1336  
  1337  		fn := func(tisfi []*structFieldInfo) {
  1338  			// tisfi here may be source or sorted, so use the src position stored elsewhere
  1339  			for _, si := range tisfi {
  1340  				pos := si2Pos[si]
  1341  				q := &genFQNs[pos]
  1342  				doOmitEmptyCheck := (omitEmptySometimes && si.path.omitEmpty) || omitEmptyAlways
  1343  				if doOmitEmptyCheck {
  1344  					x.linef("if %s[%v] {", numfieldsvar, pos)
  1345  				}
  1346  				x.linef("z.EncWriteMapElemKey()")
  1347  
  1348  				// emulate EncStructFieldKey
  1349  				switch ti.keyType {
  1350  				case valueTypeInt:
  1351  					x.linef("r.EncodeInt(z.M.Int(strconv.ParseInt(`%s`, 10, 64)))", si.encName)
  1352  				case valueTypeUint:
  1353  					x.linef("r.EncodeUint(z.M.Uint(strconv.ParseUint(`%s`, 10, 64)))", si.encName)
  1354  				case valueTypeFloat:
  1355  					x.linef("r.EncodeFloat64(z.M.Float(strconv.ParseFloat(`%s`, 64)))", si.encName)
  1356  				default: // string
  1357  					if x.jsonOnlyWhen == nil {
  1358  						if si.path.encNameAsciiAlphaNum {
  1359  							x.linef(`if z.IsJSONHandle() { z.EncWr().WriteStr("\"%s\"") } else { `, si.encName)
  1360  						}
  1361  						x.linef("r.EncodeString(`%s`)", si.encName)
  1362  						if si.path.encNameAsciiAlphaNum {
  1363  							x.linef("}")
  1364  						}
  1365  					} else if *(x.jsonOnlyWhen) {
  1366  						if si.path.encNameAsciiAlphaNum {
  1367  							x.linef(`z.EncWr().WriteStr("\"%s\"")`, si.encName)
  1368  						} else {
  1369  							x.linef("r.EncodeString(`%s`)", si.encName)
  1370  						}
  1371  					} else {
  1372  						x.linef("r.EncodeString(`%s`)", si.encName)
  1373  					}
  1374  				}
  1375  				x.line("z.EncWriteMapElemValue()")
  1376  				if q.canNil {
  1377  					x.line("if " + q.nilVar + " { r.EncodeNil() } else { ")
  1378  					x.encVarChkNil(q.fqname, q.sf.Type, false)
  1379  					x.line("}")
  1380  				} else {
  1381  					x.encVarChkNil(q.fqname, q.sf.Type, false)
  1382  				}
  1383  				if doOmitEmptyCheck {
  1384  					x.line("}")
  1385  				}
  1386  			}
  1387  		}
  1388  
  1389  		if genStructCanonical {
  1390  			x.linef("if z.EncBasicHandle().Canonical {") // if Canonical block
  1391  			fn(ti.sfi.sorted())
  1392  			x.linef("} else {") // else !Canonical block
  1393  			fn(ti.sfi.source())
  1394  			x.linef("}") // end if Canonical block
  1395  		} else {
  1396  			fn(tisfi)
  1397  		}
  1398  
  1399  		x.line("z.EncWriteMapEnd()")
  1400  	}
  1401  	if toArraySometimes {
  1402  		x.linef("} ") // end if/else ti.toArray
  1403  	}
  1404  }
  1405  
  1406  func (x *genRunner) encListFallback(varname string, t reflect.Type) {
  1407  	x.linef("if %s == nil { r.EncodeNil(); return }", varname)
  1408  	elemBytes := t.Elem().Kind() == reflect.Uint8
  1409  	if t.AssignableTo(uint8SliceTyp) {
  1410  		x.linef("r.EncodeStringBytesRaw([]byte(%s))", varname)
  1411  		return
  1412  	}
  1413  	if t.Kind() == reflect.Array && elemBytes {
  1414  		x.linef("r.EncodeStringBytesRaw(((*[%d]byte)(%s))[:])", t.Len(), varname)
  1415  		return
  1416  	}
  1417  	i := x.varsfx()
  1418  	if t.Kind() == reflect.Chan {
  1419  		type ts struct {
  1420  			Label, Chan, Slice, Sfx string
  1421  		}
  1422  		tm, err := template.New("").Parse(genEncChanTmpl)
  1423  		genCheckErr(err)
  1424  		x.linef("if %s == nil { r.EncodeNil() } else { ", varname)
  1425  		x.linef("var sch%s []%s", i, x.genTypeName(t.Elem()))
  1426  		err = tm.Execute(x.w, &ts{"Lsch" + i, varname, "sch" + i, i})
  1427  		genCheckErr(err)
  1428  		if elemBytes {
  1429  			x.linef("r.EncodeStringBytesRaw([]byte(%s))", "sch"+i)
  1430  			x.line("}")
  1431  			return
  1432  		}
  1433  		varname = "sch" + i
  1434  	}
  1435  
  1436  	x.line("z.EncWriteArrayStart(len(" + varname + "))")
  1437  
  1438  	// x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname)
  1439  	// x.linef("z.EncWriteArrayElem()")
  1440  	// x.encVar(genTempVarPfx+"v"+i, t.Elem())
  1441  	// x.line("}")
  1442  
  1443  	x.linef("for %sv%s := range %s {", genTempVarPfx, i, varname)
  1444  	x.linef("z.EncWriteArrayElem()")
  1445  	x.encVar(fmt.Sprintf("%s[%sv%s]", varname, genTempVarPfx, i), t.Elem())
  1446  	x.line("}")
  1447  
  1448  	x.line("z.EncWriteArrayEnd()")
  1449  	if t.Kind() == reflect.Chan {
  1450  		x.line("}")
  1451  	}
  1452  }
  1453  
  1454  func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
  1455  	x.linef("if %s == nil { r.EncodeNil()", varname)
  1456  	x.line("} else if z.EncBasicHandle().Canonical {")
  1457  
  1458  	// Solve for easy case accomodated by sort package without reflection i.e.
  1459  	// map keys of type: float, int, string (pre-defined/builtin types).
  1460  	//
  1461  	// To do this, we will get the keys into an array of uint64|float64|string,
  1462  	// sort them, then write them out, and grab the value and encode it appropriately
  1463  	tkey := t.Key()
  1464  	tkind := tkey.Kind()
  1465  	// tkeybase := tkey
  1466  	// for tkeybase.Kind() == reflect.Ptr {
  1467  	// 	tkeybase = tkeybase.Elem()
  1468  	// }
  1469  	// tikey := x.ti.get(rt2id(tkeybase), tkeybase)
  1470  
  1471  	// pre-defined types have a name and no pkgpath and appropriate kind
  1472  	predeclared := tkey.PkgPath() == "" && tkey.Name() != ""
  1473  
  1474  	canonSortKind := reflect.Invalid
  1475  	switch tkind {
  1476  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  1477  		canonSortKind = reflect.Int64
  1478  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  1479  		canonSortKind = reflect.Uint64
  1480  	case reflect.Float32, reflect.Float64:
  1481  		canonSortKind = reflect.Float64
  1482  	case reflect.String:
  1483  		canonSortKind = reflect.String
  1484  	}
  1485  
  1486  	var i string = x.varsfx()
  1487  
  1488  	fnCanonNumBoolStrKind := func() {
  1489  		if !predeclared {
  1490  			x.linef("var %svv%s %s", genTempVarPfx, i, x.genTypeName(tkey))
  1491  			x.linef("%sencfn%s := z.EncFnGivenAddr(&%svv%s)", genTempVarPfx, i, genTempVarPfx, i)
  1492  		}
  1493  		// get the type, get the slice type its mapped to, and complete the code
  1494  		x.linef("%ss%s := make([]%s, 0, len(%s))", genTempVarPfx, i, canonSortKind, varname)
  1495  		x.linef("for k, _ := range %s {", varname)
  1496  		x.linef("  %ss%s = append(%ss%s, %s(k))", genTempVarPfx, i, genTempVarPfx, i, canonSortKind)
  1497  		x.linef("}")
  1498  		x.linef("sort.Sort(%s%sSlice(%ss%s))", x.hn, canonSortKind, genTempVarPfx, i)
  1499  		x.linef("z.EncWriteMapStart(len(%s))", varname)
  1500  		x.linef("for _, %sv%s := range %ss%s {", genTempVarPfx, i, genTempVarPfx, i)
  1501  		x.linef("  z.EncWriteMapElemKey()")
  1502  		if predeclared {
  1503  			switch tkind {
  1504  			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
  1505  				x.linef("r.EncodeInt(int64(%sv%s))", genTempVarPfx, i)
  1506  			case reflect.Int64:
  1507  				x.linef("r.EncodeInt(%sv%s)", genTempVarPfx, i)
  1508  			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
  1509  				x.linef("r.EncodeUint(%sv%s)", genTempVarPfx, i)
  1510  			case reflect.Uint64:
  1511  				x.linef("r.EncodeUint(uint64(%sv%s))", genTempVarPfx, i)
  1512  			case reflect.Float32:
  1513  				x.linef("r.EncodeFloat32(float32(%sv%s))", genTempVarPfx, i)
  1514  			case reflect.Float64:
  1515  				x.linef("r.EncodeFloat64(%sv%s)", genTempVarPfx, i)
  1516  			case reflect.String:
  1517  				x.linef("r.EncodeString(%sv%s)", genTempVarPfx, i)
  1518  			}
  1519  		} else {
  1520  			x.linef("%svv%s = %s(%sv%s)", genTempVarPfx, i, x.genTypeName(tkey), genTempVarPfx, i)
  1521  			x.linef("z.EncEncodeNumBoolStrKindGivenAddr(&%svv%s, %sencfn%s)", genTempVarPfx, i, genTempVarPfx, i)
  1522  		}
  1523  		x.linef("  z.EncWriteMapElemValue()")
  1524  		vname := genTempVarPfx + "e" + i
  1525  		if predeclared {
  1526  			x.linef("%s := %s[%s(%sv%s)]", vname, varname, x.genTypeName(tkey), genTempVarPfx, i)
  1527  		} else {
  1528  			x.linef("%s := %s[%svv%s]", vname, varname, genTempVarPfx, i)
  1529  		}
  1530  		x.encVar(vname, t.Elem())
  1531  		x.linef("}")
  1532  
  1533  		x.line("z.EncWriteMapEnd()")
  1534  
  1535  	}
  1536  
  1537  	// if canonSortKind != reflect.Invalid && !tikey.flagMarshalInterface {
  1538  	// 	if predeclared {
  1539  	// 		fnCanonNumBoolStrKind()
  1540  	// 	} else {
  1541  	// 		// handle if an extension
  1542  	// 		x.linef("if z.Extension(%s(%s)) != nil { z.EncEncodeMapNonNil(%s) } else {",
  1543  	// 			x.genTypeName(tkey), x.genZeroValueR(tkey), varname)
  1544  	// 		fnCanonNumBoolStrKind()
  1545  	// 		x.line("}")
  1546  	// 	}
  1547  	// } else {
  1548  	// 	x.linef("z.EncEncodeMapNonNil(%s)", varname)
  1549  	// }
  1550  
  1551  	if canonSortKind != reflect.Invalid {
  1552  		fnCanonNumBoolStrKind()
  1553  	} else {
  1554  		x.linef("z.EncEncodeMapNonNil(%s)", varname)
  1555  	}
  1556  
  1557  	x.line("} else {")
  1558  
  1559  	x.linef("z.EncWriteMapStart(len(%s))", varname)
  1560  	x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
  1561  	x.linef("z.EncWriteMapElemKey()")
  1562  	x.encVar(genTempVarPfx+"k"+i, t.Key())
  1563  	x.line("z.EncWriteMapElemValue()")
  1564  	x.encVar(genTempVarPfx+"v"+i, t.Elem())
  1565  	x.line("}")
  1566  	x.line("z.EncWriteMapEnd()")
  1567  
  1568  	x.line("}")
  1569  }
  1570  
  1571  func (x *genRunner) decVarInitPtr(varname, nilvar string, t reflect.Type, si *structFieldInfo,
  1572  	newbuf, nilbuf *genBuf) (varname3 string, t2 reflect.StructField) {
  1573  	//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
  1574  	// t2 = t.FieldByIndex(si.is)
  1575  	varname3 = varname
  1576  	t2typ := t
  1577  	t2kind := t2typ.Kind()
  1578  	var nilbufed bool
  1579  	if si != nil {
  1580  		fullpath := si.path.fullpath()
  1581  		for _, path := range fullpath {
  1582  			// only one-level pointers can be seen in a type
  1583  			if t2typ.Kind() == reflect.Ptr {
  1584  				t2typ = t2typ.Elem()
  1585  			}
  1586  			t2 = t2typ.Field(int(path.index))
  1587  			t2typ = t2.Type
  1588  			varname3 = varname3 + "." + t2.Name
  1589  			t2kind = t2typ.Kind()
  1590  			if t2kind != reflect.Ptr {
  1591  				continue
  1592  			}
  1593  			if newbuf != nil {
  1594  				if len(newbuf.buf) > 0 {
  1595  					newbuf.s("\n")
  1596  				}
  1597  				newbuf.f("if %s == nil { %s = new(%s) }", varname3, varname3, x.genTypeName(t2typ.Elem()))
  1598  			}
  1599  			if nilbuf != nil {
  1600  				if !nilbufed {
  1601  					nilbuf.s("if ").s(varname3).s(" != nil")
  1602  					nilbufed = true
  1603  				} else {
  1604  					nilbuf.s(" && ").s(varname3).s(" != nil")
  1605  				}
  1606  			}
  1607  		}
  1608  	}
  1609  	if nilbuf != nil {
  1610  		if nilbufed {
  1611  			nilbuf.s(" { ").s("// remove the if-true\n")
  1612  		}
  1613  		if nilvar != "" {
  1614  			nilbuf.s(nilvar).s(" = true")
  1615  		} else if tk := t2typ.Kind(); tk == reflect.Ptr {
  1616  			if strings.IndexByte(varname3, '.') != -1 || strings.IndexByte(varname3, '[') != -1 {
  1617  				nilbuf.s(varname3).s(" = nil")
  1618  			} else {
  1619  				nilbuf.s("*").s(varname3).s(" = ").s(x.genZeroValueR(t2typ.Elem()))
  1620  			}
  1621  		} else {
  1622  			nilbuf.s(varname3).s(" = ").s(x.genZeroValueR(t2typ))
  1623  		}
  1624  		if nilbufed {
  1625  			nilbuf.s("}")
  1626  		}
  1627  	}
  1628  	return
  1629  }
  1630  
  1631  // decVar takes a variable called varname, of type t
  1632  func (x *genRunner) decVarMain(varname, rand string, t reflect.Type, checkNotNil bool) {
  1633  	// We only encode as nil if a nillable value.
  1634  	// This removes some of the wasted checks for TryDecodeAsNil.
  1635  	// We need to think about this more, to see what happens if omitempty, etc
  1636  	// cause a nil value to be stored when something is expected.
  1637  	// This could happen when decoding from a struct encoded as an array.
  1638  	// For that, decVar should be called with canNil=true, to force true as its value.
  1639  	var varname2 string
  1640  	if t.Kind() != reflect.Ptr {
  1641  		if t.PkgPath() != "" || !x.decTryAssignPrimitive(varname, t, false) {
  1642  			x.dec(varname, t, false)
  1643  		}
  1644  	} else {
  1645  		if checkNotNil {
  1646  			x.linef("if %s == nil { %s = new(%s) }", varname, varname, x.genTypeName(t.Elem()))
  1647  		}
  1648  		// Ensure we set underlying ptr to a non-nil value (so we can deref to it later).
  1649  		// There's a chance of a **T in here which is nil.
  1650  		var ptrPfx string
  1651  		for t = t.Elem(); t.Kind() == reflect.Ptr; t = t.Elem() {
  1652  			ptrPfx += "*"
  1653  			if checkNotNil {
  1654  				x.linef("if %s%s == nil { %s%s = new(%s)}", ptrPfx, varname, ptrPfx, varname, x.genTypeName(t))
  1655  			}
  1656  		}
  1657  		// Should we create temp var if a slice/map indexing? No. dec(...) can now handle it.
  1658  
  1659  		if ptrPfx == "" {
  1660  			x.dec(varname, t, true)
  1661  		} else {
  1662  			varname2 = genTempVarPfx + "z" + rand
  1663  			x.line(varname2 + " := " + ptrPfx + varname)
  1664  			x.dec(varname2, t, true)
  1665  		}
  1666  	}
  1667  }
  1668  
  1669  // decVar takes a variable called varname, of type t
  1670  func (x *genRunner) decVar(varname, nilvar string, t reflect.Type, canBeNil, checkNotNil bool) {
  1671  
  1672  	// We only encode as nil if a nillable value.
  1673  	// This removes some of the wasted checks for TryDecodeAsNil.
  1674  	// We need to think about this more, to see what happens if omitempty, etc
  1675  	// cause a nil value to be stored when something is expected.
  1676  	// This could happen when decoding from a struct encoded as an array.
  1677  	// For that, decVar should be called with canNil=true, to force true as its value.
  1678  
  1679  	i := x.varsfx()
  1680  	if t.Kind() == reflect.Ptr {
  1681  		var buf genBuf
  1682  		x.decVarInitPtr(varname, nilvar, t, nil, nil, &buf)
  1683  		x.linef("if r.TryNil() { %s } else {", buf.buf)
  1684  		x.decVarMain(varname, i, t, checkNotNil)
  1685  		x.line("} ")
  1686  	} else {
  1687  		x.decVarMain(varname, i, t, checkNotNil)
  1688  	}
  1689  }
  1690  
  1691  // dec will decode a variable (varname) of type t or ptrTo(t) if isptr==true.
  1692  func (x *genRunner) dec(varname string, t reflect.Type, isptr bool) {
  1693  	// assumptions:
  1694  	//   - the varname is to a pointer already. No need to take address of it
  1695  	//   - t is always a baseType T (not a *T, etc).
  1696  	rtid := rt2id(t)
  1697  	ti2 := x.ti.get(rtid, t)
  1698  
  1699  	// check if
  1700  	//   - type is time.Time, Raw, RawExt
  1701  	//   - the type implements (Text|JSON|Binary)(Unm|M)arshal
  1702  
  1703  	mi := x.varsfx()
  1704  
  1705  	var hasIf genIfClause
  1706  	defer hasIf.end(x)
  1707  
  1708  	var ptrPfx, addrPfx string
  1709  	if isptr {
  1710  		ptrPfx = "*"
  1711  	} else {
  1712  		addrPfx = "&"
  1713  	}
  1714  	if t == timeTyp {
  1715  		x.linef("%s z.DecBasicHandle().TimeBuiltin() { %s%v = r.DecodeTime()", hasIf.c(false), ptrPfx, varname)
  1716  		// return
  1717  	}
  1718  	if t == rawTyp {
  1719  		x.linef("%s %s%v = z.DecRaw()", hasIf.c(true), ptrPfx, varname)
  1720  		return
  1721  	}
  1722  
  1723  	if t == rawExtTyp {
  1724  		x.linef("%s r.DecodeExt(%s%v, 0, nil)", hasIf.c(true), addrPfx, varname)
  1725  		return
  1726  	}
  1727  
  1728  	// only check for extensions if extensions are configured,
  1729  	// and the type is named, and has a packagePath,
  1730  	// and this is not the CodecEncodeSelf or CodecDecodeSelf method (i.e. it is not a Selfer)
  1731  	// xdebugf("genRunner.dec: varname: %v, t: %v, genImportPath: %v, t.Name: %v", varname, t, genImportPath(t), t.Name())
  1732  	if !x.nx && varname != genTopLevelVarName && t != genStringDecAsBytesTyp &&
  1733  		t != genStringDecZCTyp && genImportPath(t) != "" && t.Name() != "" {
  1734  		// first check if extensions are configued, before doing the interface conversion
  1735  		yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi)
  1736  		x.linef("%s %s := z.Extension(%s); %s != nil { z.DecExtension(%s%s, %s) ", hasIf.c(false), yy, varname, yy, addrPfx, varname, yy)
  1737  	}
  1738  
  1739  	if x.checkForSelfer(t, varname) {
  1740  		if ti2.flagSelfer {
  1741  			x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
  1742  			return
  1743  		}
  1744  		if ti2.flagSelferPtr {
  1745  			x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
  1746  			return
  1747  		}
  1748  		if _, ok := x.td[rtid]; ok {
  1749  			x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
  1750  			return
  1751  		}
  1752  	}
  1753  
  1754  	inlist := false
  1755  	for _, t0 := range x.t {
  1756  		if t == t0 {
  1757  			inlist = true
  1758  			if x.checkForSelfer(t, varname) {
  1759  				x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
  1760  				return
  1761  			}
  1762  			break
  1763  		}
  1764  	}
  1765  
  1766  	var rtidAdded bool
  1767  	if t == x.tc {
  1768  		x.td[rtid] = true
  1769  		rtidAdded = true
  1770  	}
  1771  
  1772  	if ti2.flagBinaryUnmarshaler {
  1773  		x.linef("%s z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
  1774  	} else if ti2.flagBinaryUnmarshalerPtr {
  1775  		x.linef("%s z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
  1776  	}
  1777  	if ti2.flagJsonUnmarshaler {
  1778  		x.linef("%s !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", hasIf.c(false), ptrPfx, varname)
  1779  	} else if ti2.flagJsonUnmarshalerPtr {
  1780  		x.linef("%s !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", hasIf.c(false), addrPfx, varname)
  1781  	} else if ti2.flagTextUnmarshaler {
  1782  		x.linef("%s !z.DecBinary() { z.DecTextUnmarshal(%s%v)", hasIf.c(false), ptrPfx, varname)
  1783  	} else if ti2.flagTextUnmarshalerPtr {
  1784  		x.linef("%s !z.DecBinary() { z.DecTextUnmarshal(%s%v)", hasIf.c(false), addrPfx, varname)
  1785  	}
  1786  
  1787  	x.lineIf(hasIf.c(true))
  1788  
  1789  	if x.decTryAssignPrimitive(varname, t, isptr) {
  1790  		return
  1791  	}
  1792  
  1793  	switch t.Kind() {
  1794  	case reflect.Chan:
  1795  		x.xtraSM(varname, t, ti2, false, isptr)
  1796  	case reflect.Array:
  1797  		_, rtidu := genFastpathUnderlying(t, rtid, ti2)
  1798  		if fastpathAvIndex(rtidu) != -1 {
  1799  			g := x.newFastpathGenV(ti2.key)
  1800  			x.linef("z.F.%sN((%s)(%s[:]), d)", g.MethodNamePfx("Dec", false), x.genTypeName(ti2.key), varname)
  1801  		} else {
  1802  			x.xtraSM(varname, t, ti2, false, isptr)
  1803  		}
  1804  	case reflect.Slice:
  1805  		// if a []byte, call dedicated function
  1806  		// if a known fastpath slice, call dedicated function
  1807  		// else write encode function in-line.
  1808  		// - if elements are primitives or Selfers, call dedicated function on each member.
  1809  		// - else call Encoder.encode(XXX) on it.
  1810  
  1811  		if rtid == uint8SliceTypId {
  1812  			x.linef("%s%s = z.DecodeBytesInto(%s(%s[]byte)(%s))", ptrPfx, varname, ptrPfx, ptrPfx, varname)
  1813  		} else {
  1814  			tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
  1815  			if fastpathAvIndex(rtidu) != -1 {
  1816  				g := x.newFastpathGenV(tu)
  1817  				if rtid == rtidu {
  1818  					x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
  1819  				} else {
  1820  					x.linef("z.F.%sX((*%s)(%s%s), d)", g.MethodNamePfx("Dec", false), x.genTypeName(tu), addrPfx, varname)
  1821  				}
  1822  			} else {
  1823  				x.xtraSM(varname, t, ti2, false, isptr)
  1824  				// x.decListFallback(varname, rtid, false, t)
  1825  			}
  1826  		}
  1827  	case reflect.Map:
  1828  		// if a known fastpath map, call dedicated function
  1829  		// else write encode function in-line.
  1830  		// - if elements are primitives or Selfers, call dedicated function on each member.
  1831  		// - else call Encoder.encode(XXX) on it.
  1832  
  1833  		tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
  1834  		if fastpathAvIndex(rtidu) != -1 {
  1835  			g := x.newFastpathGenV(tu)
  1836  			if rtid == rtidu {
  1837  				x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
  1838  			} else {
  1839  				x.linef("z.F.%sX((*%s)(%s%s), d)", g.MethodNamePfx("Dec", false), x.genTypeName(tu), addrPfx, varname)
  1840  			}
  1841  		} else {
  1842  			x.xtraSM(varname, t, ti2, false, isptr)
  1843  		}
  1844  	case reflect.Struct:
  1845  		if inlist {
  1846  			// no need to create temp variable if isptr, or x.F or x[F]
  1847  			if isptr || strings.IndexByte(varname, '.') != -1 || strings.IndexByte(varname, '[') != -1 {
  1848  				x.decStruct(varname, rtid, t)
  1849  			} else {
  1850  				varname2 := genTempVarPfx + "j" + mi
  1851  				x.line(varname2 + " := &" + varname)
  1852  				x.decStruct(varname2, rtid, t)
  1853  			}
  1854  		} else {
  1855  			// delete(x.td, rtid)
  1856  			x.line("z.DecFallback(" + addrPfx + varname + ", false)")
  1857  		}
  1858  	default:
  1859  		if rtidAdded {
  1860  			delete(x.te, rtid)
  1861  		}
  1862  		x.line("z.DecFallback(" + addrPfx + varname + ", true)")
  1863  	}
  1864  }
  1865  
  1866  func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type, isptr bool) (done bool) {
  1867  	// This should only be used for exact primitives (ie un-named types).
  1868  	// Named types may be implementations of Selfer, Unmarshaler, etc.
  1869  	// They should be handled by dec(...)
  1870  
  1871  	var ptr string
  1872  	if isptr {
  1873  		ptr = "*"
  1874  	}
  1875  	switch t.Kind() {
  1876  	case reflect.Int:
  1877  		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
  1878  	case reflect.Int8:
  1879  		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 8))", ptr, varname, x.genTypeName(t))
  1880  	case reflect.Int16:
  1881  		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 16))", ptr, varname, x.genTypeName(t))
  1882  	case reflect.Int32:
  1883  		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 32))", ptr, varname, x.genTypeName(t))
  1884  	case reflect.Int64:
  1885  		x.linef("%s%s = (%s)(r.DecodeInt64())", ptr, varname, x.genTypeName(t))
  1886  
  1887  	case reflect.Uint:
  1888  		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
  1889  	case reflect.Uint8:
  1890  		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 8))", ptr, varname, x.genTypeName(t))
  1891  	case reflect.Uint16:
  1892  		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 16))", ptr, varname, x.genTypeName(t))
  1893  	case reflect.Uint32:
  1894  		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 32))", ptr, varname, x.genTypeName(t))
  1895  	case reflect.Uint64:
  1896  		x.linef("%s%s = (%s)(r.DecodeUint64())", ptr, varname, x.genTypeName(t))
  1897  	case reflect.Uintptr:
  1898  		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
  1899  
  1900  	case reflect.Float32:
  1901  		x.linef("%s%s = (%s)(z.DecDecodeFloat32())", ptr, varname, x.genTypeName(t))
  1902  	case reflect.Float64:
  1903  		x.linef("%s%s = (%s)(r.DecodeFloat64())", ptr, varname, x.genTypeName(t))
  1904  
  1905  	case reflect.Complex64:
  1906  		x.linef("%s%s = (%s)(complex(z.DecDecodeFloat32(), 0))", ptr, varname, x.genTypeName(t))
  1907  	case reflect.Complex128:
  1908  		x.linef("%s%s = (%s)(complex(r.DecodeFloat64(), 0))", ptr, varname, x.genTypeName(t))
  1909  
  1910  	case reflect.Bool:
  1911  		x.linef("%s%s = (%s)(r.DecodeBool())", ptr, varname, x.genTypeName(t))
  1912  	case reflect.String:
  1913  		if t == genStringDecAsBytesTyp {
  1914  			x.linef("%s%s = r.DecodeStringAsBytes()", ptr, varname)
  1915  		} else if t == genStringDecZCTyp {
  1916  			x.linef("%s%s = (string)(z.DecStringZC(r.DecodeStringAsBytes()))", ptr, varname)
  1917  		} else {
  1918  			x.linef("%s%s = (%s)(z.DecStringZC(r.DecodeStringAsBytes()))", ptr, varname, x.genTypeName(t))
  1919  		}
  1920  	default:
  1921  		return false
  1922  	}
  1923  	return true
  1924  }
  1925  
  1926  func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) {
  1927  	if t.AssignableTo(uint8SliceTyp) {
  1928  		x.line("*" + varname + " = z.DecodeBytesInto(*((*[]byte)(" + varname + ")))")
  1929  		return
  1930  	}
  1931  	if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
  1932  		x.linef("r.DecodeBytes( ((*[%d]byte)(%s))[:])", t.Len(), varname)
  1933  		return
  1934  	}
  1935  	type tstruc struct {
  1936  		TempVar   string
  1937  		Sfx       string
  1938  		Rand      string
  1939  		Varname   string
  1940  		CTyp      string
  1941  		Typ       string
  1942  		Immutable bool
  1943  		Size      int
  1944  	}
  1945  	telem := t.Elem()
  1946  	ts := tstruc{genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(t), x.genTypeName(telem), genIsImmutable(telem), int(telem.Size())}
  1947  
  1948  	funcs := make(template.FuncMap)
  1949  
  1950  	funcs["decLineVar"] = func(varname string) string {
  1951  		x.decVar(varname, "", telem, false, true)
  1952  		return ""
  1953  	}
  1954  	funcs["var"] = func(s string) string {
  1955  		return ts.TempVar + s + ts.Rand
  1956  	}
  1957  	funcs["xs"] = func() string {
  1958  		return ts.Sfx
  1959  	}
  1960  	funcs["zero"] = func() string {
  1961  		return x.genZeroValueR(telem)
  1962  	}
  1963  	funcs["isArray"] = func() bool {
  1964  		return t.Kind() == reflect.Array
  1965  	}
  1966  	funcs["isSlice"] = func() bool {
  1967  		return t.Kind() == reflect.Slice
  1968  	}
  1969  	funcs["isChan"] = func() bool {
  1970  		return t.Kind() == reflect.Chan
  1971  	}
  1972  	tm, err := template.New("").Funcs(funcs).Parse(genDecListTmpl)
  1973  	genCheckErr(err)
  1974  	genCheckErr(tm.Execute(x.w, &ts))
  1975  }
  1976  
  1977  func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) {
  1978  	type tstruc struct {
  1979  		TempVar string
  1980  		Sfx     string
  1981  		Rand    string
  1982  		Varname string
  1983  		KTyp    string
  1984  		Typ     string
  1985  		Size    int
  1986  	}
  1987  	telem := t.Elem()
  1988  	tkey := t.Key()
  1989  	ts := tstruc{
  1990  		genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey),
  1991  		x.genTypeName(telem), int(telem.Size() + tkey.Size()),
  1992  	}
  1993  
  1994  	funcs := make(template.FuncMap)
  1995  	funcs["decElemZero"] = func() string {
  1996  		return x.genZeroValueR(telem)
  1997  	}
  1998  	funcs["decElemKindImmutable"] = func() bool {
  1999  		return genIsImmutable(telem)
  2000  	}
  2001  	funcs["decElemKindPtr"] = func() bool {
  2002  		return telem.Kind() == reflect.Ptr
  2003  	}
  2004  	funcs["decElemKindIntf"] = func() bool {
  2005  		return telem.Kind() == reflect.Interface
  2006  	}
  2007  	funcs["decLineVarKStrBytes"] = func(varname string) string {
  2008  		x.decVar(varname, "", genStringDecAsBytesTyp, false, true)
  2009  		return ""
  2010  	}
  2011  	funcs["decLineVarKStrZC"] = func(varname string) string {
  2012  		x.decVar(varname, "", genStringDecZCTyp, false, true)
  2013  		return ""
  2014  	}
  2015  	funcs["decLineVarK"] = func(varname string) string {
  2016  		x.decVar(varname, "", tkey, false, true)
  2017  		return ""
  2018  	}
  2019  	funcs["decLineVar"] = func(varname, decodedNilVarname string) string {
  2020  		x.decVar(varname, decodedNilVarname, telem, false, true)
  2021  		return ""
  2022  	}
  2023  	funcs["var"] = func(s string) string {
  2024  		return ts.TempVar + s + ts.Rand
  2025  	}
  2026  	funcs["xs"] = func() string {
  2027  		return ts.Sfx
  2028  	}
  2029  
  2030  	tm, err := template.New("").Funcs(funcs).Parse(genDecMapTmpl)
  2031  	genCheckErr(err)
  2032  	genCheckErr(tm.Execute(x.w, &ts))
  2033  }
  2034  
  2035  func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintptr, t reflect.Type) {
  2036  	ti := x.ti.get(rtid, t)
  2037  	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
  2038  	x.line("switch string(" + kName + ") {")
  2039  	var newbuf, nilbuf genBuf
  2040  	for _, si := range tisfi {
  2041  		x.line("case \"" + si.encName + "\":")
  2042  		newbuf.reset()
  2043  		nilbuf.reset()
  2044  		varname3, t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
  2045  		if len(newbuf.buf) > 0 {
  2046  			x.linef("if r.TryNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
  2047  		}
  2048  		x.decVarMain(varname3, x.varsfx(), t2.Type, false)
  2049  		if len(newbuf.buf) > 0 {
  2050  			x.line("}")
  2051  		}
  2052  	}
  2053  	x.line("default:")
  2054  	// pass the slice here, so that the string will not escape, and maybe save allocation
  2055  	x.linef("z.DecStructFieldNotFound(-1, string(%s))", kName)
  2056  	x.linef("} // end switch %s", kName)
  2057  }
  2058  
  2059  func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type) {
  2060  	tpfx := genTempVarPfx
  2061  	ti := x.ti.get(rtid, t)
  2062  	i := x.varsfx()
  2063  	kName := tpfx + "s" + i
  2064  
  2065  	x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
  2066  	x.linef("for %sj%s := 0; z.DecContainerNext(%sj%s, %s, %shl%s); %sj%s++ {",
  2067  		tpfx, i, tpfx, i, lenvarname, tpfx, i, tpfx, i)
  2068  
  2069  	x.line("z.DecReadMapElemKey()")
  2070  
  2071  	// emulate decstructfieldkey
  2072  	switch ti.keyType {
  2073  	case valueTypeInt:
  2074  		x.linef("%s := strconv.AppendInt(z.DecScratchArrayBuffer()[:0], r.DecodeInt64(), 10)", kName)
  2075  	case valueTypeUint:
  2076  		x.linef("%s := strconv.AppendUint(z.DecScratchArrayBuffer()[:0], r.DecodeUint64(), 10)", kName)
  2077  	case valueTypeFloat:
  2078  		x.linef("%s := strconv.AppendFloat(z.DecScratchArrayBuffer()[:0], r.DecodeFloat64(), 'f', -1, 64)", kName)
  2079  	default: // string
  2080  		x.linef("%s := r.DecodeStringAsBytes()", kName)
  2081  	}
  2082  
  2083  	x.line("z.DecReadMapElemValue()")
  2084  	x.decStructMapSwitch(kName, varname, rtid, t)
  2085  
  2086  	x.line("} // end for " + tpfx + "j" + i)
  2087  }
  2088  
  2089  func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) {
  2090  	tpfx := genTempVarPfx
  2091  	i := x.varsfx()
  2092  	ti := x.ti.get(rtid, t)
  2093  	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
  2094  	x.linef("var %sj%s int", tpfx, i)
  2095  	x.linef("var %sb%s bool", tpfx, i)                        // break
  2096  	x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
  2097  	var newbuf, nilbuf genBuf
  2098  	for _, si := range tisfi {
  2099  		x.linef("%sb%s = !z.DecContainerNext(%sj%s, %s, %shl%s)", tpfx, i, tpfx, i, lenvarname, tpfx, i)
  2100  		x.linef("if %sb%s { z.DecReadArrayEnd(); %s }", tpfx, i, breakString)
  2101  		x.line("z.DecReadArrayElem()")
  2102  		newbuf.reset()
  2103  		nilbuf.reset()
  2104  		varname3, t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
  2105  		if len(newbuf.buf) > 0 {
  2106  			x.linef("if r.TryNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
  2107  		}
  2108  		x.decVarMain(varname3, x.varsfx(), t2.Type, false)
  2109  		if len(newbuf.buf) > 0 {
  2110  			x.line("}")
  2111  		}
  2112  		x.linef("%sj%s++", tpfx, i)
  2113  	}
  2114  	// read remaining values and throw away.
  2115  	x.linef("for ; z.DecContainerNext(%sj%s, %s, %shl%s); %sj%s++ {",
  2116  		tpfx, i, lenvarname, tpfx, i, tpfx, i)
  2117  	x.line("z.DecReadArrayElem()")
  2118  	x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i)
  2119  	x.line("}")
  2120  }
  2121  
  2122  func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
  2123  	// varname MUST be a ptr, or a struct field or a slice element.
  2124  	i := x.varsfx()
  2125  	x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i)
  2126  	x.linef("if %sct%s == codecSelferValueTypeNil%s {", genTempVarPfx, i, x.xs)
  2127  	x.linef("*(%s) = %s{}", varname, x.genTypeName(t))
  2128  	x.linef("} else if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs)
  2129  	x.line(genTempVarPfx + "l" + i + " := z.DecReadMapStart()")
  2130  	x.linef("if %sl%s == 0 {", genTempVarPfx, i)
  2131  
  2132  	x.line("} else { ")
  2133  	x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i)
  2134  
  2135  	x.line("}")
  2136  	x.line("z.DecReadMapEnd()")
  2137  
  2138  	// else if container is array
  2139  	x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs)
  2140  	x.line(genTempVarPfx + "l" + i + " := z.DecReadArrayStart()")
  2141  	x.linef("if %sl%s != 0 {", genTempVarPfx, i)
  2142  	x.linef("%s.codecDecodeSelfFromArray(%sl%s, d)", varname, genTempVarPfx, i)
  2143  	x.line("}")
  2144  	x.line("z.DecReadArrayEnd()")
  2145  	// else panic
  2146  	x.line("} else { ")
  2147  	x.line("panic(errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + ")")
  2148  	x.line("} ")
  2149  }
  2150  
  2151  // --------
  2152  
  2153  type fastpathGenV struct {
  2154  	// fastpathGenV is either a primitive (Primitive != "") or a map (MapKey != "") or a slice
  2155  	MapKey      string
  2156  	Elem        string
  2157  	Primitive   string
  2158  	Size        int
  2159  	NoCanonical bool
  2160  }
  2161  
  2162  func (x *genRunner) newFastpathGenV(t reflect.Type) (v fastpathGenV) {
  2163  	v.NoCanonical = !genFastpathCanonical
  2164  	switch t.Kind() {
  2165  	case reflect.Slice, reflect.Array:
  2166  		te := t.Elem()
  2167  		v.Elem = x.genTypeName(te)
  2168  		v.Size = int(te.Size())
  2169  	case reflect.Map:
  2170  		te := t.Elem()
  2171  		tk := t.Key()
  2172  		v.Elem = x.genTypeName(te)
  2173  		v.MapKey = x.genTypeName(tk)
  2174  		v.Size = int(te.Size() + tk.Size())
  2175  	default:
  2176  		halt.onerror(errGenUnexpectedTypeFastpath)
  2177  	}
  2178  	return
  2179  }
  2180  
  2181  func (x *fastpathGenV) MethodNamePfx(prefix string, prim bool) string {
  2182  	var name []byte
  2183  	if prefix != "" {
  2184  		name = append(name, prefix...)
  2185  	}
  2186  	if prim {
  2187  		name = append(name, genTitleCaseName(x.Primitive)...)
  2188  	} else {
  2189  		if x.MapKey == "" {
  2190  			name = append(name, "Slice"...)
  2191  		} else {
  2192  			name = append(name, "Map"...)
  2193  			name = append(name, genTitleCaseName(x.MapKey)...)
  2194  		}
  2195  		name = append(name, genTitleCaseName(x.Elem)...)
  2196  	}
  2197  	return string(name)
  2198  }
  2199  
  2200  // genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise.
  2201  //
  2202  // This handles the misbehaviour that occurs when 1.5-style vendoring is enabled,
  2203  // where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped.
  2204  // We strip it here.
  2205  func genImportPath(t reflect.Type) (s string) {
  2206  	s = t.PkgPath()
  2207  	if genCheckVendor {
  2208  		// HACK: always handle vendoring. It should be typically on in go 1.6, 1.7
  2209  		s = genStripVendor(s)
  2210  	}
  2211  	return
  2212  }
  2213  
  2214  // A go identifier is (letter|_)[letter|number|_]*
  2215  func genGoIdentifier(s string, checkFirstChar bool) string {
  2216  	b := make([]byte, 0, len(s))
  2217  	t := make([]byte, 4)
  2218  	var n int
  2219  	for i, r := range s {
  2220  		if checkFirstChar && i == 0 && !unicode.IsLetter(r) {
  2221  			b = append(b, '_')
  2222  		}
  2223  		// r must be unicode_letter, unicode_digit or _
  2224  		if unicode.IsLetter(r) || unicode.IsDigit(r) {
  2225  			n = utf8.EncodeRune(t, r)
  2226  			b = append(b, t[:n]...)
  2227  		} else {
  2228  			b = append(b, '_')
  2229  		}
  2230  	}
  2231  	return string(b)
  2232  }
  2233  
  2234  func genNonPtr(t reflect.Type) reflect.Type {
  2235  	for t.Kind() == reflect.Ptr {
  2236  		t = t.Elem()
  2237  	}
  2238  	return t
  2239  }
  2240  
  2241  func genFastpathUnderlying(t reflect.Type, rtid uintptr, ti *typeInfo) (tu reflect.Type, rtidu uintptr) {
  2242  	tu = t
  2243  	rtidu = rtid
  2244  	if ti.flagHasPkgPath {
  2245  		tu = ti.fastpathUnderlying
  2246  		rtidu = rt2id(tu)
  2247  	}
  2248  	return
  2249  }
  2250  
  2251  func genTitleCaseName(s string) string {
  2252  	switch s {
  2253  	case "interface{}", "interface {}":
  2254  		return "Intf"
  2255  	case "[]byte", "[]uint8", "bytes":
  2256  		return "Bytes"
  2257  	default:
  2258  		return strings.ToUpper(s[0:1]) + s[1:]
  2259  	}
  2260  }
  2261  
  2262  func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) {
  2263  	var ptrPfx string
  2264  	for t.Kind() == reflect.Ptr {
  2265  		ptrPfx += "Ptrto"
  2266  		t = t.Elem()
  2267  	}
  2268  	tstr := t.String()
  2269  	if tn := t.Name(); tn != "" {
  2270  		if tRef != nil && genImportPath(t) == genImportPath(tRef) {
  2271  			return ptrPfx + tn
  2272  		} else {
  2273  			if genQNameRegex.MatchString(tstr) {
  2274  				return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
  2275  			} else {
  2276  				return ptrPfx + genCustomTypeName(tstr)
  2277  			}
  2278  		}
  2279  	}
  2280  	switch t.Kind() {
  2281  	case reflect.Map:
  2282  		return ptrPfx + "Map" + genMethodNameT(t.Key(), tRef) + genMethodNameT(t.Elem(), tRef)
  2283  	case reflect.Slice:
  2284  		return ptrPfx + "Slice" + genMethodNameT(t.Elem(), tRef)
  2285  	case reflect.Array:
  2286  		return ptrPfx + "Array" + strconv.FormatInt(int64(t.Len()), 10) + genMethodNameT(t.Elem(), tRef)
  2287  	case reflect.Chan:
  2288  		var cx string
  2289  		switch t.ChanDir() {
  2290  		case reflect.SendDir:
  2291  			cx = "ChanSend"
  2292  		case reflect.RecvDir:
  2293  			cx = "ChanRecv"
  2294  		default:
  2295  			cx = "Chan"
  2296  		}
  2297  		return ptrPfx + cx + genMethodNameT(t.Elem(), tRef)
  2298  	default:
  2299  		if t == intfTyp {
  2300  			return ptrPfx + "Interface"
  2301  		} else {
  2302  			if tRef != nil && genImportPath(t) == genImportPath(tRef) {
  2303  				if t.Name() != "" {
  2304  					return ptrPfx + t.Name()
  2305  				} else {
  2306  					return ptrPfx + genCustomTypeName(tstr)
  2307  				}
  2308  			} else {
  2309  				// best way to get the package name inclusive
  2310  				if t.Name() != "" && genQNameRegex.MatchString(tstr) {
  2311  					return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
  2312  				} else {
  2313  					return ptrPfx + genCustomTypeName(tstr)
  2314  				}
  2315  			}
  2316  		}
  2317  	}
  2318  }
  2319  
  2320  // genCustomNameForType base32 encodes the t.String() value in such a way
  2321  // that it can be used within a function name.
  2322  func genCustomTypeName(tstr string) string {
  2323  	len2 := genTypenameEnc.EncodedLen(len(tstr))
  2324  	bufx := make([]byte, len2)
  2325  	genTypenameEnc.Encode(bufx, []byte(tstr))
  2326  	for i := len2 - 1; i >= 0; i-- {
  2327  		if bufx[i] == '=' {
  2328  			len2--
  2329  		} else {
  2330  			break
  2331  		}
  2332  	}
  2333  	return string(bufx[:len2])
  2334  }
  2335  
  2336  func genIsImmutable(t reflect.Type) (v bool) {
  2337  	return scalarBitset.isset(byte(t.Kind()))
  2338  }
  2339  
  2340  type genInternal struct {
  2341  	Version int
  2342  	Values  []fastpathGenV
  2343  	Formats []string
  2344  }
  2345  
  2346  func (x genInternal) FastpathLen() (l int) {
  2347  	for _, v := range x.Values {
  2348  		// if v.Primitive == "" && !(v.MapKey == "" && v.Elem == "uint8") {
  2349  		if v.Primitive == "" {
  2350  			l++
  2351  		}
  2352  	}
  2353  	return
  2354  }
  2355  
  2356  func genInternalZeroValue(s string) string {
  2357  	switch s {
  2358  	case "interface{}", "interface {}":
  2359  		return "nil"
  2360  	case "[]byte", "[]uint8", "bytes":
  2361  		return "nil"
  2362  	case "bool":
  2363  		return "false"
  2364  	case "string":
  2365  		return `""`
  2366  	default:
  2367  		return "0"
  2368  	}
  2369  }
  2370  
  2371  var genInternalNonZeroValueIdx [6]uint64
  2372  var genInternalNonZeroValueStrs = [...][6]string{
  2373  	{`"string-is-an-interface-1"`, "true", `"some-string-1"`, `[]byte("some-string-1")`, "11.1", "111"},
  2374  	{`"string-is-an-interface-2"`, "false", `"some-string-2"`, `[]byte("some-string-2")`, "22.2", "77"},
  2375  	{`"string-is-an-interface-3"`, "true", `"some-string-3"`, `[]byte("some-string-3")`, "33.3e3", "127"},
  2376  }
  2377  
  2378  // Note: last numbers must be in range: 0-127 (as they may be put into a int8, uint8, etc)
  2379  
  2380  func genInternalNonZeroValue(s string) string {
  2381  	var i int
  2382  	switch s {
  2383  	case "interface{}", "interface {}":
  2384  		i = 0
  2385  	case "bool":
  2386  		i = 1
  2387  	case "string":
  2388  		i = 2
  2389  	case "bytes", "[]byte", "[]uint8":
  2390  		i = 3
  2391  	case "float32", "float64", "float", "double", "complex", "complex64", "complex128":
  2392  		i = 4
  2393  	default:
  2394  		i = 5
  2395  	}
  2396  	genInternalNonZeroValueIdx[i]++
  2397  	idx := genInternalNonZeroValueIdx[i]
  2398  	slen := uint64(len(genInternalNonZeroValueStrs))
  2399  	return genInternalNonZeroValueStrs[idx%slen][i] // return string, to remove ambiguity
  2400  }
  2401  
  2402  // Note: used for fastpath only
  2403  func genInternalEncCommandAsString(s string, vname string) string {
  2404  	switch s {
  2405  	case "uint64":
  2406  		return "e.e.EncodeUint(" + vname + ")"
  2407  	case "uint", "uint8", "uint16", "uint32":
  2408  		return "e.e.EncodeUint(uint64(" + vname + "))"
  2409  	case "int64":
  2410  		return "e.e.EncodeInt(" + vname + ")"
  2411  	case "int", "int8", "int16", "int32":
  2412  		return "e.e.EncodeInt(int64(" + vname + "))"
  2413  	case "[]byte", "[]uint8", "bytes":
  2414  		return "e.e.EncodeStringBytesRaw(" + vname + ")"
  2415  	case "string":
  2416  		return "e.e.EncodeString(" + vname + ")"
  2417  	case "float32":
  2418  		return "e.e.EncodeFloat32(" + vname + ")"
  2419  	case "float64":
  2420  		return "e.e.EncodeFloat64(" + vname + ")"
  2421  	case "bool":
  2422  		return "e.e.EncodeBool(" + vname + ")"
  2423  	// case "symbol":
  2424  	// 	return "e.e.EncodeSymbol(" + vname + ")"
  2425  	default:
  2426  		return "e.encode(" + vname + ")"
  2427  	}
  2428  }
  2429  
  2430  // Note: used for fastpath only
  2431  func genInternalDecCommandAsString(s string, mapkey bool) string {
  2432  	switch s {
  2433  	case "uint":
  2434  		return "uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))"
  2435  	case "uint8":
  2436  		return "uint8(chkOvf.UintV(d.d.DecodeUint64(), 8))"
  2437  	case "uint16":
  2438  		return "uint16(chkOvf.UintV(d.d.DecodeUint64(), 16))"
  2439  	case "uint32":
  2440  		return "uint32(chkOvf.UintV(d.d.DecodeUint64(), 32))"
  2441  	case "uint64":
  2442  		return "d.d.DecodeUint64()"
  2443  	case "uintptr":
  2444  		return "uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))"
  2445  	case "int":
  2446  		return "int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))"
  2447  	case "int8":
  2448  		return "int8(chkOvf.IntV(d.d.DecodeInt64(), 8))"
  2449  	case "int16":
  2450  		return "int16(chkOvf.IntV(d.d.DecodeInt64(), 16))"
  2451  	case "int32":
  2452  		return "int32(chkOvf.IntV(d.d.DecodeInt64(), 32))"
  2453  	case "int64":
  2454  		return "d.d.DecodeInt64()"
  2455  
  2456  	case "string":
  2457  		// if mapkey {
  2458  		// 	return "d.stringZC(d.d.DecodeStringAsBytes())"
  2459  		// }
  2460  		// return "string(d.d.DecodeStringAsBytes())"
  2461  		return "d.stringZC(d.d.DecodeStringAsBytes())"
  2462  	case "[]byte", "[]uint8", "bytes":
  2463  		return "d.d.DecodeBytes([]byte{})"
  2464  	case "float32":
  2465  		return "float32(d.decodeFloat32())"
  2466  	case "float64":
  2467  		return "d.d.DecodeFloat64()"
  2468  	case "complex64":
  2469  		return "complex(d.decodeFloat32(), 0)"
  2470  	case "complex128":
  2471  		return "complex(d.d.DecodeFloat64(), 0)"
  2472  	case "bool":
  2473  		return "d.d.DecodeBool()"
  2474  	default:
  2475  		halt.onerror(errors.New("gen internal: unknown type for decode: " + s))
  2476  	}
  2477  	return ""
  2478  }
  2479  
  2480  // func genInternalSortType(s string, elem bool) string {
  2481  // 	for _, v := range [...]string{
  2482  // 		"int",
  2483  // 		"uint",
  2484  // 		"float",
  2485  // 		"bool",
  2486  // 		"string",
  2487  // 		"bytes", "[]uint8", "[]byte",
  2488  // 	} {
  2489  // 		if v == "[]byte" || v == "[]uint8" {
  2490  // 			v = "bytes"
  2491  // 		}
  2492  // 		if strings.HasPrefix(s, v) {
  2493  // 			if v == "int" || v == "uint" || v == "float" {
  2494  // 				v += "64"
  2495  // 			}
  2496  // 			if elem {
  2497  // 				return v
  2498  // 			}
  2499  // 			return v + "Slice"
  2500  // 		}
  2501  // 	}
  2502  // 	halt.onerror(errors.New("sorttype: unexpected type: " + s))
  2503  // }
  2504  
  2505  func genInternalSortType(s string, elem bool) string {
  2506  	if elem {
  2507  		return s
  2508  	}
  2509  	return s + "Slice"
  2510  }
  2511  
  2512  // MARKER: keep in sync with codecgen/gen.go
  2513  func genStripVendor(s string) string {
  2514  	// HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
  2515  	// if s contains /vendor/ OR startsWith vendor/, then return everything after it.
  2516  	const vendorStart = "vendor/"
  2517  	const vendorInline = "/vendor/"
  2518  	if i := strings.LastIndex(s, vendorInline); i >= 0 {
  2519  		s = s[i+len(vendorInline):]
  2520  	} else if strings.HasPrefix(s, vendorStart) {
  2521  		s = s[len(vendorStart):]
  2522  	}
  2523  	return s
  2524  }
  2525  
  2526  // var genInternalMu sync.Mutex
  2527  var genInternalV = genInternal{Version: genVersion}
  2528  var genInternalTmplFuncs template.FuncMap
  2529  var genInternalOnce sync.Once
  2530  
  2531  func genInternalInit() {
  2532  	wordSizeBytes := int(intBitsize) / 8
  2533  
  2534  	typesizes := map[string]int{
  2535  		"interface{}": 2 * wordSizeBytes,
  2536  		"string":      2 * wordSizeBytes,
  2537  		"[]byte":      3 * wordSizeBytes,
  2538  		"uint":        1 * wordSizeBytes,
  2539  		"uint8":       1,
  2540  		"uint16":      2,
  2541  		"uint32":      4,
  2542  		"uint64":      8,
  2543  		"uintptr":     1 * wordSizeBytes,
  2544  		"int":         1 * wordSizeBytes,
  2545  		"int8":        1,
  2546  		"int16":       2,
  2547  		"int32":       4,
  2548  		"int64":       8,
  2549  		"float32":     4,
  2550  		"float64":     8,
  2551  		"complex64":   8,
  2552  		"complex128":  16,
  2553  		"bool":        1,
  2554  	}
  2555  
  2556  	// keep as slice, so it is in specific iteration order.
  2557  	// Initial order was uint64, string, interface{}, int, int64, ...
  2558  
  2559  	var types = [...]string{
  2560  		"interface{}",
  2561  		"string",
  2562  		"[]byte",
  2563  		"float32",
  2564  		"float64",
  2565  		"uint",
  2566  		"uint8",
  2567  		"uint16",
  2568  		"uint32",
  2569  		"uint64",
  2570  		"uintptr",
  2571  		"int",
  2572  		"int8",
  2573  		"int16",
  2574  		"int32",
  2575  		"int64",
  2576  		"bool",
  2577  	}
  2578  
  2579  	var primitivetypes, slicetypes, mapkeytypes, mapvaltypes []string
  2580  
  2581  	primitivetypes = types[:]
  2582  	slicetypes = types[:]
  2583  	mapkeytypes = types[:]
  2584  	mapvaltypes = types[:]
  2585  
  2586  	if genFastpathTrimTypes {
  2587  		// Note: we only create fast-paths for commonly used types.
  2588  		// Consequently, things like int8, uint16, uint, etc are commented out.
  2589  
  2590  		slicetypes = genInternalFastpathSliceTypes()
  2591  		mapkeytypes = genInternalFastpathMapKeyTypes()
  2592  		mapvaltypes = genInternalFastpathMapValueTypes()
  2593  	}
  2594  
  2595  	// var mapkeytypes [len(&types) - 1]string // skip bool
  2596  	// copy(mapkeytypes[:], types[:])
  2597  
  2598  	// var mb []byte
  2599  	// mb = append(mb, '|')
  2600  	// for _, s := range mapkeytypes {
  2601  	// 	mb = append(mb, s...)
  2602  	// 	mb = append(mb, '|')
  2603  	// }
  2604  	// var mapkeytypestr = string(mb)
  2605  
  2606  	var gt = genInternal{Version: genVersion, Formats: genFormats}
  2607  
  2608  	// For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function
  2609  
  2610  	for _, s := range primitivetypes {
  2611  		gt.Values = append(gt.Values,
  2612  			fastpathGenV{Primitive: s, Size: typesizes[s], NoCanonical: !genFastpathCanonical})
  2613  	}
  2614  	for _, s := range slicetypes {
  2615  		// if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already.
  2616  		// 	gt.Values = append(gt.Values, fastpathGenV{Elem: s, Size: typesizes[s]})
  2617  		// }
  2618  		gt.Values = append(gt.Values,
  2619  			fastpathGenV{Elem: s, Size: typesizes[s], NoCanonical: !genFastpathCanonical})
  2620  	}
  2621  	for _, s := range mapkeytypes {
  2622  		// if _, ok := typesizes[s]; !ok {
  2623  		// if strings.Contains(mapkeytypestr, "|"+s+"|") {
  2624  		// 	gt.Values = append(gt.Values, fastpathGenV{MapKey: s, Elem: s, Size: 2 * typesizes[s]})
  2625  		// }
  2626  		for _, ms := range mapvaltypes {
  2627  			gt.Values = append(gt.Values,
  2628  				fastpathGenV{MapKey: s, Elem: ms, Size: typesizes[s] + typesizes[ms], NoCanonical: !genFastpathCanonical})
  2629  		}
  2630  	}
  2631  
  2632  	funcs := make(template.FuncMap)
  2633  	// funcs["haspfx"] = strings.HasPrefix
  2634  	funcs["encmd"] = genInternalEncCommandAsString
  2635  	funcs["decmd"] = genInternalDecCommandAsString
  2636  	funcs["zerocmd"] = genInternalZeroValue
  2637  	funcs["nonzerocmd"] = genInternalNonZeroValue
  2638  	funcs["hasprefix"] = strings.HasPrefix
  2639  	funcs["sorttype"] = genInternalSortType
  2640  
  2641  	genInternalV = gt
  2642  	genInternalTmplFuncs = funcs
  2643  }
  2644  
  2645  // genInternalGoFile is used to generate source files from templates.
  2646  func genInternalGoFile(r io.Reader, w io.Writer) (err error) {
  2647  	genInternalOnce.Do(genInternalInit)
  2648  
  2649  	gt := genInternalV
  2650  
  2651  	t := template.New("").Funcs(genInternalTmplFuncs)
  2652  
  2653  	tmplstr, err := ioutil.ReadAll(r)
  2654  	if err != nil {
  2655  		return
  2656  	}
  2657  
  2658  	if t, err = t.Parse(string(tmplstr)); err != nil {
  2659  		return
  2660  	}
  2661  
  2662  	var out bytes.Buffer
  2663  	err = t.Execute(&out, gt)
  2664  	if err != nil {
  2665  		return
  2666  	}
  2667  
  2668  	bout, err := format.Source(out.Bytes())
  2669  	if err != nil {
  2670  		w.Write(out.Bytes()) // write out if error, so we can still see.
  2671  		// w.Write(bout) // write out if error, as much as possible, so we can still see.
  2672  		return
  2673  	}
  2674  	w.Write(bout)
  2675  	return
  2676  }
  2677  
  2678  func genInternalFastpathSliceTypes() []string {
  2679  	return []string{
  2680  		"interface{}",
  2681  		"string",
  2682  		"[]byte",
  2683  		"float32",
  2684  		"float64",
  2685  		// "uint",
  2686  		// "uint8", // no need for fastpath of []uint8, as it is handled specially
  2687  		"uint8", // keep fast-path, so it doesn't have to go through reflection
  2688  		// "uint16",
  2689  		// "uint32",
  2690  		"uint64",
  2691  		// "uintptr",
  2692  		"int",
  2693  		// "int8",
  2694  		// "int16",
  2695  		"int32", // rune
  2696  		"int64",
  2697  		"bool",
  2698  	}
  2699  }
  2700  
  2701  func genInternalFastpathMapKeyTypes() []string {
  2702  	return []string{
  2703  		// "interface{}",
  2704  		"string",
  2705  		// "[]byte",
  2706  		// "float32",
  2707  		// "float64",
  2708  		// "uint",
  2709  		"uint8", // byte
  2710  		// "uint16",
  2711  		// "uint32",
  2712  		"uint64", // used for keys
  2713  		// "uintptr",
  2714  		"int", // default number key
  2715  		// "int8",
  2716  		// "int16",
  2717  		"int32", // rune
  2718  		// "int64",
  2719  		// "bool",
  2720  	}
  2721  }
  2722  
  2723  func genInternalFastpathMapValueTypes() []string {
  2724  	return []string{
  2725  		"interface{}",
  2726  		"string",
  2727  		"[]byte",
  2728  		// "uint",
  2729  		"uint8", // byte
  2730  		// "uint16",
  2731  		// "uint32",
  2732  		"uint64", // used for keys, etc
  2733  		// "uintptr",
  2734  		"int", // default number
  2735  		//"int8",
  2736  		// "int16",
  2737  		"int32", // rune (mostly used for unicode)
  2738  		// "int64",
  2739  		// "float32",
  2740  		"float64",
  2741  		"bool",
  2742  	}
  2743  }
  2744  
  2745  // sort-slice ...
  2746  // generates sort implementations for
  2747  // various slice types and combination slice+reflect.Value types.
  2748  //
  2749  // The combination slice+reflect.Value types are used
  2750  // during canonical encode, and the others are used during fast-path
  2751  // encoding of map keys.
  2752  
  2753  // genInternalSortableTypes returns the types
  2754  // that are used for fast-path canonical's encoding of maps.
  2755  //
  2756  // For now, we only support the highest sizes for
  2757  // int64, uint64, float64, bool, string, bytes.
  2758  func genInternalSortableTypes() []string {
  2759  	return genInternalFastpathMapKeyTypes()
  2760  }
  2761  
  2762  // genInternalSortablePlusTypes returns the types
  2763  // that are used for reflection-based canonical's encoding of maps.
  2764  //
  2765  // For now, we only support the highest sizes for
  2766  // int64, uint64, float64, string, bytes.
  2767  func genInternalSortablePlusTypes() []string {
  2768  	return []string{
  2769  		"string",
  2770  		"float64",
  2771  		"uint64",
  2772  		// "uintptr",
  2773  		"int64",
  2774  		// "bool",
  2775  		"time",
  2776  		"bytes",
  2777  	}
  2778  }
  2779  
  2780  func genTypeForShortName(s string) string {
  2781  	switch s {
  2782  	case "time":
  2783  		return "time.Time"
  2784  	case "bytes":
  2785  		return "[]byte"
  2786  	}
  2787  	return s
  2788  }
  2789  
  2790  func genArgs(args ...interface{}) map[string]interface{} {
  2791  	m := make(map[string]interface{}, len(args)/2)
  2792  	for i := 0; i < len(args); {
  2793  		m[args[i].(string)] = args[i+1]
  2794  		i += 2
  2795  	}
  2796  	return m
  2797  }
  2798  
  2799  func genEndsWith(s0 string, sn ...string) bool {
  2800  	for _, s := range sn {
  2801  		if strings.HasSuffix(s0, s) {
  2802  			return true
  2803  		}
  2804  	}
  2805  	return false
  2806  }
  2807  
  2808  func genCheckErr(err error) {
  2809  	halt.onerror(err)
  2810  }
  2811  
  2812  func genRunSortTmpl2Go(fnameIn, fnameOut string) {
  2813  	var err error
  2814  
  2815  	funcs := make(template.FuncMap)
  2816  	funcs["sortables"] = genInternalSortableTypes
  2817  	funcs["sortablesplus"] = genInternalSortablePlusTypes
  2818  	funcs["tshort"] = genTypeForShortName
  2819  	funcs["endswith"] = genEndsWith
  2820  	funcs["args"] = genArgs
  2821  
  2822  	t := template.New("").Funcs(funcs)
  2823  	fin, err := os.Open(fnameIn)
  2824  	genCheckErr(err)
  2825  	defer fin.Close()
  2826  	fout, err := os.Create(fnameOut)
  2827  	genCheckErr(err)
  2828  	defer fout.Close()
  2829  	tmplstr, err := ioutil.ReadAll(fin)
  2830  	genCheckErr(err)
  2831  	t, err = t.Parse(string(tmplstr))
  2832  	genCheckErr(err)
  2833  	var out bytes.Buffer
  2834  	err = t.Execute(&out, 0)
  2835  	genCheckErr(err)
  2836  	bout, err := format.Source(out.Bytes())
  2837  	if err != nil {
  2838  		fout.Write(out.Bytes()) // write out if error, so we can still see.
  2839  	}
  2840  	genCheckErr(err)
  2841  	// write out if error, as much as possible, so we can still see.
  2842  	_, err = fout.Write(bout)
  2843  	genCheckErr(err)
  2844  }
  2845  
  2846  func genRunTmpl2Go(fnameIn, fnameOut string) {
  2847  	// println("____ " + fnameIn + " --> " + fnameOut + " ______")
  2848  	fin, err := os.Open(fnameIn)
  2849  	genCheckErr(err)
  2850  	defer fin.Close()
  2851  	fout, err := os.Create(fnameOut)
  2852  	genCheckErr(err)
  2853  	defer fout.Close()
  2854  	err = genInternalGoFile(fin, fout)
  2855  	genCheckErr(err)
  2856  }
  2857  
  2858  // --- some methods here for other types, which are only used in codecgen
  2859  
  2860  // depth returns number of valid nodes in the hierachy
  2861  func (path *structFieldInfoPathNode) root() *structFieldInfoPathNode {
  2862  TOP:
  2863  	if path.parent != nil {
  2864  		path = path.parent
  2865  		goto TOP
  2866  	}
  2867  	return path
  2868  }
  2869  
  2870  func (path *structFieldInfoPathNode) fullpath() (p []*structFieldInfoPathNode) {
  2871  	// this method is mostly called by a command-line tool - it's not optimized, and that's ok.
  2872  	// it shouldn't be used in typical runtime use - as it does unnecessary allocation.
  2873  	d := path.depth()
  2874  	p = make([]*structFieldInfoPathNode, d)
  2875  	for d--; d >= 0; d-- {
  2876  		p[d] = path
  2877  		path = path.parent
  2878  	}
  2879  	return
  2880  }