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