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