mirror of
https://github.com/json-iterator/go.git
synced 2025-03-23 21:09:11 +02:00
string any
This commit is contained in:
parent
d49ea1bc49
commit
b9fe012eea
@ -2,7 +2,6 @@ package jsoniter
|
||||
|
||||
import (
|
||||
"io"
|
||||
"unsafe"
|
||||
"bytes"
|
||||
)
|
||||
|
||||
@ -10,6 +9,9 @@ import (
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
iter := ParseBytes(data)
|
||||
iter.ReadVal(v)
|
||||
if iter.head == iter.tail {
|
||||
iter.loadMore()
|
||||
}
|
||||
if iter.Error == io.EOF {
|
||||
return nil
|
||||
}
|
||||
@ -22,6 +24,9 @@ func Unmarshal(data []byte, v interface{}) error {
|
||||
func UnmarshalAny(data []byte) (Any, error) {
|
||||
iter := ParseBytes(data)
|
||||
any := iter.ReadAny()
|
||||
if iter.head == iter.tail {
|
||||
iter.loadMore()
|
||||
}
|
||||
if iter.Error == io.EOF {
|
||||
return any, nil
|
||||
}
|
||||
@ -32,10 +37,12 @@ func UnmarshalAny(data []byte) (Any, error) {
|
||||
}
|
||||
|
||||
func UnmarshalFromString(str string, v interface{}) error {
|
||||
// safe to do the unsafe cast here, as str is always referenced in this scope
|
||||
data := *(*[]byte)(unsafe.Pointer(&str))
|
||||
data := []byte(str)
|
||||
iter := ParseBytes(data)
|
||||
iter.ReadVal(v)
|
||||
if iter.head == iter.tail {
|
||||
iter.loadMore()
|
||||
}
|
||||
if iter.Error == io.EOF {
|
||||
return nil
|
||||
}
|
||||
@ -46,10 +53,12 @@ func UnmarshalFromString(str string, v interface{}) error {
|
||||
}
|
||||
|
||||
func UnmarshalAnyFromString(str string) (Any, error) {
|
||||
// safe to do the unsafe cast here, as str is always referenced in this scope
|
||||
data := *(*[]byte)(unsafe.Pointer(&str))
|
||||
data := []byte(str)
|
||||
iter := ParseBytes(data)
|
||||
any := iter.ReadAny()
|
||||
if iter.head == iter.tail {
|
||||
iter.loadMore()
|
||||
}
|
||||
if iter.Error == io.EOF {
|
||||
return any, nil
|
||||
}
|
||||
|
@ -20,18 +20,15 @@ func (iter *Iterator) ReadAny() Any {
|
||||
iter.skipFixedBytes(4)
|
||||
return &nilAny{}
|
||||
case Number:
|
||||
dotFound, lazyBuf := iter.skipNumber()
|
||||
if dotFound {
|
||||
return &floatLazyAny{lazyBuf, nil, nil, 0}
|
||||
} else {
|
||||
return &intLazyAny{lazyBuf, nil, nil, 0}
|
||||
}
|
||||
return iter.readNumberAny()
|
||||
case String:
|
||||
return iter.readStringAny()
|
||||
}
|
||||
iter.reportError("ReadAny", fmt.Sprintf("unexpected value type: %v", valueType))
|
||||
return nil
|
||||
return &invalidAny{}
|
||||
}
|
||||
|
||||
func (iter *Iterator) skipNumber() (bool, []byte) {
|
||||
func (iter *Iterator) readNumberAny() Any {
|
||||
dotFound := false
|
||||
var lazyBuf []byte
|
||||
for {
|
||||
@ -45,13 +42,44 @@ func (iter *Iterator) skipNumber() (bool, []byte) {
|
||||
case ' ', '\n', '\r', '\t', ',', '}', ']':
|
||||
lazyBuf = append(lazyBuf, iter.buf[iter.head:i]...)
|
||||
iter.head = i
|
||||
return dotFound, lazyBuf
|
||||
if dotFound {
|
||||
return &floatLazyAny{lazyBuf, nil, nil, 0}
|
||||
} else {
|
||||
return &intLazyAny{lazyBuf, nil, nil, 0}
|
||||
}
|
||||
}
|
||||
}
|
||||
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
|
||||
if !iter.loadMore() {
|
||||
iter.head = iter.tail;
|
||||
return dotFound, lazyBuf
|
||||
iter.head = iter.tail
|
||||
if dotFound {
|
||||
return &floatLazyAny{lazyBuf, nil, nil, 0}
|
||||
} else {
|
||||
return &intLazyAny{lazyBuf, nil, nil, 0}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (iter *Iterator) readStringAny() Any {
|
||||
iter.head++
|
||||
lazyBuf := make([]byte, 1, 8)
|
||||
lazyBuf[0] = '"'
|
||||
for {
|
||||
end, escaped := iter.findStringEnd()
|
||||
if end == -1 {
|
||||
lazyBuf = append(lazyBuf, iter.buf[iter.head:iter.tail]...)
|
||||
if !iter.loadMore() {
|
||||
iter.reportError("readStringAny", "incomplete string")
|
||||
return &invalidAny{}
|
||||
}
|
||||
if escaped {
|
||||
iter.head = 1 // skip the first char as last char read is \
|
||||
}
|
||||
} else {
|
||||
lazyBuf = append(lazyBuf, iter.buf[iter.head:end]...)
|
||||
iter.head = end
|
||||
return &stringLazyAny{lazyBuf, nil, nil, ""}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
feature_any_invalid.go
Normal file
36
feature_any_invalid.go
Normal file
@ -0,0 +1,36 @@
|
||||
package jsoniter
|
||||
|
||||
type invalidAny struct {
|
||||
}
|
||||
|
||||
func (any *invalidAny) LastError() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (any *invalidAny) ToBool() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (any *invalidAny) ToInt() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (any *invalidAny) ToInt32() int32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (any *invalidAny) ToInt64() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (any *invalidAny) ToFloat32() float32 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (any *invalidAny) ToFloat64() float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (any *invalidAny) ToString() string {
|
||||
return ""
|
||||
}
|
98
feature_any_string.go
Normal file
98
feature_any_string.go
Normal file
@ -0,0 +1,98 @@
|
||||
package jsoniter
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type stringLazyAny struct{
|
||||
buf []byte
|
||||
iter *Iterator
|
||||
err error
|
||||
cache string
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) fillCache() {
|
||||
if any.err != nil {
|
||||
return
|
||||
}
|
||||
iter := any.parse()
|
||||
any.cache = iter.ReadString()
|
||||
if iter.Error != io.EOF {
|
||||
iter.reportError("stringLazyAny", "there are bytes left")
|
||||
}
|
||||
any.err = iter.Error
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) parse() *Iterator {
|
||||
iter := any.iter
|
||||
if iter == nil {
|
||||
iter = NewIterator()
|
||||
any.iter = iter
|
||||
}
|
||||
iter.ResetBytes(any.buf)
|
||||
return iter
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) LastError() error {
|
||||
return any.err
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) ToBool() bool {
|
||||
str := any.ToString()
|
||||
if str == "false" {
|
||||
return false
|
||||
}
|
||||
for _, c := range str {
|
||||
switch c {
|
||||
case ' ', '\n', '\r', '\t':
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) ToInt() int {
|
||||
iter := any.parse()
|
||||
iter.head++
|
||||
val := iter.ReadInt()
|
||||
any.err = iter.Error
|
||||
return val
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) ToInt32() int32 {
|
||||
iter := any.parse()
|
||||
iter.head++
|
||||
val := iter.ReadInt32()
|
||||
any.err = iter.Error
|
||||
return val
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) ToInt64() int64 {
|
||||
iter := any.parse()
|
||||
iter.head++
|
||||
val := iter.ReadInt64()
|
||||
any.err = iter.Error
|
||||
return val
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) ToFloat32() float32 {
|
||||
iter := any.parse()
|
||||
iter.head++
|
||||
val := iter.ReadFloat32()
|
||||
any.err = iter.Error
|
||||
return val
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) ToFloat64() float64 {
|
||||
iter := any.parse()
|
||||
iter.head++
|
||||
val := iter.ReadFloat64()
|
||||
any.err = iter.Error
|
||||
return val
|
||||
}
|
||||
|
||||
func (any *stringLazyAny) ToString() string {
|
||||
any.fillCache()
|
||||
return any.cache
|
||||
}
|
@ -160,7 +160,9 @@ func (iter *Iterator) nextToken() byte {
|
||||
|
||||
func (iter *Iterator) reportError(operation string, msg string) {
|
||||
if iter.Error != nil {
|
||||
return
|
||||
if iter.Error != io.EOF {
|
||||
return
|
||||
}
|
||||
}
|
||||
peekStart := iter.head - 10
|
||||
if peekStart < 0 {
|
||||
|
@ -57,6 +57,7 @@ func (iter *Iterator) skipString() {
|
||||
end, escaped := iter.findStringEnd()
|
||||
if end == -1 {
|
||||
if !iter.loadMore() {
|
||||
iter.reportError("skipString", "incomplete string")
|
||||
return
|
||||
}
|
||||
if escaped {
|
||||
|
@ -59,12 +59,26 @@ func Test_read_exotic_string(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_read_string_via_read(t *testing.T) {
|
||||
func Test_read_string_as_interface(t *testing.T) {
|
||||
should := require.New(t)
|
||||
iter := ParseString(`"hello"`)
|
||||
should.Equal("hello", iter.Read())
|
||||
}
|
||||
|
||||
func Test_read_string_as_any(t *testing.T) {
|
||||
should := require.New(t)
|
||||
any, err := UnmarshalAnyFromString(`"hello"`)
|
||||
should.Nil(err)
|
||||
should.Equal("hello", any.ToString())
|
||||
should.True(any.ToBool())
|
||||
any, err = UnmarshalAnyFromString(`" "`)
|
||||
should.False(any.ToBool())
|
||||
any, err = UnmarshalAnyFromString(`"false"`)
|
||||
should.False(any.ToBool())
|
||||
any, err = UnmarshalAnyFromString(`"123"`)
|
||||
should.Equal(123, any.ToInt())
|
||||
}
|
||||
|
||||
func Test_write_string(t *testing.T) {
|
||||
should := require.New(t)
|
||||
str, err := MarshalToString("hello")
|
||||
|
Loading…
x
Reference in New Issue
Block a user