podman

Форк
0
2880 строк · 85.6 Кб
1
// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
2
// Use of this source code is governed by a MIT license found in the LICENSE file.
3

4
//go:build codecgen.exec
5
// +build codecgen.exec
6

7
package codec
8

9
import (
10
	"bytes"
11
	"encoding/base32"
12
	"errors"
13
	"fmt"
14
	"go/format"
15
	"io"
16
	"io/ioutil"
17
	"math/rand"
18
	"os"
19
	"reflect"
20
	"regexp"
21
	"sort"
22
	"strconv"
23
	"strings"
24
	"sync"
25
	"text/template"
26
	"time"
27
	// "ugorji.net/zz"
28
	"unicode"
29
	"unicode/utf8"
30
)
31

32
// ---------------------------------------------------
33
// codecgen supports the full cycle of reflection-based codec:
34
//    - RawExt
35
//    - Raw
36
//    - Extensions
37
//    - (Binary|Text|JSON)(Unm|M)arshal
38
//    - generic by-kind
39
//
40
// This means that, for dynamic things, we MUST use reflection to at least get the reflect.Type.
41
// In those areas, we try to only do reflection or interface-conversion when NECESSARY:
42
//    - Extensions, only if Extensions are configured.
43
//
44
// However, note following codecgen caveats:
45
//   - Canonical option.
46
//     If Canonical=true, codecgen'ed code may delegate encoding maps to reflection-based code.
47
//     This is due to the runtime work needed to marshal a map in canonical mode.
48
//     However, if map key is a pre-defined/builtin numeric or string type, codecgen
49
//     will try to write it out itself
50
//   - CheckCircularRef option.
51
//     When encoding a struct, a circular reference can lead to a stack overflow.
52
//     If CheckCircularRef=true, codecgen'ed code will delegate encoding structs to reflection-based code.
53
//   - MissingFielder implementation.
54
//     If a type implements MissingFielder, a Selfer is not generated (with a warning message).
55
//     Statically reproducing the runtime work needed to extract the missing fields and marshal them
56
//     along with the struct fields, while handling the Canonical=true special case, was onerous to implement.
57
//
58
// During encode/decode, Selfer takes precedence.
59
// A type implementing Selfer will know how to encode/decode itself statically.
60
//
61
// The following field types are supported:
62
//     array: [n]T
63
//     slice: []T
64
//     map: map[K]V
65
//     primitive: [u]int[n], float(32|64), bool, string
66
//     struct
67
//
68
// ---------------------------------------------------
69
// Note that a Selfer cannot call (e|d).(En|De)code on itself,
70
// as this will cause a circular reference, as (En|De)code will call Selfer methods.
71
// Any type that implements Selfer must implement completely and not fallback to (En|De)code.
72
//
73
// In addition, code in this file manages the generation of fast-path implementations of
74
// encode/decode of slices/maps of primitive keys/values.
75
//
76
// Users MUST re-generate their implementations whenever the code shape changes.
77
// The generated code will panic if it was generated with a version older than the supporting library.
78
// ---------------------------------------------------
79
//
80
// codec framework is very feature rich.
81
// When encoding or decoding into an interface, it depends on the runtime type of the interface.
82
// The type of the interface may be a named type, an extension, etc.
83
// Consequently, we fallback to runtime codec for encoding/decoding interfaces.
84
// In addition, we fallback for any value which cannot be guaranteed at runtime.
85
// This allows us support ANY value, including any named types, specifically those which
86
// do not implement our interfaces (e.g. Selfer).
87
//
88
// This explains some slowness compared to other code generation codecs (e.g. msgp).
89
// This reduction in speed is only seen when your refers to interfaces,
90
// e.g. type T struct { A interface{}; B []interface{}; C map[string]interface{} }
91
//
92
// codecgen will panic if the file was generated with an old version of the library in use.
93
//
94
// Note:
95
//   It was a conscious decision to have gen.go always explicitly call EncodeNil or TryDecodeAsNil.
96
//   This way, there isn't a function call overhead just to see that we should not enter a block of code.
97
//
98
// Note:
99
//   codecgen-generated code depends on the variables defined by fast-path.generated.go.
100
//   consequently, you cannot run with tags "codecgen codec.notfastpath".
101
//
102
// Note:
103
//   genInternalXXX functions are used for generating fast-path and other internally generated
104
//   files, and not for use in codecgen.
105

106
// Size of a struct or value is not portable across machines, especially across 32-bit vs 64-bit
107
// operating systems. This is due to types like int, uintptr, pointers, (and derived types like slice), etc
108
// which use the natural word size on those machines, which may be 4 bytes (on 32-bit) or 8 bytes (on 64-bit).
109
//
110
// Within decInferLen calls, we may generate an explicit size of the entry.
111
// We do this because decInferLen values are expected to be approximate,
112
// and serve as a good hint on the size of the elements or key+value entry.
113
//
114
// Since development is done on 64-bit machines, the sizes will be roughly correctly
115
// on 64-bit OS, and slightly larger than expected on 32-bit OS.
116
// This is ok.
117
//
118
// For reference, look for 'Size' in fast-path.go.tmpl, gen-dec-(array|map).go.tmpl and gen.go (this file).
119

120
// GenVersion is the current version of codecgen.
121
//
122
// MARKER: Increment this value each time codecgen changes fundamentally.
123
// Also update codecgen/gen.go (minimumCodecVersion, genVersion, etc).
124
// Fundamental changes are:
125
//   - helper methods change (signature change, new ones added, some removed, etc)
126
//   - codecgen command line changes
127
//
128
// v1: Initial Version
129
// v2: -
130
// v3: For Kubernetes: changes in signature of some unpublished helper methods and codecgen cmdline arguments.
131
// v4: Removed separator support from (en|de)cDriver, and refactored codec(gen)
132
// v5: changes to support faster json decoding. Let encoder/decoder maintain state of collections.
133
// v6: removed unsafe from gen, and now uses codecgen.exec tag
134
// v7: -
135
// v8: current - we now maintain compatibility with old generated code.
136
// v9: - skipped
137
// v10: modified encDriver and decDriver interfaces.
138
// v11: remove deprecated methods of encDriver and decDriver.
139
// v12: removed deprecated methods from genHelper and changed container tracking logic
140
// v13: 20190603 removed DecodeString - use DecodeStringAsBytes instead
141
// v14: 20190611 refactored nil handling: TryDecodeAsNil -> selective TryNil, etc
142
// v15: 20190626 encDriver.EncodeString handles StringToRaw flag inside handle
143
// v16: 20190629 refactoring for v1.1.6
144
// v17: 20200911 reduce number of types for which we generate fast path functions (v1.1.8)
145
// v18: 20201004 changed definition of genHelper...Extension (to take interface{}) and eliminated I2Rtid method
146
// v19: 20201115 updated codecgen cmdline flags and optimized output
147
// v20: 20201120 refactored GenHelper to one exported function
148
// v21: 20210104 refactored generated code to honor ZeroCopy=true for more efficiency
149
// v22: 20210118 fixed issue in generated code when encoding a type which is also a codec.Selfer
150
// v23: 20210203 changed slice/map types for which we generate fast-path functions
151
// v24: 20210226 robust handling for Canonical|CheckCircularRef flags and MissingFielder implementations
152
// v25: 20210406 pass base reflect.Type to side(En|De)code and (En|De)codeExt calls
153
// v26: 20230201 genHelper changes for more inlining and consequent performance
154
// v27: 20230219 fix error decoding struct from array - due to misplaced counter increment
155
// v28: 20230224  fix decoding missing fields of struct from array, due to double counter increment
156
const genVersion = 28
157

158
const (
159
	genCodecPkg        = "codec1978" // MARKER: keep in sync with codecgen/gen.go
160
	genTempVarPfx      = "yy"
161
	genTopLevelVarName = "x"
162

163
	// ignore canBeNil parameter, and always set to true.
164
	// This is because nil can appear anywhere, so we should always check.
165
	genAnythingCanBeNil = true
166

167
	// genStructCanonical configures whether we generate 2 paths based on Canonical flag
168
	// when encoding struct fields.
169
	genStructCanonical = true
170

171
	// genFastpathCanonical configures whether we support Canonical in fast path.
172
	// The savings is not much.
173
	//
174
	// MARKER: This MUST ALWAYS BE TRUE. fast-path.go.tmp doesn't handle it being false.
175
	genFastpathCanonical = true
176

177
	// genFastpathTrimTypes configures whether we trim uncommon fastpath types.
178
	genFastpathTrimTypes = true
179
)
180

181
type genStringDecAsBytes string
182
type genStringDecZC string
183

184
var genStringDecAsBytesTyp = reflect.TypeOf(genStringDecAsBytes(""))
185
var genStringDecZCTyp = reflect.TypeOf(genStringDecZC(""))
186
var genFormats = []string{"Json", "Cbor", "Msgpack", "Binc", "Simple"}
187

