github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/jsoni/reflect_json_number.go (about) 1 package jsoni 2 3 import ( 4 "context" 5 "encoding/json" 6 "strconv" 7 "unsafe" 8 9 "github.com/modern-go/reflect2" 10 ) 11 12 type Number string 13 14 // String returns the literal text of the number. 15 func (n Number) String() string { return string(n) } 16 17 // Float64 returns the number as a float64. 18 func (n Number) Float64() (float64, error) { 19 return strconv.ParseFloat(string(n), 64) 20 } 21 22 // Int64 returns the number as an int64. 23 func (n Number) Int64() (int64, error) { 24 return strconv.ParseInt(string(n), 10, 64) 25 } 26 27 func CastJsonNumber(val interface{}) (string, bool) { 28 switch typedVal := val.(type) { 29 case json.Number: 30 return string(typedVal), true 31 case Number: 32 return string(typedVal), true 33 } 34 return "", false 35 } 36 37 var ( 38 jsonNumberType = PtrElem((*json.Number)(nil)) 39 jsoniNumberType = PtrElem((*Number)(nil)) 40 ) 41 42 func createDecoderOfJsonNumber(_ *ctx, typ reflect2.Type) ValDecoder { 43 if typ.AssignableTo(jsonNumberType) { 44 return &jsonNumberCodec{} 45 } 46 if typ.AssignableTo(jsoniNumberType) { 47 return &jsoniNumberCodec{} 48 } 49 return nil 50 } 51 52 func createEncoderOfJsonNumber(_ *ctx, typ reflect2.Type) ValEncoder { 53 if typ.AssignableTo(jsonNumberType) { 54 return &jsonNumberCodec{} 55 } 56 if typ.AssignableTo(jsoniNumberType) { 57 return &jsoniNumberCodec{} 58 } 59 return nil 60 } 61 62 type jsonNumberCodec struct{} 63 64 func (c *jsonNumberCodec) Decode(_ context.Context, ptr unsafe.Pointer, iter *Iterator) { 65 switch iter.WhatIsNext() { 66 case StringValue: 67 *((*json.Number)(ptr)) = json.Number(iter.ReadString()) 68 case NilValue: 69 iter.skip4Bytes('n', 'u', 'l', 'l') 70 *((*json.Number)(ptr)) = "" 71 default: 72 *((*json.Number)(ptr)) = json.Number(iter.readNumberAsString()) 73 } 74 } 75 76 func (c *jsonNumberCodec) Encode(_ context.Context, ptr unsafe.Pointer, stream *Stream) { 77 if n := *((*json.Number)(ptr)); len(n) == 0 { 78 stream.writeByte('0') 79 } else { 80 stream.WriteRaw(string(n)) 81 } 82 } 83 84 func (c *jsonNumberCodec) IsEmpty(_ context.Context, p unsafe.Pointer, _ bool) bool { 85 return len(*((*json.Number)(p))) == 0 86 } 87 88 type jsoniNumberCodec struct{} 89 90 func (c *jsoniNumberCodec) Decode(_ context.Context, ptr unsafe.Pointer, iter *Iterator) { 91 switch r := (*Number)(ptr); iter.WhatIsNext() { 92 case StringValue: 93 *r = Number(iter.ReadString()) 94 case NilValue: 95 iter.skip4Bytes('n', 'u', 'l', 'l') 96 *r = "" 97 default: 98 *r = Number(iter.readNumberAsString()) 99 } 100 } 101 102 func (c *jsoniNumberCodec) Encode(_ context.Context, ptr unsafe.Pointer, stream *Stream) { 103 if n := *((*Number)(ptr)); len(n) == 0 { 104 stream.writeByte('0') 105 } else { 106 stream.WriteRaw(string(n)) 107 } 108 } 109 110 func (c *jsoniNumberCodec) IsEmpty(_ context.Context, p unsafe.Pointer, _ bool) bool { 111 return len(*((*Number)(p))) == 0 112 }