github.com/codysnider/go-ethereum@v1.10.18-0.20220420071915-14f4ae99222a/rlp/rlpgen/gen.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/format" 7 "go/types" 8 "sort" 9 10 "github.com/ethereum/go-ethereum/rlp/internal/rlpstruct" 11 ) 12 13 // buildContext keeps the data needed for make*Op. 14 type buildContext struct { 15 topType *types.Named // the type we're creating methods for 16 17 encoderIface *types.Interface 18 decoderIface *types.Interface 19 rawValueType *types.Named 20 21 typeToStructCache map[types.Type]*rlpstruct.Type 22 } 23 24 func newBuildContext(packageRLP *types.Package) *buildContext { 25 enc := packageRLP.Scope().Lookup("Encoder").Type().Underlying() 26 dec := packageRLP.Scope().Lookup("Decoder").Type().Underlying() 27 rawv := packageRLP.Scope().Lookup("RawValue").Type() 28 return &buildContext{ 29 typeToStructCache: make(map[types.Type]*rlpstruct.Type), 30 encoderIface: enc.(*types.Interface), 31 decoderIface: dec.(*types.Interface), 32 rawValueType: rawv.(*types.Named), 33 } 34 } 35 36 func (bctx *buildContext) isEncoder(typ types.Type) bool { 37 return types.Implements(typ, bctx.encoderIface) 38 } 39 40 func (bctx *buildContext) isDecoder(typ types.Type) bool { 41 return types.Implements(typ, bctx.decoderIface) 42 } 43 44 // typeToStructType converts typ to rlpstruct.Type. 45 func (bctx *buildContext) typeToStructType(typ types.Type) *rlpstruct.Type { 46 if prev := bctx.typeToStructCache[typ]; prev != nil { 47 return prev // short-circuit for recursive types. 48 } 49 50 // Resolve named types to their underlying type, but keep the name. 51 name := types.TypeString(typ, nil) 52 for { 53 utype := typ.Underlying() 54 if utype == typ { 55 break 56 } 57 typ = utype 58 } 59 60 // Create the type and store it in cache. 61 t := &rlpstruct.Type{ 62 Name: name, 63 Kind: typeReflectKind(typ), 64 IsEncoder: bctx.isEncoder(typ), 65 IsDecoder: bctx.isDecoder(typ), 66 } 67 bctx.typeToStructCache[typ] = t 68 69 // Assign element type. 70 switch typ.(type) { 71 case *types.Array, *types.Slice, *types.Pointer: 72 etype := typ.(interface{ Elem() types.Type }).Elem() 73 t.Elem = bctx.typeToStructType(etype) 74 } 75 return t 76 } 77 78 // genContext is passed to the gen* methods of op when generating 79 // the output code. It tracks packages to be imported by the output 80 // file and assigns unique names of temporary variables. 81 type genContext struct { 82 inPackage *types.Package 83 imports map[string]struct{} 84 tempCounter int 85 } 86 87 func newGenContext(inPackage *types.Package) *genContext { 88 return &genContext{ 89 inPackage: inPackage, 90 imports: make(map[string]struct{}), 91 } 92 } 93 94 func (ctx *genContext) temp() string { 95 v := fmt.Sprintf("_tmp%d", ctx.tempCounter) 96 ctx.tempCounter++ 97 return v 98 } 99 100 func (ctx *genContext) resetTemp() { 101 ctx.tempCounter = 0 102 } 103 104 func (ctx *genContext) addImport(path string) { 105 if path == ctx.inPackage.Path() { 106 return // avoid importing the package that we're generating in. 107 } 108 // TODO: renaming? 109 ctx.imports[path] = struct{}{} 110 } 111 112 // importsList returns all packages that need to be imported. 113 func (ctx *genContext) importsList() []string { 114 imp := make([]string, 0, len(ctx.imports)) 115 for k := range ctx.imports { 116 imp = append(imp, k) 117 } 118 sort.Strings(imp) 119 return imp 120 } 121 122 // qualify is the types.Qualifier used for printing types. 123 func (ctx *genContext) qualify(pkg *types.Package) string { 124 if pkg.Path() == ctx.inPackage.Path() { 125 return "" 126 } 127 ctx.addImport(pkg.Path()) 128 // TODO: renaming? 129 return pkg.Name() 130 } 131 132 type op interface { 133 // genWrite creates the encoder. The generated code should write v, 134 // which is any Go expression, to the rlp.EncoderBuffer 'w'. 135 genWrite(ctx *genContext, v string) string 136 137 // genDecode creates the decoder. The generated code should read 138 // a value from the rlp.Stream 'dec' and store it to dst. 139 genDecode(ctx *genContext) (string, string) 140 } 141 142 // basicOp handles basic types bool, uint*, string. 143 type basicOp struct { 144 typ types.Type 145 writeMethod string // calle write the value 146 writeArgType types.Type // parameter type of writeMethod 147 decMethod string 148 decResultType types.Type // return type of decMethod 149 decUseBitSize bool // if true, result bit size is appended to decMethod 150 } 151 152 func (*buildContext) makeBasicOp(typ *types.Basic) (op, error) { 153 op := basicOp{typ: typ} 154 kind := typ.Kind() 155 switch { 156 case kind == types.Bool: 157 op.writeMethod = "WriteBool" 158 op.writeArgType = types.Typ[types.Bool] 159 op.decMethod = "Bool" 160 op.decResultType = types.Typ[types.Bool] 161 case kind >= types.Uint8 && kind <= types.Uint64: 162 op.writeMethod = "WriteUint64" 163 op.writeArgType = types.Typ[types.Uint64] 164 op.decMethod = "Uint" 165 op.decResultType = typ 166 op.decUseBitSize = true 167 case kind == types.String: 168 op.writeMethod = "WriteString" 169 op.writeArgType = types.Typ[types.String] 170 op.decMethod = "String" 171 op.decResultType = types.Typ[types.String] 172 default: 173 return nil, fmt.Errorf("unhandled basic type: %v", typ) 174 } 175 return op, nil 176 } 177 178 func (*buildContext) makeByteSliceOp(typ *types.Slice) op { 179 if !isByte(typ.Elem()) { 180 panic("non-byte slice type in makeByteSliceOp") 181 } 182 bslice := types.NewSlice(types.Typ[types.Uint8]) 183 return basicOp{ 184 typ: typ, 185 writeMethod: "WriteBytes", 186 writeArgType: bslice, 187 decMethod: "Bytes", 188 decResultType: bslice, 189 } 190 } 191 192 func (bctx *buildContext) makeRawValueOp() op { 193 bslice := types.NewSlice(types.Typ[types.Uint8]) 194 return basicOp{ 195 typ: bctx.rawValueType, 196 writeMethod: "Write", 197 writeArgType: bslice, 198 decMethod: "Raw", 199 decResultType: bslice, 200 } 201 } 202 203 func (op basicOp) writeNeedsConversion() bool { 204 return !types.AssignableTo(op.typ, op.writeArgType) 205 } 206 207 func (op basicOp) decodeNeedsConversion() bool { 208 return !types.AssignableTo(op.decResultType, op.typ) 209 } 210 211 func (op basicOp) genWrite(ctx *genContext, v string) string { 212 if op.writeNeedsConversion() { 213 v = fmt.Sprintf("%s(%s)", op.writeArgType, v) 214 } 215 return fmt.Sprintf("w.%s(%s)\n", op.writeMethod, v) 216 } 217 218 func (op basicOp) genDecode(ctx *genContext) (string, string) { 219 var ( 220 resultV = ctx.temp() 221 result = resultV 222 method = op.decMethod 223 ) 224 if op.decUseBitSize { 225 // Note: For now, this only works for platform-independent integer 226 // sizes. makeBasicOp forbids the platform-dependent types. 227 var sizes types.StdSizes 228 method = fmt.Sprintf("%s%d", op.decMethod, sizes.Sizeof(op.typ)*8) 229 } 230 231 // Call the decoder method. 232 var b bytes.Buffer 233 fmt.Fprintf(&b, "%s, err := dec.%s()\n", resultV, method) 234 fmt.Fprintf(&b, "if err != nil { return err }\n") 235 if op.decodeNeedsConversion() { 236 conv := ctx.temp() 237 fmt.Fprintf(&b, "%s := %s(%s)\n", conv, types.TypeString(op.typ, ctx.qualify), resultV) 238 result = conv 239 } 240 return result, b.String() 241 } 242 243 // byteArrayOp handles [...]byte. 244 type byteArrayOp struct { 245 typ types.Type 246 name types.Type // name != typ for named byte array types (e.g. common.Address) 247 } 248 249 func (bctx *buildContext) makeByteArrayOp(name *types.Named, typ *types.Array) byteArrayOp { 250 nt := types.Type(name) 251 if name == nil { 252 nt = typ 253 } 254 return byteArrayOp{typ, nt} 255 } 256 257 func (op byteArrayOp) genWrite(ctx *genContext, v string) string { 258 return fmt.Sprintf("w.WriteBytes(%s[:])\n", v) 259 } 260 261 func (op byteArrayOp) genDecode(ctx *genContext) (string, string) { 262 var resultV = ctx.temp() 263 264 var b bytes.Buffer 265 fmt.Fprintf(&b, "var %s %s\n", resultV, types.TypeString(op.name, ctx.qualify)) 266 fmt.Fprintf(&b, "if err := dec.ReadBytes(%s[:]); err != nil { return err }\n", resultV) 267 return resultV, b.String() 268 } 269 270 // bigIntNoPtrOp handles non-pointer big.Int. 271 // This exists because big.Int has it's own decoder operation on rlp.Stream, 272 // but the decode method returns *big.Int, so it needs to be dereferenced. 273 type bigIntOp struct { 274 pointer bool 275 } 276 277 func (op bigIntOp) genWrite(ctx *genContext, v string) string { 278 var b bytes.Buffer 279 280 fmt.Fprintf(&b, "if %s.Sign() == -1 {\n", v) 281 fmt.Fprintf(&b, " return rlp.ErrNegativeBigInt\n") 282 fmt.Fprintf(&b, "}\n") 283 dst := v 284 if !op.pointer { 285 dst = "&" + v 286 } 287 fmt.Fprintf(&b, "w.WriteBigInt(%s)\n", dst) 288 289 // Wrap with nil check. 290 if op.pointer { 291 code := b.String() 292 b.Reset() 293 fmt.Fprintf(&b, "if %s == nil {\n", v) 294 fmt.Fprintf(&b, " w.Write(rlp.EmptyString)") 295 fmt.Fprintf(&b, "} else {\n") 296 fmt.Fprint(&b, code) 297 fmt.Fprintf(&b, "}\n") 298 } 299 300 return b.String() 301 } 302 303 func (op bigIntOp) genDecode(ctx *genContext) (string, string) { 304 var resultV = ctx.temp() 305 306 var b bytes.Buffer 307 fmt.Fprintf(&b, "%s, err := dec.BigInt()\n", resultV) 308 fmt.Fprintf(&b, "if err != nil { return err }\n") 309 310 result := resultV 311 if !op.pointer { 312 result = "(*" + resultV + ")" 313 } 314 return result, b.String() 315 } 316 317 // encoderDecoderOp handles rlp.Encoder and rlp.Decoder. 318 // In order to be used with this, the type must implement both interfaces. 319 // This restriction may be lifted in the future by creating separate ops for 320 // encoding and decoding. 321 type encoderDecoderOp struct { 322 typ types.Type 323 } 324 325 func (op encoderDecoderOp) genWrite(ctx *genContext, v string) string { 326 return fmt.Sprintf("if err := %s.EncodeRLP(w); err != nil { return err }\n", v) 327 } 328 329 func (op encoderDecoderOp) genDecode(ctx *genContext) (string, string) { 330 // DecodeRLP must have pointer receiver, and this is verified in makeOp. 331 etyp := op.typ.(*types.Pointer).Elem() 332 var resultV = ctx.temp() 333 334 var b bytes.Buffer 335 fmt.Fprintf(&b, "%s := new(%s)\n", resultV, types.TypeString(etyp, ctx.qualify)) 336 fmt.Fprintf(&b, "if err := %s.DecodeRLP(dec); err != nil { return err }\n", resultV) 337 return resultV, b.String() 338 } 339 340 // ptrOp handles pointer types. 341 type ptrOp struct { 342 elemTyp types.Type 343 elem op 344 nilOK bool 345 nilValue rlpstruct.NilKind 346 } 347 348 func (bctx *buildContext) makePtrOp(elemTyp types.Type, tags rlpstruct.Tags) (op, error) { 349 elemOp, err := bctx.makeOp(nil, elemTyp, rlpstruct.Tags{}) 350 if err != nil { 351 return nil, err 352 } 353 op := ptrOp{elemTyp: elemTyp, elem: elemOp} 354 355 // Determine nil value. 356 if tags.NilOK { 357 op.nilOK = true 358 op.nilValue = tags.NilKind 359 } else { 360 styp := bctx.typeToStructType(elemTyp) 361 op.nilValue = styp.DefaultNilValue() 362 } 363 return op, nil 364 } 365 366 func (op ptrOp) genWrite(ctx *genContext, v string) string { 367 // Note: in writer functions, accesses to v are read-only, i.e. v is any Go 368 // expression. To make all accesses work through the pointer, we substitute 369 // v with (*v). This is required for most accesses including `v`, `call(v)`, 370 // and `v[index]` on slices. 371 // 372 // For `v.field` and `v[:]` on arrays, the dereference operation is not required. 373 var vv string 374 _, isStruct := op.elem.(structOp) 375 _, isByteArray := op.elem.(byteArrayOp) 376 if isStruct || isByteArray { 377 vv = v 378 } else { 379 vv = fmt.Sprintf("(*%s)", v) 380 } 381 382 var b bytes.Buffer 383 fmt.Fprintf(&b, "if %s == nil {\n", v) 384 fmt.Fprintf(&b, " w.Write([]byte{0x%X})\n", op.nilValue) 385 fmt.Fprintf(&b, "} else {\n") 386 fmt.Fprintf(&b, " %s", op.elem.genWrite(ctx, vv)) 387 fmt.Fprintf(&b, "}\n") 388 return b.String() 389 } 390 391 func (op ptrOp) genDecode(ctx *genContext) (string, string) { 392 result, code := op.elem.genDecode(ctx) 393 if !op.nilOK { 394 // If nil pointers are not allowed, we can just decode the element. 395 return "&" + result, code 396 } 397 398 // nil is allowed, so check the kind and size first. 399 // If size is zero and kind matches the nilKind of the type, 400 // the value decodes as a nil pointer. 401 var ( 402 resultV = ctx.temp() 403 kindV = ctx.temp() 404 sizeV = ctx.temp() 405 wantKind string 406 ) 407 if op.nilValue == rlpstruct.NilKindList { 408 wantKind = "rlp.List" 409 } else { 410 wantKind = "rlp.String" 411 } 412 var b bytes.Buffer 413 fmt.Fprintf(&b, "var %s %s\n", resultV, types.TypeString(types.NewPointer(op.elemTyp), ctx.qualify)) 414 fmt.Fprintf(&b, "if %s, %s, err := dec.Kind(); err != nil {\n", kindV, sizeV) 415 fmt.Fprintf(&b, " return err\n") 416 fmt.Fprintf(&b, "} else if %s != 0 || %s != %s {\n", sizeV, kindV, wantKind) 417 fmt.Fprint(&b, code) 418 fmt.Fprintf(&b, " %s = &%s\n", resultV, result) 419 fmt.Fprintf(&b, "}\n") 420 return resultV, b.String() 421 } 422 423 // structOp handles struct types. 424 type structOp struct { 425 named *types.Named 426 typ *types.Struct 427 fields []*structField 428 optionalFields []*structField 429 } 430 431 type structField struct { 432 name string 433 typ types.Type 434 elem op 435 } 436 437 func (bctx *buildContext) makeStructOp(named *types.Named, typ *types.Struct) (op, error) { 438 // Convert fields to []rlpstruct.Field. 439 var allStructFields []rlpstruct.Field 440 for i := 0; i < typ.NumFields(); i++ { 441 f := typ.Field(i) 442 allStructFields = append(allStructFields, rlpstruct.Field{ 443 Name: f.Name(), 444 Exported: f.Exported(), 445 Index: i, 446 Tag: typ.Tag(i), 447 Type: *bctx.typeToStructType(f.Type()), 448 }) 449 } 450 451 // Filter/validate fields. 452 fields, tags, err := rlpstruct.ProcessFields(allStructFields) 453 if err != nil { 454 return nil, err 455 } 456 457 // Create field ops. 458 var op = structOp{named: named, typ: typ} 459 for i, field := range fields { 460 // Advanced struct tags are not supported yet. 461 tag := tags[i] 462 if err := checkUnsupportedTags(field.Name, tag); err != nil { 463 return nil, err 464 } 465 typ := typ.Field(field.Index).Type() 466 elem, err := bctx.makeOp(nil, typ, tags[i]) 467 if err != nil { 468 return nil, fmt.Errorf("field %s: %v", field.Name, err) 469 } 470 f := &structField{name: field.Name, typ: typ, elem: elem} 471 if tag.Optional { 472 op.optionalFields = append(op.optionalFields, f) 473 } else { 474 op.fields = append(op.fields, f) 475 } 476 } 477 return op, nil 478 } 479 480 func checkUnsupportedTags(field string, tag rlpstruct.Tags) error { 481 if tag.Tail { 482 return fmt.Errorf(`field %s has unsupported struct tag "tail"`, field) 483 } 484 return nil 485 } 486 487 func (op structOp) genWrite(ctx *genContext, v string) string { 488 var b bytes.Buffer 489 var listMarker = ctx.temp() 490 fmt.Fprintf(&b, "%s := w.List()\n", listMarker) 491 for _, field := range op.fields { 492 selector := v + "." + field.name 493 fmt.Fprint(&b, field.elem.genWrite(ctx, selector)) 494 } 495 op.writeOptionalFields(&b, ctx, v) 496 fmt.Fprintf(&b, "w.ListEnd(%s)\n", listMarker) 497 return b.String() 498 } 499 500 func (op structOp) writeOptionalFields(b *bytes.Buffer, ctx *genContext, v string) { 501 if len(op.optionalFields) == 0 { 502 return 503 } 504 // First check zero-ness of all optional fields. 505 var zeroV = make([]string, len(op.optionalFields)) 506 for i, field := range op.optionalFields { 507 selector := v + "." + field.name 508 zeroV[i] = ctx.temp() 509 fmt.Fprintf(b, "%s := %s\n", zeroV[i], nonZeroCheck(selector, field.typ, ctx.qualify)) 510 } 511 // Now write the fields. 512 for i, field := range op.optionalFields { 513 selector := v + "." + field.name 514 cond := "" 515 for j := i; j < len(op.optionalFields); j++ { 516 if j > i { 517 cond += " || " 518 } 519 cond += zeroV[j] 520 } 521 fmt.Fprintf(b, "if %s {\n", cond) 522 fmt.Fprint(b, field.elem.genWrite(ctx, selector)) 523 fmt.Fprintf(b, "}\n") 524 } 525 } 526 527 func (op structOp) genDecode(ctx *genContext) (string, string) { 528 // Get the string representation of the type. 529 // Here, named types are handled separately because the output 530 // would contain a copy of the struct definition otherwise. 531 var typeName string 532 if op.named != nil { 533 typeName = types.TypeString(op.named, ctx.qualify) 534 } else { 535 typeName = types.TypeString(op.typ, ctx.qualify) 536 } 537 538 // Create struct object. 539 var resultV = ctx.temp() 540 var b bytes.Buffer 541 fmt.Fprintf(&b, "var %s %s\n", resultV, typeName) 542 543 // Decode fields. 544 fmt.Fprintf(&b, "{\n") 545 fmt.Fprintf(&b, "if _, err := dec.List(); err != nil { return err }\n") 546 for _, field := range op.fields { 547 result, code := field.elem.genDecode(ctx) 548 fmt.Fprintf(&b, "// %s:\n", field.name) 549 fmt.Fprint(&b, code) 550 fmt.Fprintf(&b, "%s.%s = %s\n", resultV, field.name, result) 551 } 552 op.decodeOptionalFields(&b, ctx, resultV) 553 fmt.Fprintf(&b, "if err := dec.ListEnd(); err != nil { return err }\n") 554 fmt.Fprintf(&b, "}\n") 555 return resultV, b.String() 556 } 557 558 func (op structOp) decodeOptionalFields(b *bytes.Buffer, ctx *genContext, resultV string) { 559 var suffix bytes.Buffer 560 for _, field := range op.optionalFields { 561 result, code := field.elem.genDecode(ctx) 562 fmt.Fprintf(b, "// %s:\n", field.name) 563 fmt.Fprintf(b, "if dec.MoreDataInList() {\n") 564 fmt.Fprint(b, code) 565 fmt.Fprintf(b, "%s.%s = %s\n", resultV, field.name, result) 566 fmt.Fprintf(&suffix, "}\n") 567 } 568 suffix.WriteTo(b) 569 } 570 571 // sliceOp handles slice types. 572 type sliceOp struct { 573 typ *types.Slice 574 elemOp op 575 } 576 577 func (bctx *buildContext) makeSliceOp(typ *types.Slice) (op, error) { 578 elemOp, err := bctx.makeOp(nil, typ.Elem(), rlpstruct.Tags{}) 579 if err != nil { 580 return nil, err 581 } 582 return sliceOp{typ: typ, elemOp: elemOp}, nil 583 } 584 585 func (op sliceOp) genWrite(ctx *genContext, v string) string { 586 var ( 587 listMarker = ctx.temp() // holds return value of w.List() 588 iterElemV = ctx.temp() // iteration variable 589 elemCode = op.elemOp.genWrite(ctx, iterElemV) 590 ) 591 592 var b bytes.Buffer 593 fmt.Fprintf(&b, "%s := w.List()\n", listMarker) 594 fmt.Fprintf(&b, "for _, %s := range %s {\n", iterElemV, v) 595 fmt.Fprint(&b, elemCode) 596 fmt.Fprintf(&b, "}\n") 597 fmt.Fprintf(&b, "w.ListEnd(%s)\n", listMarker) 598 return b.String() 599 } 600 601 func (op sliceOp) genDecode(ctx *genContext) (string, string) { 602 var sliceV = ctx.temp() // holds the output slice 603 elemResult, elemCode := op.elemOp.genDecode(ctx) 604 605 var b bytes.Buffer 606 fmt.Fprintf(&b, "var %s %s\n", sliceV, types.TypeString(op.typ, ctx.qualify)) 607 fmt.Fprintf(&b, "if _, err := dec.List(); err != nil { return err }\n") 608 fmt.Fprintf(&b, "for dec.MoreDataInList() {\n") 609 fmt.Fprintf(&b, " %s", elemCode) 610 fmt.Fprintf(&b, " %s = append(%s, %s)\n", sliceV, sliceV, elemResult) 611 fmt.Fprintf(&b, "}\n") 612 fmt.Fprintf(&b, "if err := dec.ListEnd(); err != nil { return err }\n") 613 return sliceV, b.String() 614 } 615 616 func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstruct.Tags) (op, error) { 617 switch typ := typ.(type) { 618 case *types.Named: 619 if isBigInt(typ) { 620 return bigIntOp{}, nil 621 } 622 if typ == bctx.rawValueType { 623 return bctx.makeRawValueOp(), nil 624 } 625 if bctx.isDecoder(typ) { 626 return nil, fmt.Errorf("type %v implements rlp.Decoder with non-pointer receiver", typ) 627 } 628 // TODO: same check for encoder? 629 return bctx.makeOp(typ, typ.Underlying(), tags) 630 case *types.Pointer: 631 if isBigInt(typ.Elem()) { 632 return bigIntOp{pointer: true}, nil 633 } 634 // Encoder/Decoder interfaces. 635 if bctx.isEncoder(typ) { 636 if bctx.isDecoder(typ) { 637 return encoderDecoderOp{typ}, nil 638 } 639 return nil, fmt.Errorf("type %v implements rlp.Encoder but not rlp.Decoder", typ) 640 } 641 if bctx.isDecoder(typ) { 642 return nil, fmt.Errorf("type %v implements rlp.Decoder but not rlp.Encoder", typ) 643 } 644 // Default pointer handling. 645 return bctx.makePtrOp(typ.Elem(), tags) 646 case *types.Basic: 647 return bctx.makeBasicOp(typ) 648 case *types.Struct: 649 return bctx.makeStructOp(name, typ) 650 case *types.Slice: 651 etyp := typ.Elem() 652 if isByte(etyp) && !bctx.isEncoder(etyp) { 653 return bctx.makeByteSliceOp(typ), nil 654 } 655 return bctx.makeSliceOp(typ) 656 case *types.Array: 657 etyp := typ.Elem() 658 if isByte(etyp) && !bctx.isEncoder(etyp) { 659 return bctx.makeByteArrayOp(name, typ), nil 660 } 661 return nil, fmt.Errorf("unhandled array type: %v", typ) 662 default: 663 return nil, fmt.Errorf("unhandled type: %v", typ) 664 } 665 } 666 667 // generateDecoder generates the DecodeRLP method on 'typ'. 668 func generateDecoder(ctx *genContext, typ string, op op) []byte { 669 ctx.resetTemp() 670 ctx.addImport(pathOfPackageRLP) 671 672 result, code := op.genDecode(ctx) 673 var b bytes.Buffer 674 fmt.Fprintf(&b, "func (obj *%s) DecodeRLP(dec *rlp.Stream) error {\n", typ) 675 fmt.Fprint(&b, code) 676 fmt.Fprintf(&b, " *obj = %s\n", result) 677 fmt.Fprintf(&b, " return nil\n") 678 fmt.Fprintf(&b, "}\n") 679 return b.Bytes() 680 } 681 682 // generateEncoder generates the EncodeRLP method on 'typ'. 683 func generateEncoder(ctx *genContext, typ string, op op) []byte { 684 ctx.resetTemp() 685 ctx.addImport("io") 686 ctx.addImport(pathOfPackageRLP) 687 688 var b bytes.Buffer 689 fmt.Fprintf(&b, "func (obj *%s) EncodeRLP(_w io.Writer) error {\n", typ) 690 fmt.Fprintf(&b, " w := rlp.NewEncoderBuffer(_w)\n") 691 fmt.Fprint(&b, op.genWrite(ctx, "obj")) 692 fmt.Fprintf(&b, " return w.Flush()\n") 693 fmt.Fprintf(&b, "}\n") 694 return b.Bytes() 695 } 696 697 func (bctx *buildContext) generate(typ *types.Named, encoder, decoder bool) ([]byte, error) { 698 bctx.topType = typ 699 700 pkg := typ.Obj().Pkg() 701 op, err := bctx.makeOp(nil, typ, rlpstruct.Tags{}) 702 if err != nil { 703 return nil, err 704 } 705 706 var ( 707 ctx = newGenContext(pkg) 708 encSource []byte 709 decSource []byte 710 ) 711 if encoder { 712 encSource = generateEncoder(ctx, typ.Obj().Name(), op) 713 } 714 if decoder { 715 decSource = generateDecoder(ctx, typ.Obj().Name(), op) 716 } 717 718 var b bytes.Buffer 719 fmt.Fprintf(&b, "package %s\n\n", pkg.Name()) 720 for _, imp := range ctx.importsList() { 721 fmt.Fprintf(&b, "import %q\n", imp) 722 } 723 if encoder { 724 fmt.Fprintln(&b) 725 b.Write(encSource) 726 } 727 if decoder { 728 fmt.Fprintln(&b) 729 b.Write(decSource) 730 } 731 732 source := b.Bytes() 733 // fmt.Println(string(source)) 734 return format.Source(source) 735 }