188
var (
189
	errGenAllTypesSamePkg        = errors.New("All types must be in the same package")
190
	errGenExpectArrayOrMap       = errors.New("unexpected type - expecting array/map/slice")
191
	errGenUnexpectedTypeFastpath = errors.New("fast-path: unexpected type - requires map or slice")
192

193
	// don't use base64, only 63 characters allowed in valid go identifiers
194
	// ie ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_
195
	//
196
	// don't use numbers, as a valid go identifer must start with a letter.
197
	genTypenameEnc  = base32.NewEncoding("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
198
	genQNameRegex = regexp.MustCompile(`[A-Za-z_.]+`)
199
)
200

201
type genBuf struct {
202
	buf []byte
203
}
204

205
func (x *genBuf) sIf(b bool, s, t string) *genBuf {
206
	if b {
207
		x.buf = append(x.buf, s...)
208
	} else {
209
		x.buf = append(x.buf, t...)
210
	}
211
	return x
212
}
213
func (x *genBuf) s(s string) *genBuf              { x.buf = append(x.buf, s...); return x }
214
func (x *genBuf) b(s []byte) *genBuf              { x.buf = append(x.buf, s...); return x }
215
func (x *genBuf) v() string                       { return string(x.buf) }
216
func (x *genBuf) f(s string, args ...interface{}) { x.s(fmt.Sprintf(s, args...)) }
217
func (x *genBuf) reset() {
218
	if x.buf != nil {
219
		x.buf = x.buf[:0]
220
	}
221
}
222

223
// genRunner holds some state used during a Gen run.
224
type genRunner struct {
225
	w io.Writer // output
226
	c uint64    // counter used for generating varsfx
227
	f uint64    // counter used for saying false
228

229
	t  []reflect.Type   // list of types to run selfer on
230
	tc reflect.Type     // currently running selfer on this type
231
	te map[uintptr]bool // types for which the encoder has been created
232
	td map[uintptr]bool // types for which the decoder has been created
233
	tz map[uintptr]bool // types for which GenIsZero has been created
234

235
	cp string // codec import path
236

237
	im  map[string]reflect.Type // imports to add
238
	imn map[string]string       // package names of imports to add
239
	imc uint64                  // counter for import numbers
240

241
	is map[reflect.Type]struct{} // types seen during import search
242
	bp string                    // base PkgPath, for which we are generating for
243

244
	cpfx string // codec package prefix
245

246
	ty map[reflect.Type]struct{} // types for which GenIsZero *should* be created
247
	tm map[reflect.Type]struct{} // types for which enc/dec must be generated
248
	ts []reflect.Type            // types for which enc/dec must be generated
249

250
	xs string // top level variable/constant suffix
251
	hn string // fn helper type name
252

253
	ti *TypeInfos
254
	// rr *rand.Rand // random generator for file-specific types
255

256
	jsonOnlyWhen, toArrayWhen, omitEmptyWhen *bool
257

258
	nx bool // no extensions
259
}
260

261
type genIfClause struct {
262
	hasIf bool
263
}
264

265
func (g *genIfClause) end(x *genRunner) {
266
	if g.hasIf {
267
		x.line("}")
268
	}
269
}
270

271
func (g *genIfClause) c(last bool) (v string) {
272
	if last {
273
		if g.hasIf {
274
			v = " } else { "
275
		}
276
	} else if g.hasIf {
277
		v = " } else if "
278
	} else {
279
		v = "if "
280
		g.hasIf = true
281
	}
282
	return
283
}
284

285
// Gen will write a complete go file containing Selfer implementations for each
286
// type passed. All the types must be in the same package.
287
//
288
// Library users: DO NOT USE IT DIRECTLY. IT WILL CHANGE CONTINUOUSLY WITHOUT NOTICE.
289
func Gen(w io.Writer, buildTags, pkgName, uid string, noExtensions bool,
290
	jsonOnlyWhen, toArrayWhen, omitEmptyWhen *bool,
291
	ti *TypeInfos, types ...reflect.Type) (warnings []string) {
292
	// All types passed to this method do not have a codec.Selfer method implemented directly.
293
	// codecgen already checks the AST and skips any types that define the codec.Selfer methods.
294
	// Consequently, there's no need to check and trim them if they implement codec.Selfer
295

296
	if len(types) == 0 {
297
		return
298
	}
299
	x := genRunner{
300
		w:             w,
301
		t:             types,
302
		te:            make(map[uintptr]bool),
303
		td:            make(map[uintptr]bool),
304
		tz:            make(map[uintptr]bool),
305
		im:            make(map[string]reflect.Type),
306
		imn:           make(map[string]string),
307
		is:            make(map[reflect.Type]struct{}),
308
		tm:            make(map[reflect.Type]struct{}),
309
		ty:            make(map[reflect.Type]struct{}),
310
		ts:            []reflect.Type{},
311
		bp:            genImportPath(types[0]),
312
		xs:            uid,
313
		ti:            ti,
314
		jsonOnlyWhen:  jsonOnlyWhen,
315
		toArrayWhen:   toArrayWhen,
316
		omitEmptyWhen: omitEmptyWhen,
317

318
		nx: noExtensions,
319
	}
320
	if x.ti == nil {
321
		x.ti = defTypeInfos
322
	}
323
	if x.xs == "" {
324
		rr := rand.New(rand.NewSource(time.Now().UnixNano()))
325
		x.xs = strconv.FormatInt(rr.Int63n(9999), 10)
326
	}
327

328
	// gather imports first:
329
	x.cp = genImportPath(reflect.TypeOf(x))
330
	x.imn[x.cp] = genCodecPkg
331

332
	// iterate, check if all in same package, and remove any missingfielders
333
	for i := 0; i < len(x.t); {
334
		t := x.t[i]
335
		// xdebugf("###########: PkgPath: '%v', Name: '%s'\n", genImportPath(t), t.Name())
336
		if genImportPath(t) != x.bp {
337
			halt.onerror(errGenAllTypesSamePkg)
338
		}
339
		ti1 := x.ti.get(rt2id(t), t)
340
		if ti1.flagMissingFielder || ti1.flagMissingFielderPtr {
341
			// output diagnostic message  - that nothing generated for this type
342
			warnings = append(warnings, fmt.Sprintf("type: '%v' not generated; implements codec.MissingFielder", t))
343
			copy(x.t[i:], x.t[i+1:])
344
			x.t = x.t[:len(x.t)-1]
345
			continue
346
		}
347
		x.genRefPkgs(t)
348
		i++
349
	}
350

351
	x.line("// +build go1.6")
352
	if buildTags != "" {
353
		x.line("// +build " + buildTags)
354
	}
355
	x.line(`
356

357
// Code generated by codecgen - DO NOT EDIT.
358

359
`)
360
	x.line("package " + pkgName)
361
	x.line("")
362
	x.line("import (")
363
	if x.cp != x.bp {
364
		x.cpfx = genCodecPkg + "."
365
		x.linef("%s \"%s\"", genCodecPkg, x.cp)
366
	}
367
	// use a sorted set of im keys, so that we can get consistent output
368
	imKeys := make([]string, 0, len(x.im))
369
	for k := range x.im {
370
		imKeys = append(imKeys, k)
371
	}
372
	sort.Strings(imKeys)
373
	for _, k := range imKeys { // for k, _ := range x.im {
374
		if k == x.imn[k] {
375
			x.linef("\"%s\"", k)
376
		} else {
377
			x.linef("%s \"%s\"", x.imn[k], k)
378
		}
379
	}
380
	// add required packages
381
	for _, k := range [...]string{"runtime", "errors", "strconv", "sort"} { // "reflect", "fmt"
382
		if _, ok := x.im[k]; !ok {
383
			x.line("\"" + k + "\"")
384
		}
385
	}
386
	x.line(")")
387
	x.line("")
388

389
	x.line("const (")
390
	x.linef("// ----- content types ----")
391
	x.linef("codecSelferCcUTF8%s = %v", x.xs, int64(cUTF8))
392
	x.linef("codecSelferCcRAW%s = %v", x.xs, int64(cRAW))
393
	x.linef("// ----- value types used ----")
394
	for _, vt := range [...]valueType{
395
		valueTypeArray, valueTypeMap, valueTypeString,
396
		valueTypeInt, valueTypeUint, valueTypeFloat,
397
		valueTypeNil,
398
	} {
399
		x.linef("codecSelferValueType%s%s = %v", vt.String(), x.xs, int64(vt))
400
	}
401

402
	x.linef("codecSelferBitsize%s = uint8(32 << (^uint(0) >> 63))", x.xs)
403
	x.linef("codecSelferDecContainerLenNil%s = %d", x.xs, int64(containerLenNil))
404
	x.line(")")
405
	x.line("var (")
406
	x.line("errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + " = " + "errors.New(`only encoded map or array can be decoded into a struct`)")
407
	x.line("_ sort.Interface = nil")
408
	x.line(")")
409
	x.line("")
410

411
	x.hn = "codecSelfer" + x.xs
412
	x.line("type " + x.hn + " struct{}")
413
	x.line("")
414
	x.linef("func %sFalse() bool { return false }", x.hn)
415
	x.linef("func %sTrue() bool { return true }", x.hn)
416
	x.line("")
417

418
	// add types for sorting canonical
419
	for _, s := range []string{"string", "uint64", "int64", "float64"} {
420
		x.linef("type %s%sSlice []%s", x.hn, s, s)
421
		x.linef("func (p %s%sSlice) Len() int      { return len(p) }", x.hn, s)
422
		x.linef("func (p %s%sSlice) Swap(i, j int) { p[uint(i)], p[uint(j)] = p[uint(j)], p[uint(i)] }", x.hn, s)
423
		x.linef("func (p %s%sSlice) Less(i, j int) bool { return p[uint(i)] < p[uint(j)] }", x.hn, s)
424
	}
425

426
	x.line("")
427
	x.varsfxreset()
428
	x.line("func init() {")
429
	x.linef("if %sGenVersion != %v {", x.cpfx, genVersion)
430
	x.line("_, file, _, _ := runtime.Caller(0)")
431
	x.linef("ver := strconv.FormatInt(int64(%sGenVersion), 10)", x.cpfx)
432
	x.outf(`panic(errors.New("codecgen version mismatch: current: %v, need " + ver + ". Re-generate file: " + file))`, genVersion)
433
	x.linef("}")
434
	if len(imKeys) > 0 {
435
		x.line("if false { // reference the types, but skip this branch at build/run time")
436
		for _, k := range imKeys {
437
			t := x.im[k]
438
			x.linef("var _ %s.%s", x.imn[k], t.Name())
439
		}
440
		x.line("} ") // close if false
441
	}
442
	x.line("}") // close init
443
	x.line("")
444

445
	// generate rest of type info
446
	for _, t := range x.t {
447
		x.tc = t
448
		x.linef("func (%s) codecSelferViaCodecgen() {}", x.genTypeName(t))
449
		x.selfer(true)
450
		x.selfer(false)
451
		x.tryGenIsZero(t)
452
	}
453

454
	for _, t := range x.ts {
455
		rtid := rt2id(t)
456
		// generate enc functions for all these slice/map types.
457
		x.varsfxreset()
458
		x.linef("func (x %s) enc%s(v %s%s, e *%sEncoder) {", x.hn, x.genMethodNameT(t), x.arr2str(t, "*"), x.genTypeName(t), x.cpfx)
459
		x.genRequiredMethodVars(true)
460
		switch t.Kind() {
461
		case reflect.Array, reflect.Slice, reflect.Chan:
462
			x.encListFallback("v", t)
463
		case reflect.Map:
464
			x.encMapFallback("v", t)
465
		default:
466
			halt.onerror(errGenExpectArrayOrMap)
467
		}
468
		x.line("}")
469
		x.line("")
470

471
		// generate dec functions for all these slice/map types.
472
		x.varsfxreset()
473
		x.linef("func (x %s) dec%s(v *%s, d *%sDecoder) {", x.hn, x.genMethodNameT(t), x.genTypeName(t), x.cpfx)
474
		x.genRequiredMethodVars(false)
475
		switch t.Kind() {
476
		case reflect.Array, reflect.Slice, reflect.Chan:
477
			x.decListFallback("v", rtid, t)
478
		case reflect.Map:
479
			x.decMapFallback("v", rtid, t)
480
		default:
481
			halt.onerror(errGenExpectArrayOrMap)
482
		}
483
		x.line("}")
484
		x.line("")
485
	}
486

487
	for t := range x.ty {
488
		x.tryGenIsZero(t)
489
		x.line("")
490
	}
491

492
	x.line("")
493
	return
494
}
495

496
func (x *genRunner) checkForSelfer(t reflect.Type, varname string) bool {
497
	// return varname != genTopLevelVarName && t != x.tc
498
	// the only time we checkForSelfer is if we are not at the TOP of the generated code.
499
	return varname != genTopLevelVarName
500
}
501

502
func (x *genRunner) arr2str(t reflect.Type, s string) string {
503
	if t.Kind() == reflect.Array {
504
		return s
505
	}
506
	return ""
507
}
508

509
func (x *genRunner) genRequiredMethodVars(encode bool) {
510
	x.line("var h " + x.hn)
511
	if encode {
512
		x.line("z, r := " + x.cpfx + "GenHelper().Encoder(e)")
513
	} else {
514
		x.line("z, r := " + x.cpfx + "GenHelper().Decoder(d)")
515
	}
516
	x.line("_, _, _ = h, z, r")
517
}
518

519
func (x *genRunner) genRefPkgs(t reflect.Type) {
520
	if _, ok := x.is[t]; ok {
521
		return
522
	}
523
	x.is[t] = struct{}{}
524
	tpkg, tname := genImportPath(t), t.Name()
525
	if tpkg != "" && tpkg != x.bp && tpkg != x.cp && tname != "" && tname[0] >= 'A' && tname[0] <= 'Z' {
526
		if _, ok := x.im[tpkg]; !ok {
527
			x.im[tpkg] = t
528
			if idx := strings.LastIndex(tpkg, "/"); idx < 0 {
529
				x.imn[tpkg] = tpkg
530
			} else {
531
				x.imc++
532
				x.imn[tpkg] = "pkg" + strconv.FormatUint(x.imc, 10) + "_" + genGoIdentifier(tpkg[idx+1:], false)
533
			}
534
		}
535
	}
536
	switch t.Kind() {
537
	case reflect.Array, reflect.Slice, reflect.Ptr, reflect.Chan:
538
		x.genRefPkgs(t.Elem())
539
	case reflect.Map:
540
		x.genRefPkgs(t.Elem())
541
		x.genRefPkgs(t.Key())
542
	case reflect.Struct:
543
		for i := 0; i < t.NumField(); i++ {
544
			if fname := t.Field(i).Name; fname != "" && fname[0] >= 'A' && fname[0] <= 'Z' {
545
				x.genRefPkgs(t.Field(i).Type)
546
			}
547
		}
548
	}
549
}
550

551
// sayFalse will either say "false" or use a function call that returns false.
552
func (x *genRunner) sayFalse() string {
553
	x.f++
554
	if x.f%2 == 0 {
555
		return x.hn + "False()"
556
	}
557
	return "false"
558
}
559

560
// sayFalse will either say "true" or use a function call that returns true.
561
func (x *genRunner) sayTrue() string {
562
	x.f++
563
	if x.f%2 == 0 {
564
		return x.hn + "True()"
565
	}
566
	return "true"
567
}
568

569
func (x *genRunner) varsfx() string {
570
	x.c++
571
	return strconv.FormatUint(x.c, 10)
572
}
573

574
func (x *genRunner) varsfxreset() {
575
	x.c = 0
576
}
577

578
func (x *genRunner) out(s string) {
579
	_, err := io.WriteString(x.w, s)
580
	genCheckErr(err)
581
}
582

583
func (x *genRunner) outf(s string, params ...interface{}) {
584
	_, err := fmt.Fprintf(x.w, s, params...)
585
	genCheckErr(err)
586
}
587

588
func (x *genRunner) line(s string) {
589
	x.out(s)
590
	if len(s) == 0 || s[len(s)-1] != '\n' {
591
		x.out("\n")
592
	}
593
}
594

595
func (x *genRunner) lineIf(s string) {
596
	if s != "" {
597
		x.line(s)
598
	}
599
}
600

601
func (x *genRunner) linef(s string, params ...interface{}) {
602
	x.outf(s, params...)
603
	if len(s) == 0 || s[len(s)-1] != '\n' {
604
		x.out("\n")
605
	}
606
}
607

608
func (x *genRunner) genTypeName(t reflect.Type) (n string) {
609
	// if the type has a PkgPath, which doesn't match the current package,
610
	// then include it.
611
	// We cannot depend on t.String() because it includes current package,
612
	// or t.PkgPath because it includes full import path,
613
	//
614
	var ptrPfx string
615
	for t.Kind() == reflect.Ptr {
616
		ptrPfx += "*"
617
		t = t.Elem()
618
	}
619
	if tn := t.Name(); tn != "" {
620
		return ptrPfx + x.genTypeNamePrim(t)
621
	}
622
	switch t.Kind() {
623
	case reflect.Map:
624
		return ptrPfx + "map[" + x.genTypeName(t.Key()) + "]" + x.genTypeName(t.Elem())
625
	case reflect.Slice:
626
		return ptrPfx + "[]" + x.genTypeName(t.Elem())
627
	case reflect.Array:
628
		return ptrPfx + "[" + strconv.FormatInt(int64(t.Len()), 10) + "]" + x.genTypeName(t.Elem())
629
	case reflect.Chan:
630
		return ptrPfx + t.ChanDir().String() + " " + x.genTypeName(t.Elem())
631
	default:
632
		if t == intfTyp {
633
			return ptrPfx + "interface{}"
634
		} else {
635
			return ptrPfx + x.genTypeNamePrim(t)
636
		}
637
	}
638
}
639

640
func (x *genRunner) genTypeNamePrim(t reflect.Type) (n string) {
641
	if t.Name() == "" {
642
		return t.String()
643
	} else if genImportPath(t) == "" || genImportPath(t) == genImportPath(x.tc) {
644
		return t.Name()
645
	} else {
646
		return x.imn[genImportPath(t)] + "." + t.Name()
647
		// return t.String() // best way to get the package name inclusive
648
	}
649
}
650

651
func (x *genRunner) genZeroValueR(t reflect.Type) string {
652
	// if t is a named type, w
653
	switch t.Kind() {
654
	case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func,
655
		reflect.Slice, reflect.Map, reflect.Invalid:
656
		return "nil"
657
	case reflect.Bool:
658
		return "false"
659
	case reflect.String:
660
		return `""`
661
	case reflect.Struct, reflect.Array:
662
		return x.genTypeName(t) + "{}"
663
	default: // all numbers
664
		return "0"
665
	}
666
}
667

668
func (x *genRunner) genMethodNameT(t reflect.Type) (s string) {
669
	return genMethodNameT(t, x.tc)
670
}
671

672
func (x *genRunner) tryGenIsZero(t reflect.Type) (done bool) {
673
	if t.Kind() != reflect.Struct || t.Implements(isCodecEmptyerTyp) {
674
		return
675
	}
676

677
	rtid := rt2id(t)
678

679
	if _, ok := x.tz[rtid]; ok {
680
		delete(x.ty, t)
681
		return
682
	}
683

684
	x.tz[rtid] = true
685
	delete(x.ty, t)
686

687
	ti := x.ti.get(rtid, t)
688
	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
689
	varname := genTopLevelVarName
690

691
	x.linef("func (%s *%s) IsCodecEmpty() bool {", varname, x.genTypeName(t))
692

693
	anonSeen := make(map[reflect.Type]bool)
694
	var omitline genBuf
695
	for _, si := range tisfi {
696
		if si.path.parent != nil {
697
			root := si.path.root()
698
			if anonSeen[root.typ] {
699
				continue
700
			}
701
			anonSeen[root.typ] = true
702
		}
703
		t2 := genOmitEmptyLinePreChecks(varname, t, si, &omitline, true)
704
		// if Ptr, we already checked if nil above
705
		if t2.Type.Kind() != reflect.Ptr {
706
			x.doEncOmitEmptyLine(t2, varname, &omitline)
707
			omitline.s(" || ")
708
		}
709
	}
710
	omitline.s(" false")
711
	x.linef("return !(%s)", omitline.v())
712

713
	x.line("}")
714
	x.line("")
715
	return true
716
}
717

718
func (x *genRunner) selfer(encode bool) {
719
	t := x.tc
720
	// ti := x.ti.get(rt2id(t), t)
721
	t0 := t
722
	// always make decode use a pointer receiver,
723
	// and structs/arrays always use a ptr receiver (encode|decode)
724
	isptr := !encode || t.Kind() == reflect.Array || (t.Kind() == reflect.Struct && t != timeTyp)
725
	x.varsfxreset()
726

727
	fnSigPfx := "func (" + genTopLevelVarName + " "
728
	if isptr {
729
		fnSigPfx += "*"
730
	}
731
	fnSigPfx += x.genTypeName(t)
732
	x.out(fnSigPfx)
733

734
	if isptr {
735
		t = reflect.PtrTo(t)
736
	}
737
	if encode {
738
		x.line(") CodecEncodeSelf(e *" + x.cpfx + "Encoder) {")
739
		x.genRequiredMethodVars(true)
740
		if t0.Kind() == reflect.Struct {
741
			x.linef("if z.EncBasicHandle().CheckCircularRef { z.EncEncode(%s); return }", genTopLevelVarName)
742
		}
743
		x.encVar(genTopLevelVarName, t)
744
	} else {
745
		x.line(") CodecDecodeSelf(d *" + x.cpfx + "Decoder) {")
746
		x.genRequiredMethodVars(false)
747
		// do not use decVar, as there is no need to check TryDecodeAsNil
748
		// or way to elegantly handle that, and also setting it to a
749
		// non-nil value doesn't affect the pointer passed.
750
		// x.decVar(genTopLevelVarName, t, false)
751
		x.dec(genTopLevelVarName, t0, true)
752
	}
753
	x.line("}")
754
	x.line("")
755

756
	if encode || t0.Kind() != reflect.Struct {
757
		return
758
	}
759

760
	// write is containerMap
761
	x.out(fnSigPfx)
762
	x.line(") codecDecodeSelfFromMap(l int, d *" + x.cpfx + "Decoder) {")
763
	x.genRequiredMethodVars(false)
764
	x.decStructMap(genTopLevelVarName, "l", rt2id(t0), t0)
765
	x.line("}")
766
	x.line("")
767

768
	// write containerArray
769
	x.out(fnSigPfx)
770
	x.line(") codecDecodeSelfFromArray(l int, d *" + x.cpfx + "Decoder) {")
771
	x.genRequiredMethodVars(false)
772
	x.decStructArray(genTopLevelVarName, "l", "return", rt2id(t0), t0)
773
	x.line("}")
774
	x.line("")
775

776
}
777

778
// used for chan, array, slice, map
779
func (x *genRunner) xtraSM(varname string, t reflect.Type, ti *typeInfo, encode, isptr bool) {
780
	var ptrPfx, addrPfx string
781
	if isptr {
782
		ptrPfx = "*"
783
	} else {
784
		addrPfx = "&"
785
	}
786
	if encode {
787
		x.linef("h.enc%s((%s%s)(%s), e)", x.genMethodNameT(t), ptrPfx, x.genTypeName(t), varname)
788
	} else {
789
		x.linef("h.dec%s((*%s)(%s%s), d)", x.genMethodNameT(t), x.genTypeName(t), addrPfx, varname)
790
	}
791
	x.registerXtraT(t, ti)
792
}
793

794
func (x *genRunner) registerXtraT(t reflect.Type, ti *typeInfo) {
795
	// recursively register the types
796
	tk := t.Kind()
797
	if tk == reflect.Ptr {
798
		x.registerXtraT(t.Elem(), nil)
799
		return
800
	}
801
	if _, ok := x.tm[t]; ok {
802
		return
803
	}
804

805
	switch tk {
806
	case reflect.Chan, reflect.Slice, reflect.Array, reflect.Map:
807
	default:
808
		return
809
	}
810
	// only register the type if it will not default to a fast-path
811
	if ti == nil {
812
		ti = x.ti.get(rt2id(t), t)
813
	}
814
	if _, rtidu := genFastpathUnderlying(t, ti.rtid, ti); fastpathAvIndex(rtidu) != -1 {
815
		return
816
	}
817
	x.tm[t] = struct{}{}
818
	x.ts = append(x.ts, t)
819
	// check if this refers to any xtra types eg. a slice of array: add the array
820
	x.registerXtraT(t.Elem(), nil)
821
	if tk == reflect.Map {
822
		x.registerXtraT(t.Key(), nil)
823
	}
824
}
825

826
// encVar will encode a variable.
827
// The parameter, t, is the reflect.Type of the variable itself
828
func (x *genRunner) encVar(varname string, t reflect.Type) {
829
	var checkNil bool
830
	// case reflect.Ptr, reflect.Interface, reflect.Slice, reflect.Map, reflect.Chan:
831
	// do not include checkNil for slice and maps, as we already checkNil below it
832
	switch t.Kind() {
833
	case reflect.Ptr, reflect.Interface, reflect.Chan:
834
		checkNil = true
835
	}
836
	x.encVarChkNil(varname, t, checkNil)
837
}
838

839
func (x *genRunner) encVarChkNil(varname string, t reflect.Type, checkNil bool) {
840
	if checkNil {
841
		x.linef("if %s == nil { r.EncodeNil() } else {", varname)
842
	}
843

844
	switch t.Kind() {
845
	case reflect.Ptr:
846
		telem := t.Elem()
847
		tek := telem.Kind()
848
		if tek == reflect.Array || (tek == reflect.Struct && telem != timeTyp) {
849
			x.enc(varname, genNonPtr(t), true)
850
			break
851
		}
852
		i := x.varsfx()
853
		x.line(genTempVarPfx + i + " := *" + varname)
854
		x.enc(genTempVarPfx+i, genNonPtr(t), false)
855
	case reflect.Struct, reflect.Array:
856
		if t == timeTyp {
857
			x.enc(varname, t, false)
858
			break
859
		}
860
		i := x.varsfx()
861
		x.line(genTempVarPfx + i + " := &" + varname)
862
		x.enc(genTempVarPfx+i, t, true)
863
	default:
864
		x.enc(varname, t, false)
865
	}
866

867
	if checkNil {
868
		x.line("}")
869
	}
870
}
871

872
// enc will encode a variable (varname) of type t, where t represents T.
873
// if t is !time.Time and t is of kind reflect.Struct or reflect.Array, varname is of type *T
874
// (to prevent copying),
875
// else t is of type T
876
func (x *genRunner) enc(varname string, t reflect.Type, isptr bool) {
877
	rtid := rt2id(t)
878
	ti2 := x.ti.get(rtid, t)
879
	// We call CodecEncodeSelf if one of the following are honored:
880
	//   - the type already implements Selfer, call that
881
	//   - the type has a Selfer implementation just created, use that
882
	//   - the type is in the list of the ones we will generate for, but it is not currently being generated
883

884
	mi := x.varsfx()
885
	// tptr := reflect.PtrTo(t)
886
	// tk := t.Kind()
887

888
	// check if
889
	//   - type is time.Time, RawExt, Raw
890
	//   - the type implements (Text|JSON|Binary)(Unm|M)arshal
891

892
	var hasIf genIfClause
893
	defer hasIf.end(x) // end if block (if necessary)
894

895
	var ptrPfx, addrPfx string
896
	if isptr {
897
		ptrPfx = "*"
898
	} else {
899
		addrPfx = "&"
900
	}
901

902
	if t == timeTyp {
903
		x.linef("%s z.EncBasicHandle().TimeBuiltin() { r.EncodeTime(%s%s)", hasIf.c(false), ptrPfx, varname)
904
		// return
905
	}
906
	if t == rawTyp {
907
		x.linef("%s z.EncRaw(%s%s)", hasIf.c(true), ptrPfx, varname)
908
		return
909
	}
910
	if t == rawExtTyp {
911
		x.linef("%s r.EncodeRawExt(%s%s)", hasIf.c(true), addrPfx, varname)
912
		return
913
	}
914
	// only check for extensions if extensions are configured,
915
	// and the type is named, and has a packagePath,
916
	// and this is not the CodecEncodeSelf or CodecDecodeSelf method (i.e. it is not a Selfer)
917
	if !x.nx && varname != genTopLevelVarName && t != genStringDecAsBytesTyp &&
918
		t != genStringDecZCTyp && genImportPath(t) != "" && t.Name() != "" {
919
		yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi)
920
		x.linef("%s %s := z.Extension(%s); %s != nil { z.EncExtension(%s, %s) ",
921
			hasIf.c(false), yy, varname, yy, varname, yy)
922
	}
923

924
	if x.checkForSelfer(t, varname) {
925
		if ti2.flagSelfer {
926
			x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
927
			return
928
		}
929
		if ti2.flagSelferPtr {
930
			if isptr {
931
				x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
932
			} else {
933
				x.linef("%s %ssf%s := &%s", hasIf.c(true), genTempVarPfx, mi, varname)
934
				x.linef("%ssf%s.CodecEncodeSelf(e)", genTempVarPfx, mi)
935
			}
936
			return
937
		}
938

939
		if _, ok := x.te[rtid]; ok {
940
			x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
941
			return
942
		}
943
	}
944

945
	inlist := false
946
	for _, t0 := range x.t {
947
		if t == t0 {
948
			inlist = true
949
			if x.checkForSelfer(t, varname) {
950
				x.linef("%s %s.CodecEncodeSelf(e)", hasIf.c(true), varname)
951
				return
952
			}
953
			break
954
		}
955
	}
956

957
	var rtidAdded bool
958
	if t == x.tc {
959
		x.te[rtid] = true
960
		rtidAdded = true
961
	}
962

963
	if ti2.flagBinaryMarshaler {
964
		x.linef("%s z.EncBinary() { z.EncBinaryMarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
965
	} else if ti2.flagBinaryMarshalerPtr {
966
		x.linef("%s z.EncBinary() { z.EncBinaryMarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
967
	}
968

969
	if ti2.flagJsonMarshaler {
970
		x.linef("%s !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
971
	} else if ti2.flagJsonMarshalerPtr {
972
		x.linef("%s !z.EncBinary() && z.IsJSONHandle() { z.EncJSONMarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
973
	} else if ti2.flagTextMarshaler {
974
		x.linef("%s !z.EncBinary() { z.EncTextMarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
975
	} else if ti2.flagTextMarshalerPtr {
976
		x.linef("%s !z.EncBinary() { z.EncTextMarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
977
	}
978

979
	x.lineIf(hasIf.c(true))
980

981
	switch t.Kind() {
982
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
983
		x.line("r.EncodeInt(int64(" + varname + "))")
984
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
985
		x.line("r.EncodeUint(uint64(" + varname + "))")
986
	case reflect.Float32:
987
		x.line("r.EncodeFloat32(float32(" + varname + "))")
988
	case reflect.Float64:
989
		x.line("r.EncodeFloat64(float64(" + varname + "))")
990
	case reflect.Complex64:
991
		x.linef("z.EncEncodeComplex64(complex64(%s))", varname)
992
	case reflect.Complex128:
993
		x.linef("z.EncEncodeComplex128(complex128(%s))", varname)
994
	case reflect.Bool:
995
		x.line("r.EncodeBool(bool(" + varname + "))")
996
	case reflect.String:
997
		x.linef("r.EncodeString(string(%s))", varname)
998
	case reflect.Chan:
999
		x.xtraSM(varname, t, ti2, true, false)
1000
		// x.encListFallback(varname, rtid, t)
1001
	case reflect.Array:
1002
		_, rtidu := genFastpathUnderlying(t, rtid, ti2)
1003
		if fastpathAvIndex(rtidu) != -1 {
1004
			g := x.newFastpathGenV(ti2.key)
1005
			x.linef("z.F.%sV((%s)(%s[:]), e)", g.MethodNamePfx("Enc", false), x.genTypeName(ti2.key), varname)
1006
		} else {
1007
			x.xtraSM(varname, t, ti2, true, true)
1008
		}
1009
	case reflect.Slice:
1010
		// if nil, call dedicated function
1011
		// if a []byte, call dedicated function
1012
		// if a known fastpath slice, call dedicated function
1013
		// else write encode function in-line.
1014
		// - if elements are primitives or Selfers, call dedicated function on each member.
1015
		// - else call Encoder.encode(XXX) on it.
1016

1017
		x.linef("if %s == nil { r.EncodeNil() } else {", varname)
1018
		if rtid == uint8SliceTypId {
1019
			x.line("r.EncodeStringBytesRaw([]byte(" + varname + "))")
1020
		} else {
1021
			tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
1022
			if fastpathAvIndex(rtidu) != -1 {
1023
				g := x.newFastpathGenV(tu)
1024
				if rtid == rtidu {
1025
					x.linef("z.F.%sV(%s, e)", g.MethodNamePfx("Enc", false), varname)
1026
				} else {
1027
					x.linef("z.F.%sV((%s)(%s), e)", g.MethodNamePfx("Enc", false), x.genTypeName(tu), varname)
1028
				}
1029
			} else {
1030
				x.xtraSM(varname, t, ti2, true, false)
1031
			}
1032
		}
1033
		x.linef("} // end block: if %s slice == nil", varname)
1034
	case reflect.Map:
1035
		// if nil, call dedicated function
1036
		// if a known fastpath map, call dedicated function
1037
		// else write encode function in-line.
1038
		// - if elements are primitives or Selfers, call dedicated function on each member.
1039
		// - else call Encoder.encode(XXX) on it.
1040
		x.linef("if %s == nil { r.EncodeNil() } else {", varname)
1041
		tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
1042
		if fastpathAvIndex(rtidu) != -1 {
1043
			g := x.newFastpathGenV(tu)
1044
			if rtid == rtidu {
1045
				x.linef("z.F.%sV(%s, e)", g.MethodNamePfx("Enc", false), varname)
1046
			} else {
1047
				x.linef("z.F.%sV((%s)(%s), e)", g.MethodNamePfx("Enc", false), x.genTypeName(tu), varname)
1048
			}
1049
		} else {
1050
			x.xtraSM(varname, t, ti2, true, false)
1051
		}
1052
		x.linef("} // end block: if %s map == nil", varname)
1053
	case reflect.Struct:
1054
		if !inlist {
1055
			delete(x.te, rtid)
1056
			x.line("z.EncFallback(" + varname + ")")
1057
			break
1058
		}
1059
		x.encStruct(varname, rtid, t)
1060
	default:
1061
		if rtidAdded {
1062
			delete(x.te, rtid)
1063
		}
1064
		x.line("z.EncFallback(" + varname + ")")
1065
	}
1066
}
1067

1068
func (x *genRunner) encZero(t reflect.Type) {
1069
	switch t.Kind() {
1070
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1071
		x.line("r.EncodeInt(0)")
1072
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
1073
		x.line("r.EncodeUint(0)")
1074
	case reflect.Float32:
1075
		x.line("r.EncodeFloat32(0)")
1076
	case reflect.Float64:
1077
		x.line("r.EncodeFloat64(0)")
1078
	case reflect.Complex64:
1079
		x.line("z.EncEncodeComplex64(0)")
1080
	case reflect.Complex128:
1081
		x.line("z.EncEncodeComplex128(0)")
1082
	case reflect.Bool:
1083
		x.line("r.EncodeBool(false)")
1084
	case reflect.String:
1085
		x.linef(`r.EncodeString("")`)
1086
	default:
1087
		x.line("r.EncodeNil()")
1088
	}
1089
}
1090

1091
func genOmitEmptyLinePreChecks(varname string, t reflect.Type, si *structFieldInfo, omitline *genBuf, oneLevel bool) (t2 reflect.StructField) {
1092
	// xdebug2f("calling genOmitEmptyLinePreChecks on: %v", t)
1093
	t2typ := t
1094
	varname3 := varname
1095
	// go through the loop, record the t2 field explicitly,
1096
	// and gather the omit line if embedded in pointers.
1097
	fullpath := si.path.fullpath()
1098
	for i, path := range fullpath {
1099
		for t2typ.Kind() == reflect.Ptr {
1100
			t2typ = t2typ.Elem()
1101
		}
1102
		t2 = t2typ.Field(int(path.index))
1103
		t2typ = t2.Type
1104
		varname3 = varname3 + "." + t2.Name
1105
		// do not include actual field in the omit line.
1106
		// that is done subsequently (right after - below).
1107
		if i+1 < len(fullpath) && t2typ.Kind() == reflect.Ptr {
1108
			omitline.s(varname3).s(" != nil && ")
1109
		}
1110
		if oneLevel {
1111
			break
1112
		}
1113
	}
1114
	return
1115
}
1116

1117
func (x *genRunner) doEncOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) {
1118
	x.f = 0
1119
	x.encOmitEmptyLine(t2, varname, buf)
1120
}
1121

1122
func (x *genRunner) encOmitEmptyLine(t2 reflect.StructField, varname string, buf *genBuf) {
1123
	// xdebugf("calling encOmitEmptyLine on: %v", t2.Type)
1124
	// smartly check omitEmpty on a struct type, as it may contain uncomparable map/slice/etc.
1125
	// also, for maps/slices, check if len ! 0 (not if == zero value)
1126
	varname2 := varname + "." + t2.Name
1127
	switch t2.Type.Kind() {
1128
	case reflect.Struct:
1129
		rtid2 := rt2id(t2.Type)
1130
		ti2 := x.ti.get(rtid2, t2.Type)
1131
		// xdebugf(">>>> structfield: omitempty: type: %s, field: %s\n", t2.Type.Name(), t2.Name)
1132
		if ti2.rtid == timeTypId {
1133
			buf.s("!(").s(varname2).s(".IsZero())")
1134
			break
1135
		}
1136
		if ti2.flagIsZeroerPtr || ti2.flagIsZeroer {
1137
			buf.s("!(").s(varname2).s(".IsZero())")
1138
			break
1139
		}
1140
		if t2.Type.Implements(isCodecEmptyerTyp) {
1141
			buf.s("!(").s(varname2).s(".IsCodecEmpty())")
1142
			break
1143
		}
1144
		_, ok := x.tz[rtid2]
1145
		if ok {
1146
			buf.s("!(").s(varname2).s(".IsCodecEmpty())")
1147
			break
1148
		}
1149
		// if we *should* create a IsCodecEmpty for it, but haven't yet, add it here
1150
		// _, ok = x.ty[rtid2]
1151
		if genImportPath(t2.Type) == x.bp {
1152
			x.ty[t2.Type] = struct{}{}
1153
			buf.s("!(").s(varname2).s(".IsCodecEmpty())")
1154
			break
1155
		}
1156
		if ti2.flagComparable {
1157
			buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
1158
			break
1159
		}
1160
		// buf.s("(")
1161
		buf.s(x.sayFalse()) // buf.s("false")
1162
		var wrote bool
1163
		for i, n := 0, t2.Type.NumField(); i < n; i++ {
1164
			f := t2.Type.Field(i)
1165
			if f.PkgPath != "" { // unexported
1166
				continue
1167
			}
1168
			buf.s(" || ")
1169
			x.encOmitEmptyLine(f, varname2, buf)
1170
			wrote = true
1171
		}
1172
		if !wrote {
1173
			buf.s(" || ").s(x.sayTrue())
1174
		}
1175
		//buf.s(")")
1176
	case reflect.Bool:
1177
		buf.s("bool(").s(varname2).s(")")
1178
	case reflect.Map, reflect.Slice, reflect.Chan:
1179
		buf.s("len(").s(varname2).s(") != 0")
1180
	case reflect.Array:
1181
		tlen := t2.Type.Len()
1182
		if tlen == 0 {
1183
			buf.s(x.sayFalse())
1184
		} else if t2.Type.Comparable() {
1185
			buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
1186
		} else { // then we cannot even compare the individual values
1187
			// TODO use playground to check if you can compare to a
1188
			// zero value of an array, even if array not comparable.
1189
			buf.s(x.sayTrue())
1190
		}
1191
	default:
1192
		buf.s(varname2).s(" != ").s(x.genZeroValueR(t2.Type))
1193
	}
1194
}
1195

1196
func (x *genRunner) encStruct(varname string, rtid uintptr, t reflect.Type) {
1197
	// Use knowledge from structfieldinfo (mbs, encodable fields. Ignore omitempty. )
1198
	// replicate code in kStruct i.e. for each field, deref type to non-pointer, and call x.enc on it
1199

1200
	// if t === type currently running selfer on, do for all
1201
	ti := x.ti.get(rtid, t)
1202
	i := x.varsfx()
1203
	// sepVarname := genTempVarPfx + "sep" + i
1204
	numfieldsvar := genTempVarPfx + "q" + i
1205
	ti2arrayvar := genTempVarPfx + "r" + i
1206
	struct2arrvar := genTempVarPfx + "2arr" + i
1207

1208
	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
1209

1210
	type genFQN struct {
1211
		i       string
1212
		fqname  string
1213
		nilLine genBuf
1214
		nilVar  string
1215
		canNil  bool
1216
		sf      reflect.StructField
1217
	}
1218

1219
	genFQNs := make([]genFQN, len(tisfi))
1220
	si2Pos := make(map[*structFieldInfo]int) // stores position in sorted structFieldInfos
1221

1222
	for j, si := range tisfi {
1223
		si2Pos[si] = j
1224
		q := &genFQNs[j]
1225
		q.i = x.varsfx()
1226
		q.nilVar = genTempVarPfx + "n" + q.i
1227
		q.canNil = false
1228
		q.fqname = varname
1229
		{
1230
			t2typ := t
1231
			fullpath := si.path.fullpath()
1232
			for _, path := range fullpath {
1233
				for t2typ.Kind() == reflect.Ptr {
1234
					t2typ = t2typ.Elem()
1235
				}
1236
				q.sf = t2typ.Field(int(path.index))
1237
				t2typ = q.sf.Type
1238
				q.fqname += "." + q.sf.Name
1239
				if t2typ.Kind() == reflect.Ptr {
1240
					if !q.canNil {
1241
						q.nilLine.f("%s == nil", q.fqname)
1242
						q.canNil = true
1243
					} else {
1244
						q.nilLine.f(" || %s == nil", q.fqname)
1245
					}
1246
				}
1247
			}
1248
		}
1249
	}
1250

1251
	// x.line(sepVarname + " := !z.EncBinary()")
1252
	x.linef("%s := z.EncBasicHandle().StructToArray", struct2arrvar)
1253
	// x.linef("_, _ = %s, %s", sepVarname, struct2arrvar)
1254
	x.linef("_ = %s", struct2arrvar)
1255
	x.linef("const %s bool = %v // struct tag has 'toArray'", ti2arrayvar, ti.toArray)
1256

1257
	for j := range genFQNs {
1258
		q := &genFQNs[j]
1259
		if q.canNil {
1260
			x.linef("var %s bool = %s", q.nilVar, q.nilLine.v())
1261
		}
1262
	}
1263

1264
	// var nn int
1265
	// due to omitEmpty, we need to calculate the
1266
	// number of non-empty things we write out first.
1267
	// This is required as we need to pre-determine the size of the container,
1268
	// to support length-prefixing.
1269
	omitEmptySometimes := x.omitEmptyWhen == nil
1270
	omitEmptyAlways := (x.omitEmptyWhen != nil && *(x.omitEmptyWhen))
1271
	// omitEmptyNever := (x.omitEmptyWhen != nil && !*(x.omitEmptyWhen))
1272

1273
	toArraySometimes := x.toArrayWhen == nil
1274
	toArrayAlways := (x.toArrayWhen != nil && *(x.toArrayWhen))
1275
	toArrayNever := (x.toArrayWhen != nil && !(*(x.toArrayWhen)))
1276

1277
	if (omitEmptySometimes && ti.anyOmitEmpty) || omitEmptyAlways {
1278
		x.linef("var %s = [%v]bool{ // should field at this index be written?", numfieldsvar, len(tisfi))
1279

1280
		for _, si := range tisfi {
1281
			if omitEmptySometimes && !si.path.omitEmpty {
1282
				x.linef("true, // %s", si.encName) // si.fieldName)
1283
				continue
1284
			}
1285
			var omitline genBuf
1286
			t2 := genOmitEmptyLinePreChecks(varname, t, si, &omitline, false)
1287
			x.doEncOmitEmptyLine(t2, varname, &omitline)
1288
			x.linef("%s, // %s", omitline.v(), si.encName) // si.fieldName)
1289
		}
1290
		x.line("}")
1291
		x.linef("_ = %s", numfieldsvar)
1292
	}
1293

1294
	if toArraySometimes {
1295
		x.linef("if %s || %s {", ti2arrayvar, struct2arrvar) // if ti.toArray
1296
	}
1297
	if toArraySometimes || toArrayAlways {
1298
		x.linef("z.EncWriteArrayStart(%d)", len(tisfi))
1299

1300
		for j, si := range tisfi {
1301
			doOmitEmptyCheck := (omitEmptySometimes && si.path.omitEmpty) || omitEmptyAlways
1302
			q := &genFQNs[j]
1303
			// if the type of the field is a Selfer, or one of the ones
1304
			if q.canNil {
1305
				x.linef("if %s { z.EncWriteArrayElem(); r.EncodeNil() } else { ", q.nilVar)
1306
			}
1307
			x.linef("z.EncWriteArrayElem()")
1308
			if doOmitEmptyCheck {
1309
				x.linef("if %s[%v] {", numfieldsvar, j)
1310
			}
1311
			x.encVarChkNil(q.fqname, q.sf.Type, false)
1312
			if doOmitEmptyCheck {
1313
				x.linef("} else {")
1314
				x.encZero(q.sf.Type)
1315
				x.linef("}")
1316
			}
1317
			if q.canNil {
1318
				x.line("}")
1319
			}
1320
		}
1321

1322
		x.line("z.EncWriteArrayEnd()")
1323
	}
1324
	if toArraySometimes {
1325
		x.linef("} else {") // if not ti.toArray
1326
	}
1327
	if toArraySometimes || toArrayNever {
1328
		if (omitEmptySometimes && ti.anyOmitEmpty) || omitEmptyAlways {
1329
			x.linef("var %snn%s int", genTempVarPfx, i)
1330
			x.linef("for _, b := range %s { if b { %snn%s++ } }", numfieldsvar, genTempVarPfx, i)
1331
			x.linef("z.EncWriteMapStart(%snn%s)", genTempVarPfx, i)
1332
			x.linef("%snn%s = %v", genTempVarPfx, i, 0)
1333
		} else {
1334
			x.linef("z.EncWriteMapStart(%d)", len(tisfi))
1335
		}
1336

1337
		fn := func(tisfi []*structFieldInfo) {
1338
			// tisfi here may be source or sorted, so use the src position stored elsewhere
1339
			for _, si := range tisfi {
1340
				pos := si2Pos[si]
1341
				q := &genFQNs[pos]
1342
				doOmitEmptyCheck := (omitEmptySometimes && si.path.omitEmpty) || omitEmptyAlways
1343
				if doOmitEmptyCheck {
1344
					x.linef("if %s[%v] {", numfieldsvar, pos)
1345
				}
1346
				x.linef("z.EncWriteMapElemKey()")
1347

1348
				// emulate EncStructFieldKey
1349
				switch ti.keyType {
1350
				case valueTypeInt:
1351
					x.linef("r.EncodeInt(z.M.Int(strconv.ParseInt(`%s`, 10, 64)))", si.encName)
1352
				case valueTypeUint:
1353
					x.linef("r.EncodeUint(z.M.Uint(strconv.ParseUint(`%s`, 10, 64)))", si.encName)
1354
				case valueTypeFloat:
1355
					x.linef("r.EncodeFloat64(z.M.Float(strconv.ParseFloat(`%s`, 64)))", si.encName)
1356
				default: // string
1357
					if x.jsonOnlyWhen == nil {
1358
						if si.path.encNameAsciiAlphaNum {
1359
							x.linef(`if z.IsJSONHandle() { z.EncWr().WriteStr("\"%s\"") } else { `, si.encName)
1360
						}
1361
						x.linef("r.EncodeString(`%s`)", si.encName)
1362
						if si.path.encNameAsciiAlphaNum {
1363
							x.linef("}")
1364
						}
1365
					} else if *(x.jsonOnlyWhen) {
1366
						if si.path.encNameAsciiAlphaNum {
1367
							x.linef(`z.EncWr().WriteStr("\"%s\"")`, si.encName)
1368
						} else {
1369
							x.linef("r.EncodeString(`%s`)", si.encName)
1370
						}
1371
					} else {
1372
						x.linef("r.EncodeString(`%s`)", si.encName)
1373
					}
1374
				}
1375
				x.line("z.EncWriteMapElemValue()")
1376
				if q.canNil {
1377
					x.line("if " + q.nilVar + " { r.EncodeNil() } else { ")
1378
					x.encVarChkNil(q.fqname, q.sf.Type, false)
1379
					x.line("}")
1380
				} else {
1381
					x.encVarChkNil(q.fqname, q.sf.Type, false)
1382
				}
1383
				if doOmitEmptyCheck {
1384
					x.line("}")
1385
				}
1386
			}
1387
		}
1388

1389
		if genStructCanonical {
1390
			x.linef("if z.EncBasicHandle().Canonical {") // if Canonical block
1391
			fn(ti.sfi.sorted())
1392
			x.linef("} else {") // else !Canonical block
1393
			fn(ti.sfi.source())
1394
			x.linef("}") // end if Canonical block
1395
		} else {
1396
			fn(tisfi)
1397
		}
1398

1399
		x.line("z.EncWriteMapEnd()")
1400
	}
1401
	if toArraySometimes {
1402
		x.linef("} ") // end if/else ti.toArray
1403
	}
1404
}
1405

1406
func (x *genRunner) encListFallback(varname string, t reflect.Type) {
1407
	x.linef("if %s == nil { r.EncodeNil(); return }", varname)
1408
	elemBytes := t.Elem().Kind() == reflect.Uint8
1409
	if t.AssignableTo(uint8SliceTyp) {
1410
		x.linef("r.EncodeStringBytesRaw([]byte(%s))", varname)
1411
		return
1412
	}
1413
	if t.Kind() == reflect.Array && elemBytes {
1414
		x.linef("r.EncodeStringBytesRaw(((*[%d]byte)(%s))[:])", t.Len(), varname)
1415
		return
1416
	}
1417
	i := x.varsfx()
1418
	if t.Kind() == reflect.Chan {
1419
		type ts struct {
1420
			Label, Chan, Slice, Sfx string
1421
		}
1422
		tm, err := template.New("").Parse(genEncChanTmpl)
1423
		genCheckErr(err)
1424
		x.linef("if %s == nil { r.EncodeNil() } else { ", varname)
1425
		x.linef("var sch%s []%s", i, x.genTypeName(t.Elem()))
1426
		err = tm.Execute(x.w, &ts{"Lsch" + i, varname, "sch" + i, i})
1427
		genCheckErr(err)
1428
		if elemBytes {
1429
			x.linef("r.EncodeStringBytesRaw([]byte(%s))", "sch"+i)
1430
			x.line("}")
1431
			return
1432
		}
1433
		varname = "sch" + i
1434
	}
1435

1436
	x.line("z.EncWriteArrayStart(len(" + varname + "))")
1437

1438
	// x.linef("for _, %sv%s := range %s {", genTempVarPfx, i, varname)
1439
	// x.linef("z.EncWriteArrayElem()")
1440
	// x.encVar(genTempVarPfx+"v"+i, t.Elem())
1441
	// x.line("}")
1442

1443
	x.linef("for %sv%s := range %s {", genTempVarPfx, i, varname)
1444
	x.linef("z.EncWriteArrayElem()")
1445
	x.encVar(fmt.Sprintf("%s[%sv%s]", varname, genTempVarPfx, i), t.Elem())
1446
	x.line("}")
1447

1448
	x.line("z.EncWriteArrayEnd()")
1449
	if t.Kind() == reflect.Chan {
1450
		x.line("}")
1451
	}
1452
}
1453

1454
func (x *genRunner) encMapFallback(varname string, t reflect.Type) {
1455
	x.linef("if %s == nil { r.EncodeNil()", varname)
1456
	x.line("} else if z.EncBasicHandle().Canonical {")
1457

1458
	// Solve for easy case accomodated by sort package without reflection i.e.
1459
	// map keys of type: float, int, string (pre-defined/builtin types).
1460
	//
1461
	// To do this, we will get the keys into an array of uint64|float64|string,
1462
	// sort them, then write them out, and grab the value and encode it appropriately
1463
	tkey := t.Key()
1464
	tkind := tkey.Kind()
1465
	// tkeybase := tkey
1466
	// for tkeybase.Kind() == reflect.Ptr {
1467
	// 	tkeybase = tkeybase.Elem()
1468
	// }
1469
	// tikey := x.ti.get(rt2id(tkeybase), tkeybase)
1470

1471
	// pre-defined types have a name and no pkgpath and appropriate kind
1472
	predeclared := tkey.PkgPath() == "" && tkey.Name() != ""
1473

1474
	canonSortKind := reflect.Invalid
1475
	switch tkind {
1476
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
1477
		canonSortKind = reflect.Int64
1478
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
1479
		canonSortKind = reflect.Uint64
1480
	case reflect.Float32, reflect.Float64:
1481
		canonSortKind = reflect.Float64
1482
	case reflect.String:
1483
		canonSortKind = reflect.String
1484
	}
1485

1486
	var i string = x.varsfx()
1487

1488
	fnCanonNumBoolStrKind := func() {
1489
		if !predeclared {
1490
			x.linef("var %svv%s %s", genTempVarPfx, i, x.genTypeName(tkey))
1491
			x.linef("%sencfn%s := z.EncFnGivenAddr(&%svv%s)", genTempVarPfx, i, genTempVarPfx, i)
1492
		}
1493
		// get the type, get the slice type its mapped to, and complete the code
1494
		x.linef("%ss%s := make([]%s, 0, len(%s))", genTempVarPfx, i, canonSortKind, varname)
1495
		x.linef("for k, _ := range %s {", varname)
1496
		x.linef("  %ss%s = append(%ss%s, %s(k))", genTempVarPfx, i, genTempVarPfx, i, canonSortKind)
1497
		x.linef("}")
1498
		x.linef("sort.Sort(%s%sSlice(%ss%s))", x.hn, canonSortKind, genTempVarPfx, i)
1499
		x.linef("z.EncWriteMapStart(len(%s))", varname)
1500
		x.linef("for _, %sv%s := range %ss%s {", genTempVarPfx, i, genTempVarPfx, i)
1501
		x.linef("  z.EncWriteMapElemKey()")
1502
		if predeclared {
1503
			switch tkind {
1504
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
1505
				x.linef("r.EncodeInt(int64(%sv%s))", genTempVarPfx, i)
1506
			case reflect.Int64:
1507
				x.linef("r.EncodeInt(%sv%s)", genTempVarPfx, i)
1508
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
1509
				x.linef("r.EncodeUint(%sv%s)", genTempVarPfx, i)
1510
			case reflect.Uint64:
1511
				x.linef("r.EncodeUint(uint64(%sv%s))", genTempVarPfx, i)
1512
			case reflect.Float32:
1513
				x.linef("r.EncodeFloat32(float32(%sv%s))", genTempVarPfx, i)
1514
			case reflect.Float64:
1515
				x.linef("r.EncodeFloat64(%sv%s)", genTempVarPfx, i)
1516
			case reflect.String:
1517
				x.linef("r.EncodeString(%sv%s)", genTempVarPfx, i)
1518
			}
1519
		} else {
1520
			x.linef("%svv%s = %s(%sv%s)", genTempVarPfx, i, x.genTypeName(tkey), genTempVarPfx, i)
1521
			x.linef("z.EncEncodeNumBoolStrKindGivenAddr(&%svv%s, %sencfn%s)", genTempVarPfx, i, genTempVarPfx, i)
1522
		}
1523
		x.linef("  z.EncWriteMapElemValue()")
1524
		vname := genTempVarPfx + "e" + i
1525
		if predeclared {
1526
			x.linef("%s := %s[%s(%sv%s)]", vname, varname, x.genTypeName(tkey), genTempVarPfx, i)
1527
		} else {
1528
			x.linef("%s := %s[%svv%s]", vname, varname, genTempVarPfx, i)
1529
		}
1530
		x.encVar(vname, t.Elem())
1531
		x.linef("}")
1532

1533
		x.line("z.EncWriteMapEnd()")
1534

1535
	}
1536

1537
	// if canonSortKind != reflect.Invalid && !tikey.flagMarshalInterface {
1538
	// 	if predeclared {
1539
	// 		fnCanonNumBoolStrKind()
1540
	// 	} else {
1541
	// 		// handle if an extension
1542
	// 		x.linef("if z.Extension(%s(%s)) != nil { z.EncEncodeMapNonNil(%s) } else {",
1543
	// 			x.genTypeName(tkey), x.genZeroValueR(tkey), varname)
1544
	// 		fnCanonNumBoolStrKind()
1545
	// 		x.line("}")
1546
	// 	}
1547
	// } else {
1548
	// 	x.linef("z.EncEncodeMapNonNil(%s)", varname)
1549
	// }
1550

1551
	if canonSortKind != reflect.Invalid {
1552
		fnCanonNumBoolStrKind()
1553
	} else {
1554
		x.linef("z.EncEncodeMapNonNil(%s)", varname)
1555
	}
1556

1557
	x.line("} else {")
1558

1559
	x.linef("z.EncWriteMapStart(len(%s))", varname)
1560
	x.linef("for %sk%s, %sv%s := range %s {", genTempVarPfx, i, genTempVarPfx, i, varname)
1561
	x.linef("z.EncWriteMapElemKey()")
1562
	x.encVar(genTempVarPfx+"k"+i, t.Key())
1563
	x.line("z.EncWriteMapElemValue()")
1564
	x.encVar(genTempVarPfx+"v"+i, t.Elem())
1565
	x.line("}")
1566
	x.line("z.EncWriteMapEnd()")
1567

1568
	x.line("}")
1569
}
1570

1571
func (x *genRunner) decVarInitPtr(varname, nilvar string, t reflect.Type, si *structFieldInfo,
1572
	newbuf, nilbuf *genBuf) (varname3 string, t2 reflect.StructField) {
1573
	//we must accommodate anonymous fields, where the embedded field is a nil pointer in the value.
1574
	// t2 = t.FieldByIndex(si.is)
1575
	varname3 = varname
1576
	t2typ := t
1577
	t2kind := t2typ.Kind()
1578
	var nilbufed bool
1579
	if si != nil {
1580
		fullpath := si.path.fullpath()
1581
		for _, path := range fullpath {
1582
			// only one-level pointers can be seen in a type
1583
			if t2typ.Kind() == reflect.Ptr {
1584
				t2typ = t2typ.Elem()
1585
			}
1586
			t2 = t2typ.Field(int(path.index))
1587
			t2typ = t2.Type
1588
			varname3 = varname3 + "." + t2.Name
1589
			t2kind = t2typ.Kind()
1590
			if t2kind != reflect.Ptr {
1591
				continue
1592
			}
1593
			if newbuf != nil {
1594
				if len(newbuf.buf) > 0 {
1595
					newbuf.s("\n")
1596
				}
1597
				newbuf.f("if %s == nil { %s = new(%s) }", varname3, varname3, x.genTypeName(t2typ.Elem()))
1598
			}
1599
			if nilbuf != nil {
1600
				if !nilbufed {
1601
					nilbuf.s("if ").s(varname3).s(" != nil")
1602
					nilbufed = true
1603
				} else {
1604
					nilbuf.s(" && ").s(varname3).s(" != nil")
1605
				}
1606
			}
1607
		}
1608
	}
1609
	if nilbuf != nil {
1610
		if nilbufed {
1611
			nilbuf.s(" { ").s("// remove the if-true\n")
1612
		}
1613
		if nilvar != "" {
1614
			nilbuf.s(nilvar).s(" = true")
1615
		} else if tk := t2typ.Kind(); tk == reflect.Ptr {
1616
			if strings.IndexByte(varname3, '.') != -1 || strings.IndexByte(varname3, '[') != -1 {
1617
				nilbuf.s(varname3).s(" = nil")
1618
			} else {
1619
				nilbuf.s("*").s(varname3).s(" = ").s(x.genZeroValueR(t2typ.Elem()))
1620
			}
1621
		} else {
1622
			nilbuf.s(varname3).s(" = ").s(x.genZeroValueR(t2typ))
1623
		}
1624
		if nilbufed {
1625
			nilbuf.s("}")
1626
		}
1627
	}
1628
	return
1629
}
1630

1631
// decVar takes a variable called varname, of type t
1632
func (x *genRunner) decVarMain(varname, rand string, t reflect.Type, checkNotNil bool) {
1633
	// We only encode as nil if a nillable value.
1634
	// This removes some of the wasted checks for TryDecodeAsNil.
1635
	// We need to think about this more, to see what happens if omitempty, etc
1636
	// cause a nil value to be stored when something is expected.
1637
	// This could happen when decoding from a struct encoded as an array.
1638
	// For that, decVar should be called with canNil=true, to force true as its value.
1639
	var varname2 string
1640
	if t.Kind() != reflect.Ptr {
1641
		if t.PkgPath() != "" || !x.decTryAssignPrimitive(varname, t, false) {
1642
			x.dec(varname, t, false)
1643
		}
1644
	} else {
1645
		if checkNotNil {
1646
			x.linef("if %s == nil { %s = new(%s) }", varname, varname, x.genTypeName(t.Elem()))
1647
		}
1648
		// Ensure we set underlying ptr to a non-nil value (so we can deref to it later).
1649
		// There's a chance of a **T in here which is nil.
1650
		var ptrPfx string
1651
		for t = t.Elem(); t.Kind() == reflect.Ptr; t = t.Elem() {
1652
			ptrPfx += "*"
1653
			if checkNotNil {
1654
				x.linef("if %s%s == nil { %s%s = new(%s)}", ptrPfx, varname, ptrPfx, varname, x.genTypeName(t))
1655
			}
1656
		}
1657
		// Should we create temp var if a slice/map indexing? No. dec(...) can now handle it.
1658

1659
		if ptrPfx == "" {
1660
			x.dec(varname, t, true)
1661
		} else {
1662
			varname2 = genTempVarPfx + "z" + rand
1663
			x.line(varname2 + " := " + ptrPfx + varname)
1664
			x.dec(varname2, t, true)
1665
		}
1666
	}
1667
}
1668

1669
// decVar takes a variable called varname, of type t
1670
func (x *genRunner) decVar(varname, nilvar string, t reflect.Type, canBeNil, checkNotNil bool) {
1671

1672
	// We only encode as nil if a nillable value.
1673
	// This removes some of the wasted checks for TryDecodeAsNil.
1674
	// We need to think about this more, to see what happens if omitempty, etc
1675
	// cause a nil value to be stored when something is expected.
1676
	// This could happen when decoding from a struct encoded as an array.
1677
	// For that, decVar should be called with canNil=true, to force true as its value.
1678

1679
	i := x.varsfx()
1680
	if t.Kind() == reflect.Ptr {
1681
		var buf genBuf
1682
		x.decVarInitPtr(varname, nilvar, t, nil, nil, &buf)
1683
		x.linef("if r.TryNil() { %s } else {", buf.buf)
1684
		x.decVarMain(varname, i, t, checkNotNil)
1685
		x.line("} ")
1686
	} else {
1687
		x.decVarMain(varname, i, t, checkNotNil)
1688
	}
1689
}
1690

1691
// dec will decode a variable (varname) of type t or ptrTo(t) if isptr==true.
1692
func (x *genRunner) dec(varname string, t reflect.Type, isptr bool) {
1693
	// assumptions:
1694
	//   - the varname is to a pointer already. No need to take address of it
1695
	//   - t is always a baseType T (not a *T, etc).
1696
	rtid := rt2id(t)
1697
	ti2 := x.ti.get(rtid, t)
1698

1699
	// check if
1700
	//   - type is time.Time, Raw, RawExt
1701
	//   - the type implements (Text|JSON|Binary)(Unm|M)arshal
1702

1703
	mi := x.varsfx()
1704

1705
	var hasIf genIfClause
1706
	defer hasIf.end(x)
1707

1708
	var ptrPfx, addrPfx string
1709
	if isptr {
1710
		ptrPfx = "*"
1711
	} else {
1712
		addrPfx = "&"
1713
	}
1714
	if t == timeTyp {
1715
		x.linef("%s z.DecBasicHandle().TimeBuiltin() { %s%v = r.DecodeTime()", hasIf.c(false), ptrPfx, varname)
1716
		// return
1717
	}
1718
	if t == rawTyp {
1719
		x.linef("%s %s%v = z.DecRaw()", hasIf.c(true), ptrPfx, varname)
1720
		return
1721
	}
1722

1723
	if t == rawExtTyp {
1724
		x.linef("%s r.DecodeExt(%s%v, 0, nil)", hasIf.c(true), addrPfx, varname)
1725
		return
1726
	}
1727

1728
	// only check for extensions if extensions are configured,
1729
	// and the type is named, and has a packagePath,
1730
	// and this is not the CodecEncodeSelf or CodecDecodeSelf method (i.e. it is not a Selfer)
1731
	// xdebugf("genRunner.dec: varname: %v, t: %v, genImportPath: %v, t.Name: %v", varname, t, genImportPath(t), t.Name())
1732
	if !x.nx && varname != genTopLevelVarName && t != genStringDecAsBytesTyp &&
1733
		t != genStringDecZCTyp && genImportPath(t) != "" && t.Name() != "" {
1734
		// first check if extensions are configued, before doing the interface conversion
1735
		yy := fmt.Sprintf("%sxt%s", genTempVarPfx, mi)
1736
		x.linef("%s %s := z.Extension(%s); %s != nil { z.DecExtension(%s%s, %s) ", hasIf.c(false), yy, varname, yy, addrPfx, varname, yy)
1737
	}
1738

1739
	if x.checkForSelfer(t, varname) {
1740
		if ti2.flagSelfer {
1741
			x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
1742
			return
1743
		}
1744
		if ti2.flagSelferPtr {
1745
			x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
1746
			return
1747
		}
1748
		if _, ok := x.td[rtid]; ok {
1749
			x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
1750
			return
1751
		}
1752
	}
1753

1754
	inlist := false
1755
	for _, t0 := range x.t {
1756
		if t == t0 {
1757
			inlist = true
1758
			if x.checkForSelfer(t, varname) {
1759
				x.linef("%s %s.CodecDecodeSelf(d)", hasIf.c(true), varname)
1760
				return
1761
			}
1762
			break
1763
		}
1764
	}
1765

1766
	var rtidAdded bool
1767
	if t == x.tc {
1768
		x.td[rtid] = true
1769
		rtidAdded = true
1770
	}
1771

1772
	if ti2.flagBinaryUnmarshaler {
1773
		x.linef("%s z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", hasIf.c(false), ptrPfx, varname)
1774
	} else if ti2.flagBinaryUnmarshalerPtr {
1775
		x.linef("%s z.DecBinary() { z.DecBinaryUnmarshal(%s%v) ", hasIf.c(false), addrPfx, varname)
1776
	}
1777
	if ti2.flagJsonUnmarshaler {
1778
		x.linef("%s !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", hasIf.c(false), ptrPfx, varname)
1779
	} else if ti2.flagJsonUnmarshalerPtr {
1780
		x.linef("%s !z.DecBinary() && z.IsJSONHandle() { z.DecJSONUnmarshal(%s%v)", hasIf.c(false), addrPfx, varname)
1781
	} else if ti2.flagTextUnmarshaler {
1782
		x.linef("%s !z.DecBinary() { z.DecTextUnmarshal(%s%v)", hasIf.c(false), ptrPfx, varname)
1783
	} else if ti2.flagTextUnmarshalerPtr {
1784
		x.linef("%s !z.DecBinary() { z.DecTextUnmarshal(%s%v)", hasIf.c(false), addrPfx, varname)
1785
	}
1786

1787
	x.lineIf(hasIf.c(true))
1788

1789
	if x.decTryAssignPrimitive(varname, t, isptr) {
1790
		return
1791
	}
1792

1793
	switch t.Kind() {
1794
	case reflect.Chan:
1795
		x.xtraSM(varname, t, ti2, false, isptr)
1796
	case reflect.Array:
1797
		_, rtidu := genFastpathUnderlying(t, rtid, ti2)
1798
		if fastpathAvIndex(rtidu) != -1 {
1799
			g := x.newFastpathGenV(ti2.key)
1800
			x.linef("z.F.%sN((%s)(%s[:]), d)", g.MethodNamePfx("Dec", false), x.genTypeName(ti2.key), varname)
1801
		} else {
1802
			x.xtraSM(varname, t, ti2, false, isptr)
1803
		}
1804
	case reflect.Slice:
1805
		// if a []byte, call dedicated function
1806
		// if a known fastpath slice, call dedicated function
1807
		// else write encode function in-line.
1808
		// - if elements are primitives or Selfers, call dedicated function on each member.
1809
		// - else call Encoder.encode(XXX) on it.
1810

1811
		if rtid == uint8SliceTypId {
1812
			x.linef("%s%s = z.DecodeBytesInto(%s(%s[]byte)(%s))", ptrPfx, varname, ptrPfx, ptrPfx, varname)
1813
		} else {
1814
			tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
1815
			if fastpathAvIndex(rtidu) != -1 {
1816
				g := x.newFastpathGenV(tu)
1817
				if rtid == rtidu {
1818
					x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
1819
				} else {
1820
					x.linef("z.F.%sX((*%s)(%s%s), d)", g.MethodNamePfx("Dec", false), x.genTypeName(tu), addrPfx, varname)
1821
				}
1822
			} else {
1823
				x.xtraSM(varname, t, ti2, false, isptr)
1824
				// x.decListFallback(varname, rtid, false, t)
1825
			}
1826
		}
1827
	case reflect.Map:
1828
		// if a known fastpath map, call dedicated function
1829
		// else write encode function in-line.
1830
		// - if elements are primitives or Selfers, call dedicated function on each member.
1831
		// - else call Encoder.encode(XXX) on it.
1832

1833
		tu, rtidu := genFastpathUnderlying(t, rtid, ti2)
1834
		if fastpathAvIndex(rtidu) != -1 {
1835
			g := x.newFastpathGenV(tu)
1836
			if rtid == rtidu {
1837
				x.linef("z.F.%sX(%s%s, d)", g.MethodNamePfx("Dec", false), addrPfx, varname)
1838
			} else {
1839
				x.linef("z.F.%sX((*%s)(%s%s), d)", g.MethodNamePfx("Dec", false), x.genTypeName(tu), addrPfx, varname)
1840
			}
1841
		} else {
1842
			x.xtraSM(varname, t, ti2, false, isptr)
1843
		}
1844
	case reflect.Struct:
1845
		if inlist {
1846
			// no need to create temp variable if isptr, or x.F or x[F]
1847
			if isptr || strings.IndexByte(varname, '.') != -1 || strings.IndexByte(varname, '[') != -1 {
1848
				x.decStruct(varname, rtid, t)
1849
			} else {
1850
				varname2 := genTempVarPfx + "j" + mi
1851
				x.line(varname2 + " := &" + varname)
1852
				x.decStruct(varname2, rtid, t)
1853
			}
1854
		} else {
1855
			// delete(x.td, rtid)
1856
			x.line("z.DecFallback(" + addrPfx + varname + ", false)")
1857
		}
1858
	default:
1859
		if rtidAdded {
1860
			delete(x.te, rtid)
1861
		}
1862
		x.line("z.DecFallback(" + addrPfx + varname + ", true)")
1863
	}
1864
}
1865

1866
func (x *genRunner) decTryAssignPrimitive(varname string, t reflect.Type, isptr bool) (done bool) {
1867
	// This should only be used for exact primitives (ie un-named types).
1868
	// Named types may be implementations of Selfer, Unmarshaler, etc.
1869
	// They should be handled by dec(...)
1870

1871
	var ptr string
1872
	if isptr {
1873
		ptr = "*"
1874
	}
1875
	switch t.Kind() {
1876
	case reflect.Int:
1877
		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
1878
	case reflect.Int8:
1879
		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 8))", ptr, varname, x.genTypeName(t))
1880
	case reflect.Int16:
1881
		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 16))", ptr, varname, x.genTypeName(t))
1882
	case reflect.Int32:
1883
		x.linef("%s%s = (%s)(z.C.IntV(r.DecodeInt64(), 32))", ptr, varname, x.genTypeName(t))
1884
	case reflect.Int64:
1885
		x.linef("%s%s = (%s)(r.DecodeInt64())", ptr, varname, x.genTypeName(t))
1886

1887
	case reflect.Uint:
1888
		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
1889
	case reflect.Uint8:
1890
		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 8))", ptr, varname, x.genTypeName(t))
1891
	case reflect.Uint16:
1892
		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 16))", ptr, varname, x.genTypeName(t))
