github.com/klaytn/klaytn@v1.10.2/rlp/typecache.go (about)

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