mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
2.6 KiB
112 lines
2.6 KiB
package jsoniter |
|
|
|
import ( |
|
"encoding/json" |
|
"github.com/modern-go/reflect2" |
|
"strconv" |
|
"unsafe" |
|
) |
|
|
|
type Number string |
|
|
|
// String returns the literal text of the number. |
|
func (n Number) String() string { return string(n) } |
|
|
|
// Float64 returns the number as a float64. |
|
func (n Number) Float64() (float64, error) { |
|
return strconv.ParseFloat(string(n), 64) |
|
} |
|
|
|
// Int64 returns the number as an int64. |
|
func (n Number) Int64() (int64, error) { |
|
return strconv.ParseInt(string(n), 10, 64) |
|
} |
|
|
|
func CastJsonNumber(val interface{}) (string, bool) { |
|
switch typedVal := val.(type) { |
|
case json.Number: |
|
return string(typedVal), true |
|
case Number: |
|
return string(typedVal), true |
|
} |
|
return "", false |
|
} |
|
|
|
var jsonNumberType = reflect2.TypeOfPtr((*json.Number)(nil)).Elem() |
|
var jsoniterNumberType = reflect2.TypeOfPtr((*Number)(nil)).Elem() |
|
|
|
func createDecoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValDecoder { |
|
if typ.AssignableTo(jsonNumberType) { |
|
return &jsonNumberCodec{} |
|
} |
|
if typ.AssignableTo(jsoniterNumberType) { |
|
return &jsoniterNumberCodec{} |
|
} |
|
return nil |
|
} |
|
|
|
func createEncoderOfJsonNumber(ctx *ctx, typ reflect2.Type) ValEncoder { |
|
if typ.AssignableTo(jsonNumberType) { |
|
return &jsonNumberCodec{} |
|
} |
|
if typ.AssignableTo(jsoniterNumberType) { |
|
return &jsoniterNumberCodec{} |
|
} |
|
return nil |
|
} |
|
|
|
type jsonNumberCodec struct { |
|
} |
|
|
|
func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { |
|
switch iter.WhatIsNext() { |
|
case StringValue: |
|
*((*json.Number)(ptr)) = json.Number(iter.ReadString()) |
|
case NilValue: |
|
iter.skipFourBytes('n', 'u', 'l', 'l') |
|
*((*json.Number)(ptr)) = "" |
|
default: |
|
*((*json.Number)(ptr)) = json.Number([]byte(iter.readNumberAsString())) |
|
} |
|
} |
|
|
|
func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { |
|
number := *((*json.Number)(ptr)) |
|
if len(number) == 0 { |
|
stream.writeByte('0') |
|
} else { |
|
stream.WriteRaw(string(number)) |
|
} |
|
} |
|
|
|
func (codec *jsonNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { |
|
return len(*((*json.Number)(ptr))) == 0 |
|
} |
|
|
|
type jsoniterNumberCodec struct { |
|
} |
|
|
|
func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { |
|
switch iter.WhatIsNext() { |
|
case StringValue: |
|
*((*Number)(ptr)) = Number(iter.ReadString()) |
|
case NilValue: |
|
iter.skipFourBytes('n', 'u', 'l', 'l') |
|
*((*Number)(ptr)) = "" |
|
default: |
|
*((*Number)(ptr)) = Number([]byte(iter.readNumberAsString())) |
|
} |
|
} |
|
|
|
func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) { |
|
number := *((*Number)(ptr)) |
|
if len(number) == 0 { |
|
stream.writeByte('0') |
|
} else { |
|
stream.WriteRaw(string(number)) |
|
} |
|
} |
|
|
|
func (codec *jsoniterNumberCodec) IsEmpty(ptr unsafe.Pointer) bool { |
|
return len(*((*Number)(ptr))) == 0 |
|
}
|
|
|