1893
	case reflect.Uint32:
1894
		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), 32))", ptr, varname, x.genTypeName(t))
1895
	case reflect.Uint64:
1896
		x.linef("%s%s = (%s)(r.DecodeUint64())", ptr, varname, x.genTypeName(t))
1897
	case reflect.Uintptr:
1898
		x.linef("%s%s = (%s)(z.C.UintV(r.DecodeUint64(), codecSelferBitsize%s))", ptr, varname, x.genTypeName(t), x.xs)
1899

1900
	case reflect.Float32:
1901
		x.linef("%s%s = (%s)(z.DecDecodeFloat32())", ptr, varname, x.genTypeName(t))
1902
	case reflect.Float64:
1903
		x.linef("%s%s = (%s)(r.DecodeFloat64())", ptr, varname, x.genTypeName(t))
1904

1905
	case reflect.Complex64:
1906
		x.linef("%s%s = (%s)(complex(z.DecDecodeFloat32(), 0))", ptr, varname, x.genTypeName(t))
1907
	case reflect.Complex128:
1908
		x.linef("%s%s = (%s)(complex(r.DecodeFloat64(), 0))", ptr, varname, x.genTypeName(t))
1909

1910
	case reflect.Bool:
1911
		x.linef("%s%s = (%s)(r.DecodeBool())", ptr, varname, x.genTypeName(t))
