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