github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/decoder_config.go (about) 1 package jzon 2 3 import ( 4 "io" 5 "reflect" 6 "sync" 7 "sync/atomic" 8 ) 9 10 var ( 11 // DefaultDecoderConfig is compatible with standard lib 12 DefaultDecoderConfig = NewDecoderConfig(nil) 13 ) 14 15 // DecoderOption can be used to customize the decoder config 16 type DecoderOption struct { 17 // custom value decoders 18 ValDecoders map[reflect.Type]ValDecoder 19 20 // if the object key is case sensitive 21 // `false` by default 22 CaseSensitive bool 23 24 // the tag name for structures 25 // `json` by default 26 Tag string 27 28 OnlyTaggedField bool 29 30 UseNumber bool 31 32 DisallowUnknownFields bool 33 } 34 35 type decoderCache = map[rtype]ValDecoder 36 37 // DecoderConfig is a frozen config for decoding 38 type DecoderConfig struct { 39 cacheMu sync.Mutex 40 decoderCache atomic.Value 41 42 // fixed config, cannot override during runtime 43 caseSensitive bool 44 tag string 45 onlyTaggedField bool 46 47 // can override during runtime 48 useNumber bool 49 disallowUnknownFields bool 50 } 51 52 // NewDecoderConfig returns a new decoder config 53 // If the input option is nil, the default option will be applied 54 func NewDecoderConfig(opt *DecoderOption) *DecoderConfig { 55 decCfg := DecoderConfig{ 56 tag: "json", 57 } 58 // add decoders to cache 59 cache := decoderCache{} 60 if opt != nil { 61 for elemTyp, valDec := range opt.ValDecoders { 62 cache[rtypeOfType(reflect.PtrTo(elemTyp))] = valDec 63 } 64 decCfg.caseSensitive = opt.CaseSensitive 65 if opt.Tag != "" { 66 decCfg.tag = opt.Tag 67 } 68 decCfg.onlyTaggedField = opt.OnlyTaggedField 69 decCfg.useNumber = opt.UseNumber 70 decCfg.disallowUnknownFields = opt.DisallowUnknownFields 71 } 72 decCfg.decoderCache.Store(cache) 73 return &decCfg 74 } 75 76 // Unmarshal behave like json.Unmarshal 77 func (decCfg *DecoderConfig) Unmarshal(data []byte, obj interface{}) error { 78 it := decCfg.NewIterator() 79 err := it.Unmarshal(data, obj) 80 if err != nil { 81 err = it.WrapError(err) 82 } 83 it.Release() 84 return err 85 } 86 87 // UnmarshalFromString behave like json.Unmarshal but with a string 88 func (decCfg *DecoderConfig) UnmarshalFromString(s string, obj interface{}) error { 89 return decCfg.Unmarshal(localStringToBytes(s), obj) 90 } 91 92 // UnmarshalFromReader behave like json.Unmarshal but with an io.Reader 93 func (decCfg *DecoderConfig) UnmarshalFromReader(r io.Reader, obj interface{}) error { 94 it := decCfg.NewIterator() 95 err := it.UnmarshalFromReader(r, obj) 96 if err != nil { 97 err = it.WrapError(err) 98 } 99 it.Release() 100 return err 101 } 102 103 func (decCfg *DecoderConfig) getDecoderFromCache(rType rtype) ValDecoder { 104 return decCfg.decoderCache.Load().(decoderCache)[rType] 105 } 106 107 // NewDecoder returns a new decoder that reads from r. 108 func (decCfg *DecoderConfig) NewDecoder(r io.Reader) *Decoder { 109 it := decCfg.NewIterator() 110 it.Reset(r) 111 return &Decoder{ 112 it: it, 113 } 114 } 115 116 // the typ must be a pointer type 117 func (decCfg *DecoderConfig) createDecoder(rType rtype, ptrType reflect.Type) ValDecoder { 118 decCfg.cacheMu.Lock() 119 defer decCfg.cacheMu.Unlock() 120 cache := decCfg.decoderCache.Load().(decoderCache) 121 // double check 122 if vd := cache[rType]; vd != nil { 123 return vd 124 } 125 // make copy 126 newCache := decoderCache{} 127 for k, v := range cache { 128 newCache[k] = v 129 } 130 var q typeQueue 131 q.push(ptrType) 132 decCfg.createDecoderInternal(newCache, q) 133 decCfg.decoderCache.Store(newCache) 134 return newCache[rType] 135 } 136 137 type decoderBuilder interface { 138 build(cache decoderCache) 139 } 140 141 func (decCfg *DecoderConfig) createDecoderInternal(cache decoderCache, typesToCreate typeQueue) { 142 rebuildMap := map[rtype]decoderBuilder{} 143 for ptrType := typesToCreate.pop(); ptrType != nil; ptrType = typesToCreate.pop() { 144 rType := rtypeOfType(ptrType) 145 if _, ok := cache[rType]; ok { // check if visited 146 continue 147 } 148 // check global decoders 149 if v, ok := globalValDecoders[rType]; ok { 150 cache[rType] = v 151 continue 152 } 153 // check json.Unmarshaler interface 154 if ptrType.Implements(jsonUnmarshalerType) { 155 cache[rType] = jsonUnmarshalerDecoder(rType) 156 continue 157 } 158 if ptrType.Implements(textUnmarshalerType) { 159 cache[rType] = textUnmarshalerDecoder(rType) 160 continue 161 } 162 elem := ptrType.Elem() 163 elemKind := elem.Kind() 164 if elemNativeRType := decoderKindMap[elemKind]; elemNativeRType != 0 { 165 // TODO: shall we make this an option? 166 // TODO: so that only the native type is affected? 167 // check if the native type has a custom decoder 168 if v, ok := cache[elemNativeRType]; ok { 169 cache[rType] = v 170 continue 171 } 172 // otherwise check default native type decoder 173 if v := kindDecoders[elemKind]; v != nil { 174 cache[rType] = v 175 continue 176 } 177 } 178 switch elemKind { 179 case reflect.Interface: 180 if elem.NumMethod() == 0 { 181 cache[rType] = (*efaceDecoder)(nil) 182 } else { 183 cache[rType] = (*ifaceDecoder)(nil) 184 } 185 case reflect.Struct: 186 fields := describeStruct(elem, decCfg.tag, decCfg.onlyTaggedField) 187 numFields := len(fields) 188 if numFields == 0 { 189 cache[rType] = (*emptyObjectDecoder)(nil) 190 continue 191 } 192 for i := range fields { 193 fi := &fields[i] 194 typesToCreate.push(fi.ptrType) 195 } 196 if numFields == 1 { 197 w := newOneFieldStructDecoder(&fields[0], decCfg.caseSensitive) 198 cache[rType] = w.decoder 199 rebuildMap[rType] = w 200 } else if numFields <= 10 { 201 // TODO: determinate the threshold, several factors may be involved: 202 // TODO: 1. number of fields 203 // TODO: 2. (average) field length 204 // TODO: 3. field similarity 205 w := newSmallStructDecoder(fields) 206 cache[rType] = w.decoder 207 rebuildMap[rType] = w 208 } else { 209 w := newStructDecoder(fields) 210 cache[rType] = w.decoder 211 rebuildMap[rType] = w 212 } 213 case reflect.Ptr: 214 typesToCreate.push(elem) 215 w := newPointerDecoder(elem) 216 cache[rType] = w.decoder 217 rebuildMap[rType] = w 218 case reflect.Array: 219 elemPtrType := reflect.PtrTo(elem.Elem()) 220 typesToCreate.push(elemPtrType) 221 w := newArrayDecoder(elem) 222 cache[rType] = w.decoder 223 rebuildMap[rType] = w 224 case reflect.Slice: 225 elemPtrType := reflect.PtrTo(elem.Elem()) 226 typesToCreate.push(elemPtrType) 227 w := newSliceDecoder(elem) 228 cache[rType] = w.decoder 229 rebuildMap[rType] = w 230 case reflect.Map: 231 w := newMapDecoder(elem) 232 if w == nil { 233 cache[rType] = notSupportedDecoder(ptrType.String()) 234 } else { 235 valuePtrType := reflect.PtrTo(elem.Elem()) 236 typesToCreate.push(valuePtrType) 237 cache[rType] = w.decoder 238 rebuildMap[rType] = w 239 } 240 default: 241 cache[rType] = notSupportedDecoder(ptrType.String()) 242 } 243 } 244 // rebuild some decoders 245 for _, builder := range rebuildMap { 246 builder.build(cache) 247 } 248 }