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 }