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  }