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 }