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 }