github.com/jimmyx0x/go-ethereum@v1.10.28/rlp/typecache.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package rlp
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"sync"
    23  	"sync/atomic"
    24  
    25  	"github.com/ethereum/go-ethereum/rlp/internal/rlpstruct"
    26  )
    27  
    28  // typeinfo is an entry in the type cache.
    29  type typeinfo struct {
    30  	decoder    decoder
    31  	decoderErr error // error from makeDecoder
    32  	writer     writer
    33  	writerErr  error // error from makeWriter
    34  }
    35  
    36  // typekey is the key of a type in typeCache. It includes the struct tags because
    37  // they might generate a different decoder.
    38  type typekey struct {
    39  	reflect.Type
    40  	rlpstruct.Tags
    41  }
    42  
    43  type decoder func(*Stream, reflect.Value) error
    44  
    45  type writer func(reflect.Value, *encBuffer) error
    46  
    47  var theTC = newTypeCache()
    48  
    49  type typeCache struct {
    50  	cur atomic.Value
    51  
    52  	// This lock synchronizes writers.
    53  	mu   sync.Mutex
    54  	next map[typekey]*typeinfo
    55  }
    56  
    57  func newTypeCache() *typeCache {
    58  	c := new(typeCache)
    59  	c.cur.Store(make(map[typekey]*typeinfo))
    60  	return c
    61  }
    62  
    63  func cachedDecoder(typ reflect.Type) (decoder, error) {
    64  	info := theTC.info(typ)
    65  	return info.decoder, info.decoderErr
    66  }
    67  
    68  func cachedWriter(typ reflect.Type) (writer, error) {
    69  	info := theTC.info(typ)
    70  	return info.writer, info.writerErr
    71  }
    72  
    73  func (c *typeCache) info(typ reflect.Type) *typeinfo {
    74  	key := typekey{Type: typ}
    75  	if info := c.cur.Load().(map[typekey]*typeinfo)[key]; info != nil {
    76  		return info
    77  	}
    78  
    79  	// Not in the cache, need to generate info for this type.
    80  	return c.generate(typ, rlpstruct.Tags{})
    81  }
    82  
    83  func (c *typeCache) generate(typ reflect.Type, tags rlpstruct.Tags) *typeinfo {
    84  	c.mu.Lock()
    85  	defer c.mu.Unlock()
    86  
    87  	cur := c.cur.Load().(map[typekey]*typeinfo)
    88  	if info := cur[typekey{typ, tags}]; info != nil {
    89  		return info
    90  	}
    91  
    92  	// Copy cur to next.
    93  	c.next = make(map[typekey]*typeinfo, len(cur)+1)
    94  	for k, v := range cur {
    95  		c.next[k] = v
    96  	}
    97  
    98  	// Generate.
    99  	info := c.infoWhileGenerating(typ, tags)
   100  
   101  	// next -> cur
   102  	c.cur.Store(c.next)
   103  	c.next = nil
   104  	return info
   105  }
   106  
   107  func (c *typeCache) infoWhileGenerating(typ reflect.Type, tags rlpstruct.Tags) *typeinfo {
   108  	key := typekey{typ, tags}
   109  	if info := c.next[key]; info != nil {
   110  		return info
   111  	}
   112  	// Put a dummy value into the cache before generating.
   113  	// If the generator tries to lookup itself, it will get
   114  	// the dummy value and won't call itself recursively.
   115  	info := new(typeinfo)
   116  	c.next[key] = info
   117  	info.generate(typ, tags)
   118  	return info
   119  }
   120  
   121  type field struct {
   122  	index    int
   123  	info     *typeinfo
   124  	optional bool
   125  }
   126  
   127  // structFields resolves the typeinfo of all public fields in a struct type.
   128  func structFields(typ reflect.Type) (fields []field, err error) {
   129  	// Convert fields to rlpstruct.Field.
   130  	var allStructFields []rlpstruct.Field
   131  	for i := 0; i < typ.NumField(); i++ {
   132  		rf := typ.Field(i)
   133  		allStructFields = append(allStructFields, rlpstruct.Field{
   134  			Name:     rf.Name,
   135  			Index:    i,
   136  			Exported: rf.PkgPath == "",
   137  			Tag:      string(rf.Tag),
   138  			Type:     *rtypeToStructType(rf.Type, nil),
   139  		})
   140  	}
   141  
   142  	// Filter/validate fields.
   143  	structFields, structTags, err := rlpstruct.ProcessFields(allStructFields)
   144  	if err != nil {
   145  		if tagErr, ok := err.(rlpstruct.TagError); ok {
   146  			tagErr.StructType = typ.String()
   147  			return nil, tagErr
   148  		}
   149  		return nil, err
   150  	}
   151  
   152  	// Resolve typeinfo.
   153  	for i, sf := range structFields {
   154  		typ := typ.Field(sf.Index).Type
   155  		tags := structTags[i]
   156  		info := theTC.infoWhileGenerating(typ, tags)
   157  		fields = append(fields, field{sf.Index, info, tags.Optional})
   158  	}
   159  	return fields, nil
   160  }
   161  
   162  // firstOptionalField returns the index of the first field with "optional" tag.
   163  func firstOptionalField(fields []field) int {
   164  	for i, f := range fields {
   165  		if f.optional {
   166  			return i
   167  		}
   168  	}
   169  	return len(fields)
   170  }
   171  
   172  type structFieldError struct {
   173  	typ   reflect.Type
   174  	field int
   175  	err   error
   176  }
   177  
   178  func (e structFieldError) Error() string {
   179  	return fmt.Sprintf("%v (struct field %v.%s)", e.err, e.typ, e.typ.Field(e.field).Name)
   180  }
   181  
   182  func (i *typeinfo) generate(typ reflect.Type, tags rlpstruct.Tags) {
   183  	i.decoder, i.decoderErr = makeDecoder(typ, tags)
   184  	i.writer, i.writerErr = makeWriter(typ, tags)
   185  }
   186  
   187  // rtypeToStructType converts typ to rlpstruct.Type.
   188  func rtypeToStructType(typ reflect.Type, rec map[reflect.Type]*rlpstruct.Type) *rlpstruct.Type {
   189  	k := typ.Kind()
   190  	if k == reflect.Invalid {
   191  		panic("invalid kind")
   192  	}
   193  
   194  	if prev := rec[typ]; prev != nil {
   195  		return prev // short-circuit for recursive types
   196  	}
   197  	if rec == nil {
   198  		rec = make(map[reflect.Type]*rlpstruct.Type)
   199  	}
   200  
   201  	t := &rlpstruct.Type{
   202  		Name:      typ.String(),
   203  		Kind:      k,
   204  		IsEncoder: typ.Implements(encoderInterface),
   205  		IsDecoder: typ.Implements(decoderInterface),
   206  	}
   207  	rec[typ] = t
   208  	if k == reflect.Array || k == reflect.Slice || k == reflect.Ptr {
   209  		t.Elem = rtypeToStructType(typ.Elem(), rec)
   210  	}
   211  	return t
   212  }
   213  
   214  // typeNilKind gives the RLP value kind for nil pointers to 'typ'.
   215  func typeNilKind(typ reflect.Type, tags rlpstruct.Tags) Kind {
   216  	styp := rtypeToStructType(typ, nil)
   217  
   218  	var nk rlpstruct.NilKind
   219  	if tags.NilOK {
   220  		nk = tags.NilKind
   221  	} else {
   222  		nk = styp.DefaultNilValue()
   223  	}
   224  	switch nk {
   225  	case rlpstruct.NilKindString:
   226  		return String
   227  	case rlpstruct.NilKindList:
   228  		return List
   229  	default:
   230  		panic("invalid nil kind value")
   231  	}
   232  }
   233  
   234  func isUint(k reflect.Kind) bool {
   235  	return k >= reflect.Uint && k <= reflect.Uintptr
   236  }
   237  
   238  func isByte(typ reflect.Type) bool {
   239  	return typ.Kind() == reflect.Uint8 && !typ.Implements(encoderInterface)
   240  }