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