1912
	case reflect.String:
1913
		if t == genStringDecAsBytesTyp {
1914
			x.linef("%s%s = r.DecodeStringAsBytes()", ptr, varname)
1915
		} else if t == genStringDecZCTyp {
1916
			x.linef("%s%s = (string)(z.DecStringZC(r.DecodeStringAsBytes()))", ptr, varname)
1917
		} else {
1918
			x.linef("%s%s = (%s)(z.DecStringZC(r.DecodeStringAsBytes()))", ptr, varname, x.genTypeName(t))
1919
		}
1920
	default:
1921
		return false
1922
	}
1923
	return true
1924
}
1925

1926
func (x *genRunner) decListFallback(varname string, rtid uintptr, t reflect.Type) {
1927
	if t.AssignableTo(uint8SliceTyp) {
1928
		x.line("*" + varname + " = z.DecodeBytesInto(*((*[]byte)(" + varname + ")))")
1929
		return
1930
	}
1931
	if t.Kind() == reflect.Array && t.Elem().Kind() == reflect.Uint8 {
1932
		x.linef("r.DecodeBytes( ((*[%d]byte)(%s))[:])", t.Len(), varname)
1933
		return
1934
	}
1935
	type tstruc struct {
1936
		TempVar   string
1937
		Sfx       string
1938
		Rand      string
1939
		Varname   string
1940
		CTyp      string
1941
		Typ       string
1942
		Immutable bool
1943
		Size      int
1944
	}
1945
	telem := t.Elem()
1946
	ts := tstruc{genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(t), x.genTypeName(telem), genIsImmutable(telem), int(telem.Size())}
1947

1948
	funcs := make(template.FuncMap)
1949

1950
	funcs["decLineVar"] = func(varname string) string {
1951
		x.decVar(varname, "", telem, false, true)
1952
		return ""
1953
	}
1954
	funcs["var"] = func(s string) string {
1955
		return ts.TempVar + s + ts.Rand
1956
	}
1957
	funcs["xs"] = func() string {
1958
		return ts.Sfx
1959
	}
1960
	funcs["zero"] = func() string {
1961
		return x.genZeroValueR(telem)
1962
	}
1963
	funcs["isArray"] = func() bool {
1964
		return t.Kind() == reflect.Array
1965
	}
1966
	funcs["isSlice"] = func() bool {
1967
		return t.Kind() == reflect.Slice
1968
	}
1969
	funcs["isChan"] = func() bool {
1970
		return t.Kind() == reflect.Chan
1971
	}
1972
	tm, err := template.New("").Funcs(funcs).Parse(genDecListTmpl)
1973
	genCheckErr(err)
1974
	genCheckErr(tm.Execute(x.w, &ts))
1975
}
1976

