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