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