github.com/amazechain/amc@v0.1.3/internal/avm/rlp/typecache.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package rlp
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"strings"
    23  	"sync"
    24  )
    25  
    26  var (
    27  	typeCacheMutex sync.RWMutex
    28  	typeCache      = make(map[typekey]*typeinfo)
    29  )
    30  
    31  type typeinfo struct {
    32  	decoder    decoder
    33  	decoderErr error // error from makeDecoder
    34  	writer     writer
    35  	writerErr  error // error from makeWriter
    36  }
    37  
    38  // tags represents struct tags.
    39  type tags struct {
    40  	// rlp:"nil" controls whether empty input results in a nil pointer.
    41  	// nilKind is the kind of empty value allowed for the field.
    42  	nilKind Kind
    43  	nilOK   bool
    44  
    45  	// rlp:"optional" allows for a field to be missing in the input list.
    46  	// If this is set, all subsequent fields must also be optional.
    47  	optional bool
    48  
    49  	// rlp:"tail" controls whether this field swallows additional list elements. It can
    50  	// only be set for the last field, which must be of slice type.
    51  	tail bool
    52  
    53  	// rlp:"-" ignores fields.
    54  	ignored bool
    55  }
    56  
    57  // typekey is the key of a type in typeCache. It includes the struct tags because
    58  // they might generate a different decoder.
    59  type typekey struct {
    60  	reflect.Type
    61  	tags
    62  }
    63  
    64  type decoder func(*Stream, reflect.Value) error
    65  
    66  type writer func(reflect.Value, *encbuf) error
    67  
    68  func cachedDecoder(typ reflect.Type) (decoder, error) {
    69  	info := cachedTypeInfo(typ, tags{})
    70  	return info.decoder, info.decoderErr
    71  }
    72  
    73  func cachedWriter(typ reflect.Type) (writer, error) {
    74  	info := cachedTypeInfo(typ, tags{})
    75  	return info.writer, info.writerErr
    76  }
    77  
    78  func cachedTypeInfo(typ reflect.Type, tags tags) *typeinfo {
    79  	typeCacheMutex.RLock()
    80  	info := typeCache[typekey{typ, tags}]
    81  	typeCacheMutex.RUnlock()
    82  	if info != nil {
    83  		return info
    84  	}
    85  	// not in the cache, need to generate info for this type.
    86  	typeCacheMutex.Lock()
    87  	defer typeCacheMutex.Unlock()
    88  	return cachedTypeInfo1(typ, tags)
    89  }
    90  
    91  func cachedTypeInfo1(typ reflect.Type, tags tags) *typeinfo {
    92  	key := typekey{typ, tags}
    93  	info := typeCache[key]
    94  	if info != nil {
    95  		// another goroutine got the write lock first
    96  		return info
    97  	}
    98  	// put a dummy value into the cache before generating.
    99  	// if the generator tries to lookup itself, it will get
   100  	// the dummy value and won't call itself recursively.
   101  	info = new(typeinfo)
   102  	typeCache[key] = info
   103  	info.generate(typ, tags)
   104  	return info
   105  }
   106  
   107  type field struct {
   108  	index    int
   109  	info     *typeinfo
   110  	optional bool
   111  }
   112  
   113  // structFields resolves the typeinfo of all public fields in a struct type.
   114  func structFields(typ reflect.Type) (fields []field, err error) {
   115  	var (
   116  		lastPublic  = lastPublicField(typ)
   117  		anyOptional = false
   118  	)
   119  	for i := 0; i < typ.NumField(); i++ {
   120  		if f := typ.Field(i); f.PkgPath == "" { // exported
   121  			tags, err := parseStructTag(typ, i, lastPublic)
   122  			if err != nil {
   123  				return nil, err
   124  			}
   125  
   126  			// Skip rlp:"-" fields.
   127  			if tags.ignored {
   128  				continue
   129  			}
   130  			// If any field has the "optional" tag, subsequent fields must also have it.
   131  			if tags.optional || tags.tail {
   132  				anyOptional = true
   133  			} else if anyOptional {
   134  				return nil, fmt.Errorf(`rlp: struct field %v.%s needs "optional" tag`, typ, f.Name)
   135  			}
   136  			info := cachedTypeInfo1(f.Type, tags)
   137  			fields = append(fields, field{i, info, tags.optional})
   138  		}
   139  	}
   140  	return fields, nil
   141  }
   142  
   143  // anyOptionalFields returns the index of the first field with "optional" tag.
   144  func firstOptionalField(fields []field) int {
   145  	for i, f := range fields {
   146  		if f.optional {
   147  			return i
   148  		}
   149  	}
   150  	return len(fields)
   151  }
   152  
   153  type structFieldError struct {
   154  	typ   reflect.Type
   155  	field int
   156  	err   error
   157  }
   158  
   159  func (e structFieldError) Error() string {
   160  	return fmt.Sprintf("%v (struct field %v.%s)", e.err, e.typ, e.typ.Field(e.field).Name)
   161  }
   162  
   163  type structTagError struct {
   164  	typ             reflect.Type
   165  	field, tag, err string
   166  }
   167  
   168  func (e structTagError) Error() string {
   169  	return fmt.Sprintf("rlp: invalid struct tag %q for %v.%s (%s)", e.tag, e.typ, e.field, e.err)
   170  }
   171  
   172  func parseStructTag(typ reflect.Type, fi, lastPublic int) (tags, error) {
   173  	f := typ.Field(fi)
   174  	var ts tags
   175  	for _, t := range strings.Split(f.Tag.Get("rlp"), ",") {
   176  		switch t = strings.TrimSpace(t); t {
   177  		case "":
   178  		case "-":
   179  			ts.ignored = true
   180  		case "nil", "nilString", "nilList":
   181  			ts.nilOK = true
   182  			if f.Type.Kind() != reflect.Ptr {
   183  				return ts, structTagError{typ, f.Name, t, "field is not a pointer"}
   184  			}
   185  			switch t {
   186  			case "nil":
   187  				ts.nilKind = defaultNilKind(f.Type.Elem())
   188  			case "nilString":
   189  				ts.nilKind = String
   190  			case "nilList":
   191  				ts.nilKind = List
   192  			}
   193  		case "optional":
   194  			ts.optional = true
   195  			if ts.tail {
   196  				return ts, structTagError{typ, f.Name, t, `also has "tail" tag`}
   197  			}
   198  		case "tail":
   199  			ts.tail = true
   200  			if fi != lastPublic {
   201  				return ts, structTagError{typ, f.Name, t, "must be on last field"}
   202  			}
   203  			if ts.optional {
   204  				return ts, structTagError{typ, f.Name, t, `also has "optional" tag`}
   205  			}
   206  			if f.Type.Kind() != reflect.Slice {
   207  				return ts, structTagError{typ, f.Name, t, "field type is not slice"}
   208  			}
   209  		default:
   210  			return ts, fmt.Errorf("rlp: unknown struct tag %q on %v.%s", t, typ, f.Name)
   211  		}
   212  	}
   213  	return ts, nil
   214  }
   215  
   216  func lastPublicField(typ reflect.Type) int {
   217  	last := 0
   218  	for i := 0; i < typ.NumField(); i++ {
   219  		if typ.Field(i).PkgPath == "" {
   220  			last = i
   221  		}
   222  	}
   223  	return last
   224  }
   225  
   226  func (i *typeinfo) generate(typ reflect.Type, tags tags) {
   227  	i.decoder, i.decoderErr = makeDecoder(typ, tags)
   228  	i.writer, i.writerErr = makeWriter(typ, tags)
   229  }
   230  
   231  // defaultNilKind determines whether a nil pointer to typ encodes/decodes
   232  // as an empty string or empty list.
   233  func defaultNilKind(typ reflect.Type) Kind {
   234  	k := typ.Kind()
   235  	if isUint(k) || k == reflect.String || k == reflect.Bool || isByteArray(typ) {
   236  		return String
   237  	}
   238  	return List
   239  }
   240  
   241  func isUint(k reflect.Kind) bool {
   242  	return k >= reflect.Uint && k <= reflect.Uintptr
   243  }
   244  
   245  func isByte(typ reflect.Type) bool {
   246  	return typ.Kind() == reflect.Uint8 && !typ.Implements(encoderInterface)
   247  }
   248  
   249  func isByteArray(typ reflect.Type) bool {
   250  	return (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Array) && isByte(typ.Elem())
   251  }