1977
func (x *genRunner) decMapFallback(varname string, rtid uintptr, t reflect.Type) {
1978
	type tstruc struct {
1979
		TempVar string
1980
		Sfx     string
1981
		Rand    string
1982
		Varname string
1983
		KTyp    string
1984
		Typ     string
1985
		Size    int
1986
	}
1987
	telem := t.Elem()
1988
	tkey := t.Key()
1989
	ts := tstruc{
1990
		genTempVarPfx, x.xs, x.varsfx(), varname, x.genTypeName(tkey),
1991
		x.genTypeName(telem), int(telem.Size() + tkey.Size()),
1992
	}
1993

1994
	funcs := make(template.FuncMap)
1995
	funcs["decElemZero"] = func() string {
1996
		return x.genZeroValueR(telem)
1997
	}
1998
	funcs["decElemKindImmutable"] = func() bool {
1999
		return genIsImmutable(telem)
2000
	}
2001
	funcs["decElemKindPtr"] = func() bool {
2002
		return telem.Kind() == reflect.Ptr
2003
	}
2004
	funcs["decElemKindIntf"] = func() bool {
2005
		return telem.Kind() == reflect.Interface
2006
	}
2007
	funcs["decLineVarKStrBytes"] = func(varname string) string {
2008
		x.decVar(varname, "", genStringDecAsBytesTyp, false, true)
2009
		return ""
2010
	}
2011
	funcs["decLineVarKStrZC"] = func(varname string) string {
2012
		x.decVar(varname, "", genStringDecZCTyp, false, true)
2013
		return ""
2014
	}
2015
	funcs["decLineVarK"] = func(varname string) string {
2016
		x.decVar(varname, "", tkey, false, true)
2017
		return ""
2018
	}
2019
	funcs["decLineVar"] = func(varname, decodedNilVarname string) string {
2020
		x.decVar(varname, decodedNilVarname, telem, false, true)
2021
		return ""
2022
	}
2023
	funcs["var"] = func(s string) string {
2024
		return ts.TempVar + s + ts.Rand
2025
	}
2026
	funcs["xs"] = func() string {
2027
		return ts.Sfx
2028
	}
2029

2030
	tm, err := template.New("").Funcs(funcs).Parse(genDecMapTmpl)
2031
	genCheckErr(err)
2032
	genCheckErr(tm.Execute(x.w, &ts))
2033
}
2034

