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