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