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  }