mirror of https://github.com/goccy/go-json.git
Merge pull request #14 from goccy/feature/support-json-number
Support json.Number
This commit is contained in:
commit
0943ec9fb8
|
@ -258,5 +258,5 @@ func (d *Decoder) InputOffset() int64 {
|
||||||
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
|
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
|
||||||
// Number instead of as a float64.
|
// Number instead of as a float64.
|
||||||
func (d *Decoder) UseNumber() {
|
func (d *Decoder) UseNumber() {
|
||||||
|
d.s.useNumber = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,20 @@ type interfaceDecoder struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInterfaceDecoder(typ *rtype) *interfaceDecoder {
|
func newInterfaceDecoder(typ *rtype) *interfaceDecoder {
|
||||||
return &interfaceDecoder{typ: typ}
|
return &interfaceDecoder{
|
||||||
|
typ: typ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *interfaceDecoder) numDecoder(s *stream) decoder {
|
||||||
|
if s.useNumber {
|
||||||
|
return newNumberDecoder(func(p uintptr, v Number) {
|
||||||
|
*(*interface{})(unsafe.Pointer(p)) = v
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return newFloatDecoder(func(p uintptr, v float64) {
|
||||||
|
*(*interface{})(unsafe.Pointer(p)) = v
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -28,7 +41,11 @@ func (d *interfaceDecoder) decodeStream(s *stream, p uintptr) error {
|
||||||
var v map[interface{}]interface{}
|
var v map[interface{}]interface{}
|
||||||
ptr := unsafe.Pointer(&v)
|
ptr := unsafe.Pointer(&v)
|
||||||
d.dummy = ptr
|
d.dummy = ptr
|
||||||
dec := newMapDecoder(interfaceMapType, newInterfaceDecoder(d.typ), newInterfaceDecoder(d.typ))
|
dec := newMapDecoder(
|
||||||
|
interfaceMapType,
|
||||||
|
newInterfaceDecoder(d.typ),
|
||||||
|
newInterfaceDecoder(d.typ),
|
||||||
|
)
|
||||||
if err := dec.decodeStream(s, uintptr(ptr)); err != nil {
|
if err := dec.decodeStream(s, uintptr(ptr)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -38,16 +55,18 @@ func (d *interfaceDecoder) decodeStream(s *stream, p uintptr) error {
|
||||||
var v []interface{}
|
var v []interface{}
|
||||||
ptr := unsafe.Pointer(&v)
|
ptr := unsafe.Pointer(&v)
|
||||||
d.dummy = ptr // escape ptr
|
d.dummy = ptr // escape ptr
|
||||||
dec := newSliceDecoder(newInterfaceDecoder(d.typ), d.typ, d.typ.Size())
|
dec := newSliceDecoder(
|
||||||
|
newInterfaceDecoder(d.typ),
|
||||||
|
d.typ,
|
||||||
|
d.typ.Size(),
|
||||||
|
)
|
||||||
if err := dec.decodeStream(s, uintptr(ptr)); err != nil {
|
if err := dec.decodeStream(s, uintptr(ptr)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
*(*interface{})(unsafe.Pointer(p)) = v
|
*(*interface{})(unsafe.Pointer(p)) = v
|
||||||
return nil
|
return nil
|
||||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
return newFloatDecoder(func(p uintptr, v float64) {
|
return d.numDecoder(s).decodeStream(s, p)
|
||||||
*(*interface{})(unsafe.Pointer(p)) = v
|
|
||||||
}).decodeStream(s, p)
|
|
||||||
case '"':
|
case '"':
|
||||||
s.cursor++
|
s.cursor++
|
||||||
start := s.cursor
|
start := s.cursor
|
||||||
|
@ -104,7 +123,11 @@ func (d *interfaceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, e
|
||||||
var v map[interface{}]interface{}
|
var v map[interface{}]interface{}
|
||||||
ptr := unsafe.Pointer(&v)
|
ptr := unsafe.Pointer(&v)
|
||||||
d.dummy = ptr
|
d.dummy = ptr
|
||||||
dec := newMapDecoder(interfaceMapType, newInterfaceDecoder(d.typ), newInterfaceDecoder(d.typ))
|
dec := newMapDecoder(
|
||||||
|
interfaceMapType,
|
||||||
|
newInterfaceDecoder(d.typ),
|
||||||
|
newInterfaceDecoder(d.typ),
|
||||||
|
)
|
||||||
cursor, err := dec.decode(buf, cursor, uintptr(ptr))
|
cursor, err := dec.decode(buf, cursor, uintptr(ptr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -115,7 +138,11 @@ func (d *interfaceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, e
|
||||||
var v []interface{}
|
var v []interface{}
|
||||||
ptr := unsafe.Pointer(&v)
|
ptr := unsafe.Pointer(&v)
|
||||||
d.dummy = ptr // escape ptr
|
d.dummy = ptr // escape ptr
|
||||||
dec := newSliceDecoder(newInterfaceDecoder(d.typ), d.typ, d.typ.Size())
|
dec := newSliceDecoder(
|
||||||
|
newInterfaceDecoder(d.typ),
|
||||||
|
d.typ,
|
||||||
|
d.typ.Size(),
|
||||||
|
)
|
||||||
cursor, err := dec.decode(buf, cursor, uintptr(ptr))
|
cursor, err := dec.decode(buf, cursor, uintptr(ptr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
|
|
@ -8,6 +8,7 @@ type mapDecoder struct {
|
||||||
mapType *rtype
|
mapType *rtype
|
||||||
keyDecoder decoder
|
keyDecoder decoder
|
||||||
valueDecoder decoder
|
valueDecoder decoder
|
||||||
|
dummy *interfaceHeader
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMapDecoder(mapType *rtype, keyDec decoder, valueDec decoder) *mapDecoder {
|
func newMapDecoder(mapType *rtype, keyDec decoder, valueDec decoder) *mapDecoder {
|
||||||
|
@ -37,11 +38,13 @@ func (d *mapDecoder) setValue(buf []byte, cursor int64, key interface{}) (int64,
|
||||||
|
|
||||||
func (d *mapDecoder) setKeyStream(s *stream, key interface{}) error {
|
func (d *mapDecoder) setKeyStream(s *stream, key interface{}) error {
|
||||||
header := (*interfaceHeader)(unsafe.Pointer(&key))
|
header := (*interfaceHeader)(unsafe.Pointer(&key))
|
||||||
|
d.dummy = header
|
||||||
return d.keyDecoder.decodeStream(s, uintptr(header.ptr))
|
return d.keyDecoder.decodeStream(s, uintptr(header.ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *mapDecoder) setValueStream(s *stream, key interface{}) error {
|
func (d *mapDecoder) setValueStream(s *stream, key interface{}) error {
|
||||||
header := (*interfaceHeader)(unsafe.Pointer(&key))
|
header := (*interfaceHeader)(unsafe.Pointer(&key))
|
||||||
|
d.dummy = header
|
||||||
return d.valueDecoder.decodeStream(s, uintptr(header.ptr))
|
return d.valueDecoder.decodeStream(s, uintptr(header.ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package json
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type numberDecoder struct {
|
||||||
|
*floatDecoder
|
||||||
|
op func(uintptr, Number)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newNumberDecoder(op func(uintptr, Number)) *numberDecoder {
|
||||||
|
return &numberDecoder{
|
||||||
|
floatDecoder: newFloatDecoder(nil),
|
||||||
|
op: op,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *numberDecoder) decodeStream(s *stream, p uintptr) error {
|
||||||
|
bytes, err := d.floatDecoder.decodeStreamByte(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
str := *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
d.op(p, Number(str))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *numberDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error) {
|
||||||
|
bytes, c, err := d.floatDecoder.decodeByte(buf, cursor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
cursor = c
|
||||||
|
s := *(*string)(unsafe.Pointer(&bytes))
|
||||||
|
d.op(p, Number(s))
|
||||||
|
return cursor, nil
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ type stream struct {
|
||||||
offset int64
|
offset int64
|
||||||
cursor int64
|
cursor int64
|
||||||
allRead bool
|
allRead bool
|
||||||
|
useNumber bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stream) buffered() io.Reader {
|
func (s *stream) buffered() io.Reader {
|
||||||
|
|
|
@ -217,6 +217,14 @@ func Test_Decoder(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_Decoder_UseNumber(t *testing.T) {
|
||||||
|
dec := json.NewDecoder(strings.NewReader(`{"a": 3.14}`))
|
||||||
|
dec.UseNumber()
|
||||||
|
var v map[string]interface{}
|
||||||
|
assertErr(t, dec.Decode(&v))
|
||||||
|
assertEq(t, "json.Number", "json.Number", fmt.Sprintf("%T", v["a"]))
|
||||||
|
}
|
||||||
|
|
||||||
type unmarshalJSON struct {
|
type unmarshalJSON struct {
|
||||||
v int
|
v int
|
||||||
}
|
}
|
||||||
|
|
21
json.go
21
json.go
|
@ -1,6 +1,9 @@
|
||||||
package json
|
package json
|
||||||
|
|
||||||
import "bytes"
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
// Marshaler is the interface implemented by types that
|
// Marshaler is the interface implemented by types that
|
||||||
// can marshal themselves into valid JSON.
|
// can marshal themselves into valid JSON.
|
||||||
|
@ -275,3 +278,19 @@ func UnmarshalNoEscape(data []byte, v interface{}) error {
|
||||||
// nil, for JSON null
|
// nil, for JSON null
|
||||||
//
|
//
|
||||||
type Token interface{}
|
type Token interface{}
|
||||||
|
|
||||||
|
// A Number represents a JSON number literal.
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue