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