2035
func (x *genRunner) decStructMapSwitch(kName string, varname string, rtid uintptr, t reflect.Type) {
2036
	ti := x.ti.get(rtid, t)
2037
	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
2038
	x.line("switch string(" + kName + ") {")
2039
	var newbuf, nilbuf genBuf
2040
	for _, si := range tisfi {
2041
		x.line("case \"" + si.encName + "\":")
2042
		newbuf.reset()
2043
		nilbuf.reset()
2044
		varname3, t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
2045
		if len(newbuf.buf) > 0 {
2046
			x.linef("if r.TryNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
2047
		}
2048
		x.decVarMain(varname3, x.varsfx(), t2.Type, false)
2049
		if len(newbuf.buf) > 0 {
2050
			x.line("}")
2051
		}
2052
	}
2053
	x.line("default:")
2054
	// pass the slice here, so that the string will not escape, and maybe save allocation
2055
	x.linef("z.DecStructFieldNotFound(-1, string(%s))", kName)
2056
	x.linef("} // end switch %s", kName)
2057
}
2058

2059
func (x *genRunner) decStructMap(varname, lenvarname string, rtid uintptr, t reflect.Type) {
2060
	tpfx := genTempVarPfx
2061
	ti := x.ti.get(rtid, t)
2062
	i := x.varsfx()
2063
	kName := tpfx + "s" + i
2064

2065
	x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
2066
	x.linef("for %sj%s := 0; z.DecContainerNext(%sj%s, %s, %shl%s); %sj%s++ {",
2067
		tpfx, i, tpfx, i, lenvarname, tpfx, i, tpfx, i)
2068

2069
	x.line("z.DecReadMapElemKey()")
2070

2071
	// emulate decstructfieldkey
2072
	switch ti.keyType {
2073
	case valueTypeInt:
2074
		x.linef("%s := strconv.AppendInt(z.DecScratchArrayBuffer()[:0], r.DecodeInt64(), 10)", kName)
2075
	case valueTypeUint:
2076
		x.linef("%s := strconv.AppendUint(z.DecScratchArrayBuffer()[:0], r.DecodeUint64(), 10)", kName)
2077
	case valueTypeFloat:
2078
		x.linef("%s := strconv.AppendFloat(z.DecScratchArrayBuffer()[:0], r.DecodeFloat64(), 'f', -1, 64)", kName)
2079
	default: // string
2080
		x.linef("%s := r.DecodeStringAsBytes()", kName)
2081
	}
2082

2083
	x.line("z.DecReadMapElemValue()")
2084
	x.decStructMapSwitch(kName, varname, rtid, t)
2085

2086
	x.line("} // end for " + tpfx + "j" + i)
2087
}
2088

2089
func (x *genRunner) decStructArray(varname, lenvarname, breakString string, rtid uintptr, t reflect.Type) {
2090
	tpfx := genTempVarPfx
2091
	i := x.varsfx()
2092
	ti := x.ti.get(rtid, t)
2093
	tisfi := ti.sfi.source() // always use sequence from file. decStruct expects same thing.
2094
	x.linef("var %sj%s int", tpfx, i)
2095
	x.linef("var %sb%s bool", tpfx, i)                        // break
2096
	x.linef("var %shl%s bool = %s >= 0", tpfx, i, lenvarname) // has length
2097
	var newbuf, nilbuf genBuf
2098
	for _, si := range tisfi {
2099
		x.linef("%sb%s = !z.DecContainerNext(%sj%s, %s, %shl%s)", tpfx, i, tpfx, i, lenvarname, tpfx, i)
2100
		x.linef("if %sb%s { z.DecReadArrayEnd(); %s }", tpfx, i, breakString)
2101
		x.line("z.DecReadArrayElem()")
2102
		newbuf.reset()
2103
		nilbuf.reset()
2104
		varname3, t2 := x.decVarInitPtr(varname, "", t, si, &newbuf, &nilbuf)
2105
		if len(newbuf.buf) > 0 {
2106
			x.linef("if r.TryNil() { %s } else { %s", nilbuf.buf, newbuf.buf)
2107
		}
2108
		x.decVarMain(varname3, x.varsfx(), t2.Type, false)
2109
		if len(newbuf.buf) > 0 {
2110
			x.line("}")
2111
		}
2112
		x.linef("%sj%s++", tpfx, i)
2113
	}
2114
	// read remaining values and throw away.
2115
	x.linef("for ; z.DecContainerNext(%sj%s, %s, %shl%s); %sj%s++ {",
2116
		tpfx, i, lenvarname, tpfx, i, tpfx, i)
2117
	x.line("z.DecReadArrayElem()")
2118
	x.linef(`z.DecStructFieldNotFound(%sj%s - 1, "")`, tpfx, i)
2119
	x.line("}")
2120
}
2121

2122
func (x *genRunner) decStruct(varname string, rtid uintptr, t reflect.Type) {
2123
	// varname MUST be a ptr, or a struct field or a slice element.
2124
	i := x.varsfx()
2125
	x.linef("%sct%s := r.ContainerType()", genTempVarPfx, i)
2126
	x.linef("if %sct%s == codecSelferValueTypeNil%s {", genTempVarPfx, i, x.xs)
2127
	x.linef("*(%s) = %s{}", varname, x.genTypeName(t))
2128
	x.linef("} else if %sct%s == codecSelferValueTypeMap%s {", genTempVarPfx, i, x.xs)
2129
	x.line(genTempVarPfx + "l" + i + " := z.DecReadMapStart()")
2130
	x.linef("if %sl%s == 0 {", genTempVarPfx, i)
2131

2132
	x.line("} else { ")
2133
	x.linef("%s.codecDecodeSelfFromMap(%sl%s, d)", varname, genTempVarPfx, i)
2134

2135
	x.line("}")
2136
	x.line("z.DecReadMapEnd()")
2137

2138
	// else if container is array
2139
	x.linef("} else if %sct%s == codecSelferValueTypeArray%s {", genTempVarPfx, i, x.xs)
2140
	x.line(genTempVarPfx + "l" + i + " := z.DecReadArrayStart()")
2141
	x.linef("if %sl%s != 0 {", genTempVarPfx, i)
2142
	x.linef("%s.codecDecodeSelfFromArray(%sl%s, d)", varname, genTempVarPfx, i)
2143
	x.line("}")
2144
	x.line("z.DecReadArrayEnd()")
2145
	// else panic
2146
	x.line("} else { ")
2147
	x.line("panic(errCodecSelferOnlyMapOrArrayEncodeToStruct" + x.xs + ")")
2148
	x.line("} ")
2149
}
2150

2151
// --------
2152

2153
type fastpathGenV struct {
2154
	// fastpathGenV is either a primitive (Primitive != "") or a map (MapKey != "") or a slice
2155
	MapKey      string
2156
	Elem        string
2157
	Primitive   string
2158
	Size        int
2159
	NoCanonical bool
2160
}
2161

2162
func (x *genRunner) newFastpathGenV(t reflect.Type) (v fastpathGenV) {
2163
	v.NoCanonical = !genFastpathCanonical
2164
	switch t.Kind() {
2165
	case reflect.Slice, reflect.Array:
2166
		te := t.Elem()
2167
		v.Elem = x.genTypeName(te)
2168
		v.Size = int(te.Size())
2169
	case reflect.Map:
2170
		te := t.Elem()
2171
		tk := t.Key()
2172
		v.Elem = x.genTypeName(te)
2173
		v.MapKey = x.genTypeName(tk)
2174
		v.Size = int(te.Size() + tk.Size())
2175
	default:
2176
		halt.onerror(errGenUnexpectedTypeFastpath)
2177
	}
2178
	return
2179
}
2180

2181
func (x *fastpathGenV) MethodNamePfx(prefix string, prim bool) string {
2182
	var name []byte
2183
	if prefix != "" {
2184
		name = append(name, prefix...)
2185
	}
2186
	if prim {
2187
		name = append(name, genTitleCaseName(x.Primitive)...)
2188
	} else {
2189
		if x.MapKey == "" {
2190
			name = append(name, "Slice"...)
2191
		} else {
2192
			name = append(name, "Map"...)
2193
			name = append(name, genTitleCaseName(x.MapKey)...)
2194
		}
2195
		name = append(name, genTitleCaseName(x.Elem)...)
2196
	}
2197
	return string(name)
2198
}
2199

2200
// genImportPath returns import path of a non-predeclared named typed, or an empty string otherwise.
2201
//
2202
// This handles the misbehaviour that occurs when 1.5-style vendoring is enabled,
2203
// where PkgPath returns the full path, including the vendoring pre-fix that should have been stripped.
2204
// We strip it here.
2205
func genImportPath(t reflect.Type) (s string) {
2206
	s = t.PkgPath()
2207
	if genCheckVendor {
2208
		// HACK: always handle vendoring. It should be typically on in go 1.6, 1.7
2209
		s = genStripVendor(s)
2210
	}
2211
	return
2212
}
2213

2214
// A go identifier is (letter|_)[letter|number|_]*
2215
func genGoIdentifier(s string, checkFirstChar bool) string {
2216
	b := make([]byte, 0, len(s))
2217
	t := make([]byte, 4)
2218
	var n int
2219
	for i, r := range s {
2220
		if checkFirstChar && i == 0 && !unicode.IsLetter(r) {
2221
			b = append(b, '_')
2222
		}
2223
		// r must be unicode_letter, unicode_digit or _
2224
		if unicode.IsLetter(r) || unicode.IsDigit(r) {
2225
			n = utf8.EncodeRune(t, r)
2226
			b = append(b, t[:n]...)
2227
		} else {
2228
			b = append(b, '_')
2229
		}
2230
	}
2231
	return string(b)
2232
}
2233

2234
func genNonPtr(t reflect.Type) reflect.Type {
2235
	for t.Kind() == reflect.Ptr {
2236
		t = t.Elem()
2237
	}
2238
	return t
2239
}
2240

2241
func genFastpathUnderlying(t reflect.Type, rtid uintptr, ti *typeInfo) (tu reflect.Type, rtidu uintptr) {
2242
	tu = t
2243
	rtidu = rtid
2244
	if ti.flagHasPkgPath {
2245
		tu = ti.fastpathUnderlying
2246
		rtidu = rt2id(tu)
2247
	}
2248
	return
2249
}
2250

2251
func genTitleCaseName(s string) string {
2252
	switch s {
2253
	case "interface{}", "interface {}":
2254
		return "Intf"
2255
	case "[]byte", "[]uint8", "bytes":
2256
		return "Bytes"
2257
	default:
2258
		return strings.ToUpper(s[0:1]) + s[1:]
2259
	}
2260
}
2261

2262
func genMethodNameT(t reflect.Type, tRef reflect.Type) (n string) {
2263
	var ptrPfx string
2264
	for t.Kind() == reflect.Ptr {
2265
		ptrPfx += "Ptrto"
2266
		t = t.Elem()
2267
	}
2268
	tstr := t.String()
2269
	if tn := t.Name(); tn != "" {
2270
		if tRef != nil && genImportPath(t) == genImportPath(tRef) {
2271
			return ptrPfx + tn
2272
		} else {
2273
			if genQNameRegex.MatchString(tstr) {
2274
				return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
2275
			} else {
2276
				return ptrPfx + genCustomTypeName(tstr)
2277
			}
2278
		}
2279
	}
2280
	switch t.Kind() {
2281
	case reflect.Map:
2282
		return ptrPfx + "Map" + genMethodNameT(t.Key(), tRef) + genMethodNameT(t.Elem(), tRef)
2283
	case reflect.Slice:
2284
		return ptrPfx + "Slice" + genMethodNameT(t.Elem(), tRef)
2285
	case reflect.Array:
2286
		return ptrPfx + "Array" + strconv.FormatInt(int64(t.Len()), 10) + genMethodNameT(t.Elem(), tRef)
2287
	case reflect.Chan:
2288
		var cx string
2289
		switch t.ChanDir() {
2290
		case reflect.SendDir:
2291
			cx = "ChanSend"
2292
		case reflect.RecvDir:
2293
			cx = "ChanRecv"
2294
		default:
2295
			cx = "Chan"
2296
		}
2297
		return ptrPfx + cx + genMethodNameT(t.Elem(), tRef)
2298
	default:
2299
		if t == intfTyp {
2300
			return ptrPfx + "Interface"
2301
		} else {
2302
			if tRef != nil && genImportPath(t) == genImportPath(tRef) {
2303
				if t.Name() != "" {
2304
					return ptrPfx + t.Name()
2305
				} else {
2306
					return ptrPfx + genCustomTypeName(tstr)
2307
				}
2308
			} else {
2309
				// best way to get the package name inclusive
2310
				if t.Name() != "" && genQNameRegex.MatchString(tstr) {
2311
					return ptrPfx + strings.Replace(tstr, ".", "_", 1000)
2312
				} else {
2313
					return ptrPfx + genCustomTypeName(tstr)
2314
				}
2315
			}
2316
		}
2317
	}
2318
}
2319

2320
// genCustomNameForType base32 encodes the t.String() value in such a way
2321
// that it can be used within a function name.
2322
func genCustomTypeName(tstr string) string {
2323
	len2 := genTypenameEnc.EncodedLen(len(tstr))
2324
	bufx := make([]byte, len2)
2325
	genTypenameEnc.Encode(bufx, []byte(tstr))
2326
	for i := len2 - 1; i >= 0; i-- {
2327
		if bufx[i] == '=' {
2328
			len2--
2329
		} else {
2330
			break
2331
		}
2332
	}
2333
	return string(bufx[:len2])
2334
}
2335

2336
func genIsImmutable(t reflect.Type) (v bool) {
2337
	return scalarBitset.isset(byte(t.Kind()))
2338
}
2339

2340
type genInternal struct {
2341
	Version int
2342
	Values  []fastpathGenV
2343
	Formats []string
2344
}
2345

2346
func (x genInternal) FastpathLen() (l int) {
2347
	for _, v := range x.Values {
2348
		// if v.Primitive == "" && !(v.MapKey == "" && v.Elem == "uint8") {
2349
		if v.Primitive == "" {
2350
			l++
2351
		}
2352
	}
2353
	return
2354
}
2355

2356
func genInternalZeroValue(s string) string {
2357
	switch s {
2358
	case "interface{}", "interface {}":
2359
		return "nil"
2360
	case "[]byte", "[]uint8", "bytes":
2361
		return "nil"
2362
	case "bool":
2363
		return "false"
2364
	case "string":
2365
		return `""`
2366
	default:
2367
		return "0"
2368
	}
2369
}
2370

2371
var genInternalNonZeroValueIdx [6]uint64
2372
var genInternalNonZeroValueStrs = [...][6]string{
2373
	{`"string-is-an-interface-1"`, "true", `"some-string-1"`, `[]byte("some-string-1")`, "11.1", "111"},
2374
	{`"string-is-an-interface-2"`, "false", `"some-string-2"`, `[]byte("some-string-2")`, "22.2", "77"},
2375
	{`"string-is-an-interface-3"`, "true", `"some-string-3"`, `[]byte("some-string-3")`, "33.3e3", "127"},
2376
}
2377

2378
// Note: last numbers must be in range: 0-127 (as they may be put into a int8, uint8, etc)
2379

2380
func genInternalNonZeroValue(s string) string {
2381
	var i int
2382
	switch s {
2383
	case "interface{}", "interface {}":
2384
		i = 0
2385
	case "bool":
2386
		i = 1
2387
	case "string":
2388
		i = 2
2389
	case "bytes", "[]byte", "[]uint8":
2390
		i = 3
2391
	case "float32", "float64", "float", "double", "complex", "complex64", "complex128":
2392
		i = 4
2393
	default:
2394
		i = 5
2395
	}
2396
	genInternalNonZeroValueIdx[i]++
2397
	idx := genInternalNonZeroValueIdx[i]
2398
	slen := uint64(len(genInternalNonZeroValueStrs))
2399
	return genInternalNonZeroValueStrs[idx%slen][i] // return string, to remove ambiguity
2400
}
2401

2402
// Note: used for fastpath only
2403
func genInternalEncCommandAsString(s string, vname string) string {
2404
	switch s {
2405
	case "uint64":
2406
		return "e.e.EncodeUint(" + vname + ")"
2407
	case "uint", "uint8", "uint16", "uint32":
2408
		return "e.e.EncodeUint(uint64(" + vname + "))"
2409
	case "int64":
2410
		return "e.e.EncodeInt(" + vname + ")"
2411
	case "int", "int8", "int16", "int32":
2412
		return "e.e.EncodeInt(int64(" + vname + "))"
2413
	case "[]byte", "[]uint8", "bytes":
2414
		return "e.e.EncodeStringBytesRaw(" + vname + ")"
2415
	case "string":
2416
		return "e.e.EncodeString(" + vname + ")"
2417
	case "float32":
2418
		return "e.e.EncodeFloat32(" + vname + ")"
2419
	case "float64":
2420
		return "e.e.EncodeFloat64(" + vname + ")"
2421
	case "bool":
2422
		return "e.e.EncodeBool(" + vname + ")"
2423
	// case "symbol":
2424
	// 	return "e.e.EncodeSymbol(" + vname + ")"
2425
	default:
2426
		return "e.encode(" + vname + ")"
2427
	}
2428
}
2429

2430
// Note: used for fastpath only
2431
func genInternalDecCommandAsString(s string, mapkey bool) string {
2432
	switch s {
2433
	case "uint":
2434
		return "uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))"
2435
	case "uint8":
2436
		return "uint8(chkOvf.UintV(d.d.DecodeUint64(), 8))"
2437
	case "uint16":
2438
		return "uint16(chkOvf.UintV(d.d.DecodeUint64(), 16))"
2439
	case "uint32":
2440
		return "uint32(chkOvf.UintV(d.d.DecodeUint64(), 32))"
2441
	case "uint64":
2442
		return "d.d.DecodeUint64()"
2443
	case "uintptr":
2444
		return "uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize))"
2445
	case "int":
2446
		return "int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize))"
2447
	case "int8":
2448
		return "int8(chkOvf.IntV(d.d.DecodeInt64(), 8))"
2449
	case "int16":
2450
		return "int16(chkOvf.IntV(d.d.DecodeInt64(), 16))"
2451
	case "int32":
2452
		return "int32(chkOvf.IntV(d.d.DecodeInt64(), 32))"
2453
	case "int64":
2454
		return "d.d.DecodeInt64()"
2455

2456
	case "string":
2457
		// if mapkey {
2458
		// 	return "d.stringZC(d.d.DecodeStringAsBytes())"
2459
		// }
2460
		// return "string(d.d.DecodeStringAsBytes())"
2461
		return "d.stringZC(d.d.DecodeStringAsBytes())"
2462
	case "[]byte", "[]uint8", "bytes":
2463
		return "d.d.DecodeBytes([]byte{})"
2464
	case "float32":
2465
		return "float32(d.decodeFloat32())"
2466
	case "float64":
2467
		return "d.d.DecodeFloat64()"
2468
	case "complex64":
2469
		return "complex(d.decodeFloat32(), 0)"
2470
	case "complex128":
2471
		return "complex(d.d.DecodeFloat64(), 0)"
2472
	case "bool":
2473
		return "d.d.DecodeBool()"
2474
	default:
2475
		halt.onerror(errors.New("gen internal: unknown type for decode: " + s))
2476
	}
2477
	return ""
2478
}
2479

2480
// func genInternalSortType(s string, elem bool) string {
2481
// 	for _, v := range [...]string{
2482
// 		"int",
2483
// 		"uint",
2484
// 		"float",
2485
// 		"bool",
2486
// 		"string",
2487
// 		"bytes", "[]uint8", "[]byte",
2488
// 	} {
2489
// 		if v == "[]byte" || v == "[]uint8" {
2490
// 			v = "bytes"
2491
// 		}
2492
// 		if strings.HasPrefix(s, v) {
2493
// 			if v == "int" || v == "uint" || v == "float" {
2494
// 				v += "64"
2495
// 			}
2496
// 			if elem {
2497
// 				return v
2498
// 			}
2499
// 			return v + "Slice"
2500
// 		}
2501
// 	}
2502
// 	halt.onerror(errors.New("sorttype: unexpected type: " + s))
2503
// }
2504

2505
func genInternalSortType(s string, elem bool) string {
2506
	if elem {
2507
		return s
2508
	}
2509
	return s + "Slice"
2510
}
2511

2512
// MARKER: keep in sync with codecgen/gen.go
2513
func genStripVendor(s string) string {
2514
	// HACK: Misbehaviour occurs in go 1.5. May have to re-visit this later.
2515
	// if s contains /vendor/ OR startsWith vendor/, then return everything after it.
2516
	const vendorStart = "vendor/"
2517
	const vendorInline = "/vendor/"
2518
	if i := strings.LastIndex(s, vendorInline); i >= 0 {
2519
		s = s[i+len(vendorInline):]
2520
	} else if strings.HasPrefix(s, vendorStart) {
2521
		s = s[len(vendorStart):]
2522
	}
2523
	return s
2524
}
2525

2526
// var genInternalMu sync.Mutex
2527
var genInternalV = genInternal{Version: genVersion}
2528
var genInternalTmplFuncs template.FuncMap
2529
var genInternalOnce sync.Once
2530

2531
func genInternalInit() {
2532
	wordSizeBytes := int(intBitsize) / 8
2533

2534
	typesizes := map[string]int{
2535
		"interface{}": 2 * wordSizeBytes,
2536
		"string":      2 * wordSizeBytes,
2537
		"[]byte":      3 * wordSizeBytes,
2538
		"uint":        1 * wordSizeBytes,
2539
		"uint8":       1,
2540
		"uint16":      2,
2541
		"uint32":      4,
2542
		"uint64":      8,
2543
		"uintptr":     1 * wordSizeBytes,
2544
		"int":         1 * wordSizeBytes,
2545
		"int8":        1,
2546
		"int16":       2,
2547
		"int32":       4,
2548
		"int64":       8,
2549
		"float32":     4,
2550
		"float64":     8,
2551
		"complex64":   8,
2552
		"complex128":  16,
2553
		"bool":        1,
2554
	}
2555

2556
	// keep as slice, so it is in specific iteration order.
2557
	// Initial order was uint64, string, interface{}, int, int64, ...
2558

2559
	var types = [...]string{
2560
		"interface{}",
2561
		"string",
2562
		"[]byte",
2563
		"float32",
2564
		"float64",
2565
		"uint",
2566
		"uint8",
2567
		"uint16",
2568
		"uint32",
2569
		"uint64",
2570
		"uintptr",
2571
		"int",
2572
		"int8",
2573
		"int16",
2574
		"int32",
2575
		"int64",
2576
		"bool",
2577
	}
2578

2579
	var primitivetypes, slicetypes, mapkeytypes, mapvaltypes []string
2580

2581
	primitivetypes = types[:]
2582
	slicetypes = types[:]
2583
	mapkeytypes = types[:]
2584
	mapvaltypes = types[:]
2585

2586
	if genFastpathTrimTypes {
2587
		// Note: we only create fast-paths for commonly used types.
2588
		// Consequently, things like int8, uint16, uint, etc are commented out.
2589

2590
		slicetypes = genInternalFastpathSliceTypes()
2591
		mapkeytypes = genInternalFastpathMapKeyTypes()
2592
		mapvaltypes = genInternalFastpathMapValueTypes()
2593
	}
2594

2595
	// var mapkeytypes [len(&types) - 1]string // skip bool
2596
	// copy(mapkeytypes[:], types[:])
2597

2598
	// var mb []byte
2599
	// mb = append(mb, '|')
2600
	// for _, s := range mapkeytypes {
2601
	// 	mb = append(mb, s...)
2602
	// 	mb = append(mb, '|')
2603
	// }
2604
	// var mapkeytypestr = string(mb)
2605

2606
	var gt = genInternal{Version: genVersion, Formats: genFormats}
2607

2608
	// For each slice or map type, there must be a (symmetrical) Encode and Decode fast-path function
2609

2610
	for _, s := range primitivetypes {
2611
		gt.Values = append(gt.Values,
2612
			fastpathGenV{Primitive: s, Size: typesizes[s], NoCanonical: !genFastpathCanonical})
2613
	}
2614
	for _, s := range slicetypes {
2615
		// if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already.
2616
		// 	gt.Values = append(gt.Values, fastpathGenV{Elem: s, Size: typesizes[s]})
2617
		// }
2618
		gt.Values = append(gt.Values,
2619
			fastpathGenV{Elem: s, Size: typesizes[s], NoCanonical: !genFastpathCanonical})
2620
	}
2621
	for _, s := range mapkeytypes {
2622
		// if _, ok := typesizes[s]; !ok {
2623
		// if strings.Contains(mapkeytypestr, "|"+s+"|") {
2624
		// 	gt.Values = append(gt.Values, fastpathGenV{MapKey: s, Elem: s, Size: 2 * typesizes[s]})
2625
		// }
2626
		for _, ms := range mapvaltypes {
2627
			gt.Values = append(gt.Values,
2628
				fastpathGenV{MapKey: s, Elem: ms, Size: typesizes[s] + typesizes[ms], NoCanonical: !genFastpathCanonical})
2629
		}
2630
	}
2631

2632
	funcs := make(template.FuncMap)
2633
	// funcs["haspfx"] = strings.HasPrefix
2634
	funcs["encmd"] = genInternalEncCommandAsString
2635
	funcs["decmd"] = genInternalDecCommandAsString
2636
	funcs["zerocmd"] = genInternalZeroValue
2637
	funcs["nonzerocmd"] = genInternalNonZeroValue
2638
	funcs["hasprefix"] = strings.HasPrefix
2639
	funcs["sorttype"] = genInternalSortType
2640

2641
	genInternalV = gt
2642
	genInternalTmplFuncs = funcs
2643
}
2644

2645
// genInternalGoFile is used to generate source files from templates.
2646
func genInternalGoFile(r io.Reader, w io.Writer) (err error) {
2647
	genInternalOnce.Do(genInternalInit)
2648

2649
	gt := genInternalV
2650

2651
	t := template.New("").Funcs(genInternalTmplFuncs)
2652

2653
	tmplstr, err := ioutil.ReadAll(r)
2654
	if err != nil {
2655
		return
2656
	}
2657

2658
	if t, err = t.Parse(string(tmplstr)); err != nil {
2659
		return
2660
	}
2661

2662
	var out bytes.Buffer
2663
	err = t.Execute(&out, gt)
2664
	if err != nil {
2665
		return
2666
	}
2667

2668
	bout, err := format.Source(out.Bytes())
2669
	if err != nil {
2670
		w.Write(out.Bytes()) // write out if error, so we can still see.
2671
		// w.Write(bout) // write out if error, as much as possible, so we can still see.
2672
		return
2673
	}
2674
	w.Write(bout)
2675
	return
2676
}
2677

2678
func genInternalFastpathSliceTypes() []string {
2679
	return []string{
2680
		"interface{}",
2681
		"string",
2682
		"[]byte",
2683
		"float32",
2684
		"float64",
2685
		// "uint",
2686
		// "uint8", // no need for fastpath of []uint8, as it is handled specially
2687
		"uint8", // keep fast-path, so it doesn't have to go through reflection
2688
		// "uint16",
2689
		// "uint32",
2690
		"uint64",
2691
		// "uintptr",
2692
		"int",
2693
		// "int8",
2694
		// "int16",
2695
		"int32", // rune
2696
		"int64",
2697
		"bool",
2698
	}
2699
}
2700

2701
func genInternalFastpathMapKeyTypes() []string {
2702
	return []string{
2703
		// "interface{}",
2704
		"string",
2705
		// "[]byte",
2706
		// "float32",
2707
		// "float64",
2708
		// "uint",
2709
		"uint8", // byte
2710
		// "uint16",
2711
		// "uint32",
2712
		"uint64", // used for keys
2713
		// "uintptr",
2714
		"int", // default number key
2715
		// "int8",
2716
		// "int16",
2717
		"int32", // rune
2718
		// "int64",
2719
		// "bool",
2720
	}
2721
}
2722

2723
func genInternalFastpathMapValueTypes() []string {
2724
	return []string{
2725
		"interface{}",
2726
		"string",
2727
		"[]byte",
2728
		// "uint",
2729
		"uint8", // byte
2730
		// "uint16",
2731
		// "uint32",
2732
		"uint64", // used for keys, etc
2733
		// "uintptr",
2734
		"int", // default number
2735
		//"int8",
2736
		// "int16",
2737
		"int32", // rune (mostly used for unicode)
2738
		// "int64",
2739
		// "float32",
2740
		"float64",
2741
		"bool",
2742
	}
2743
}
2744

2745
// sort-slice ...
2746
// generates sort implementations for
2747
// various slice types and combination slice+reflect.Value types.
2748
//
2749
// The combination slice+reflect.Value types are used
2750
// during canonical encode, and the others are used during fast-path
2751
// encoding of map keys.
2752

2753
// genInternalSortableTypes returns the types
2754
// that are used for fast-path canonical's encoding of maps.
2755
//
2756
// For now, we only support the highest sizes for
2757
// int64, uint64, float64, bool, string, bytes.
2758
func genInternalSortableTypes() []string {
2759
	return genInternalFastpathMapKeyTypes()
2760
}
2761

2762
// genInternalSortablePlusTypes returns the types
2763
// that are used for reflection-based canonical's encoding of maps.
2764
//
2765
// For now, we only support the highest sizes for
2766
// int64, uint64, float64, string, bytes.
2767
func genInternalSortablePlusTypes() []string {
2768
	return []string{
2769
		"string",
2770
		"float64",
2771
		"uint64",
2772
		// "uintptr",
2773
		"int64",
2774
		// "bool",
2775
		"time",
2776
		"bytes",
2777
	}
2778
}
2779

2780
func genTypeForShortName(s string) string {
2781
	switch s {
2782
	case "time":
2783
		return "time.Time"
2784
	case "bytes":
2785
		return "[]byte"
2786
	}
2787
	return s
2788
}
2789

2790
func genArgs(args ...interface{}) map[string]interface{} {
2791
	m := make(map[string]interface{}, len(args)/2)
2792
	for i := 0; i < len(args); {
2793
		m[args[i].(string)] = args[i+1]
2794
		i += 2
2795
	}
2796
	return m
2797
}
2798

2799
func genEndsWith(s0 string, sn ...string) bool {
2800
	for _, s := range sn {
2801
		if strings.HasSuffix(s0, s) {
2802
			return true
2803
		}
2804
	}
2805
	return false
2806
}
2807

2808
func genCheckErr(err error) {
2809
	halt.onerror(err)
2810
}
2811

2812
func genRunSortTmpl2Go(fnameIn, fnameOut string) {
2813
	var err error
2814

2815
	funcs := make(template.FuncMap)
2816
	funcs["sortables"] = genInternalSortableTypes
2817
	funcs["sortablesplus"] = genInternalSortablePlusTypes
2818
	funcs["tshort"] = genTypeForShortName
2819
	funcs["endswith"] = genEndsWith
2820
	funcs["args"] = genArgs
2821

2822
	t := template.New("").Funcs(funcs)
2823
	fin, err := os.Open(fnameIn)
2824
	genCheckErr(err)
2825
	defer fin.Close()
2826
	fout, err := os.Create(fnameOut)
2827
	genCheckErr(err)
2828
	defer fout.Close()
2829
	tmplstr, err := ioutil.ReadAll(fin)
2830
	genCheckErr(err)
2831
	t, err = t.Parse(string(tmplstr))
2832
	genCheckErr(err)
2833
	var out bytes.Buffer
2834
	err = t.Execute(&out, 0)
2835
	genCheckErr(err)
2836
	bout, err := format.Source(out.Bytes())
2837
	if err != nil {
2838
		fout.Write(out.Bytes()) // write out if error, so we can still see.
2839
	}
2840
	genCheckErr(err)
2841
	// write out if error, as much as possible, so we can still see.
2842
	_, err = fout.Write(bout)
2843
	genCheckErr(err)
2844
}
2845

2846
func genRunTmpl2Go(fnameIn, fnameOut string) {
2847
	// println("____ " + fnameIn + " --> " + fnameOut + " ______")
2848
	fin, err := os.Open(fnameIn)
2849
	genCheckErr(err)
2850
	defer fin.Close()
2851
	fout, err := os.Create(fnameOut)
2852
	genCheckErr(err)
2853
	defer fout.Close()
2854
	err = genInternalGoFile(fin, fout)
2855
	genCheckErr(err)
2856
}
2857

2858
// --- some methods here for other types, which are only used in codecgen
2859

2860
// depth returns number of valid nodes in the hierachy
2861
func (path *structFieldInfoPathNode) root() *structFieldInfoPathNode {
2862
TOP:
2863
	if path.parent != nil {
2864
		path = path.parent
2865
		goto TOP
2866
	}
2867
	return path
2868
}
2869

2870
func (path *structFieldInfoPathNode) fullpath() (p []*structFieldInfoPathNode) {
2871
	// this method is mostly called by a command-line tool - it's not optimized, and that's ok.
2872
	// it shouldn't be used in typical runtime use - as it does unnecessary allocation.
2873
	d := path.depth()
2874
	p = make([]*structFieldInfoPathNode, d)
2875
	for d--; d >= 0; d-- {
2876
		p[d] = path
2877
		path = path.parent
2878
	}
2879
	return
2880
}
2881

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.