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