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  }