package extra import ( "github.com/json-iterator/go" "unsafe" "encoding/json" "strings" "math" ) const MaxUint = ^uint(0) const MaxInt = int(MaxUint >> 1) const MinInt = -MaxInt - 1 func RegisterFuzzyDecoders() { jsoniter.RegisterTypeDecoder("string", &FuzzyStringDecoder{}) jsoniter.RegisterTypeDecoder("float32", &FuzzyFloat32Decoder{}) jsoniter.RegisterTypeDecoder("float64", &FuzzyFloat64Decoder{}) jsoniter.RegisterTypeDecoder("int", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(MaxInt) || val < float64(MinInt) { iter.ReportError("fuzzy decode int", "exceed range") return } *((*int)(ptr)) = int(val) } else { *((*int)(ptr)) = iter.ReadInt() } }}) jsoniter.RegisterTypeDecoder("uint", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(MaxUint) || val < 0 { iter.ReportError("fuzzy decode uint", "exceed range") return } *((*uint)(ptr)) = uint(val) } else { *((*uint)(ptr)) = iter.ReadUint() } }}) jsoniter.RegisterTypeDecoder("int8", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxInt8) || val < float64(math.MinInt8) { iter.ReportError("fuzzy decode int8", "exceed range") return } *((*int8)(ptr)) = int8(val) } else { *((*int8)(ptr)) = iter.ReadInt8() } }}) jsoniter.RegisterTypeDecoder("uint8", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxUint8) || val < 0 { iter.ReportError("fuzzy decode uint8", "exceed range") return } *((*uint8)(ptr)) = uint8(val) } else { *((*uint8)(ptr)) = iter.ReadUint8() } }}) jsoniter.RegisterTypeDecoder("int16", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxInt16) || val < float64(math.MinInt16) { iter.ReportError("fuzzy decode int16", "exceed range") return } *((*int16)(ptr)) = int16(val) } else { *((*int16)(ptr)) = iter.ReadInt16() } }}) jsoniter.RegisterTypeDecoder("uint16", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxUint16) || val < 0 { iter.ReportError("fuzzy decode uint16", "exceed range") return } *((*uint16)(ptr)) = uint16(val) } else { *((*uint16)(ptr)) = iter.ReadUint16() } }}) jsoniter.RegisterTypeDecoder("int32", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxInt32) || val < float64(math.MinInt32) { iter.ReportError("fuzzy decode int32", "exceed range") return } *((*int32)(ptr)) = int32(val) } else { *((*int32)(ptr)) = iter.ReadInt32() } }}) jsoniter.RegisterTypeDecoder("uint32", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxUint32) || val < 0 { iter.ReportError("fuzzy decode uint32", "exceed range") return } *((*uint32)(ptr)) = uint32(val) } else { *((*uint32)(ptr)) = iter.ReadUint32() } }}) jsoniter.RegisterTypeDecoder("int64", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxInt64) || val < float64(math.MinInt64) { iter.ReportError("fuzzy decode int64", "exceed range") return } *((*int64)(ptr)) = int64(val) } else { *((*int64)(ptr)) = iter.ReadInt64() } }}) jsoniter.RegisterTypeDecoder("uint64", &FuzzyIntegerDecoder{func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) { if isFloat { val := iter.ReadFloat64() if val > float64(math.MaxUint64) || val < 0 { iter.ReportError("fuzzy decode uint64", "exceed range") return } *((*uint64)(ptr)) = uint64(val) } else { *((*uint64)(ptr)) = iter.ReadUint64() } }}) } type FuzzyStringDecoder struct { } func (decoder *FuzzyStringDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { valueType := iter.WhatIsNext() switch valueType { case jsoniter.Number: var number json.Number iter.ReadVal(&number) *((*string)(ptr)) = string(number) case jsoniter.String: *((*string)(ptr)) = iter.ReadString() default: iter.ReportError("FuzzyStringDecoder", "not number or string") } } type FuzzyIntegerDecoder struct { fun func(isFloat bool, ptr unsafe.Pointer, iter *jsoniter.Iterator) } func (decoder *FuzzyIntegerDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { valueType := iter.WhatIsNext() var str string switch valueType { case jsoniter.Number: var number json.Number iter.ReadVal(&number) str = string(number) case jsoniter.String: str = iter.ReadString() default: iter.ReportError("FuzzyIntegerDecoder", "not number or string") } newIter := iter.Config().BorrowIterator([]byte(str)) defer iter.Config().ReturnIterator(newIter) isFloat := strings.IndexByte(str, '.') != -1 decoder.fun(isFloat, ptr, newIter) if newIter.Error != nil { iter.Error = newIter.Error } } type FuzzyFloat32Decoder struct { } func (decoder *FuzzyFloat32Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { valueType := iter.WhatIsNext() var str string switch valueType { case jsoniter.Number: *((*float32)(ptr)) = iter.ReadFloat32() case jsoniter.String: str = iter.ReadString() newIter := iter.Config().BorrowIterator([]byte(str)) defer iter.Config().ReturnIterator(newIter) *((*float32)(ptr)) = newIter.ReadFloat32() if newIter.Error != nil { iter.Error = newIter.Error } default: iter.ReportError("FuzzyFloat32Decoder", "not number or string") } } type FuzzyFloat64Decoder struct { } func (decoder *FuzzyFloat64Decoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { valueType := iter.WhatIsNext() var str string switch valueType { case jsoniter.Number: *((*float64)(ptr)) = iter.ReadFloat64() case jsoniter.String: str = iter.ReadString() newIter := iter.Config().BorrowIterator([]byte(str)) defer iter.Config().ReturnIterator(newIter) *((*float64)(ptr)) = newIter.ReadFloat64() if newIter.Error != nil { iter.Error = newIter.Error } default: iter.ReportError("FuzzyFloat32Decoder", "not number or string") } }