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