package gojay
import (
"reflect"
"unsafe"
)
func (dec *Decoder ) DecodeObject (j UnmarshalerJSONObject ) error {
if dec .isPooled == 1 {
panic (InvalidUsagePooledDecoderError ("Invalid usage of pooled decoder" ))
}
_ , err := dec .decodeObject (j )
return err
}
func (dec *Decoder ) decodeObject (j UnmarshalerJSONObject ) (int , error ) {
keys := j .NKeys ()
for ; dec .cursor < dec .length || dec .read (); dec .cursor ++ {
switch dec .data [dec .cursor ] {
case ' ' , '\n' , '\t' , '\r' , ',' :
case '{' :
dec .cursor = dec .cursor + 1
if keys == 0 {
for dec .cursor < dec .length || dec .read () {
k , done , err := dec .nextKey ()
if err != nil {
return 0 , err
} else if done {
return dec .cursor , nil
}
err = j .UnmarshalJSONObject (dec , k )
if err != nil {
dec .err = err
return 0 , err
} else if dec .called &1 == 0 {
err := dec .skipData ()
if err != nil {
return 0 , err
}
} else {
dec .keysDone ++
}
dec .called &= 0
}
} else {
for (dec .cursor < dec .length || dec .read ()) && dec .keysDone < keys {
k , done , err := dec .nextKey ()
if err != nil {
return 0 , err
} else if done {
return dec .cursor , nil
}
err = j .UnmarshalJSONObject (dec , k )
if err != nil {
dec .err = err
return 0 , err
} else if dec .called &1 == 0 {
err := dec .skipData ()
if err != nil {
return 0 , err
}
} else {
dec .keysDone ++
}
dec .called &= 0
}
}
if dec .child &1 != 0 {
end , err := dec .skipObject ()
dec .cursor = end
return dec .cursor , err
}
return dec .cursor , nil
case 'n' :
dec .cursor ++
err := dec .assertNull ()
if err != nil {
return 0 , err
}
return dec .cursor , nil
default :
dec .err = dec .makeInvalidUnmarshalErr (j )
err := dec .skipData ()
if err != nil {
return 0 , err
}
return dec .cursor , nil
}
}
return 0 , dec .raiseInvalidJSONErr (dec .cursor )
}
func (dec *Decoder ) decodeObjectNull (v interface {}) (int , error ) {
vv := reflect .ValueOf (v )
vvt := vv .Type ()
if vvt .Kind () != reflect .Ptr || vvt .Elem ().Kind () != reflect .Ptr {
dec .err = ErrUnmarshalPtrExpected
return 0 , dec .err
}
for ; dec .cursor < dec .length || dec .read (); dec .cursor ++ {
switch dec .data [dec .cursor ] {
case ' ' , '\n' , '\t' , '\r' , ',' :
case '{' :
elt := vv .Elem ()
n := reflect .New (elt .Type ().Elem ())
elt .Set (n )
var j UnmarshalerJSONObject
var ok bool
if j , ok = n .Interface ().(UnmarshalerJSONObject ); !ok {
dec .err = dec .makeInvalidUnmarshalErr ((UnmarshalerJSONObject )(nil ))
return 0 , dec .err
}
keys := j .NKeys ()
dec .cursor = dec .cursor + 1
if keys == 0 {
for dec .cursor < dec .length || dec .read () {
k , done , err := dec .nextKey ()
if err != nil {
return 0 , err
} else if done {
return dec .cursor , nil
}
err = j .UnmarshalJSONObject (dec , k )
if err != nil {
dec .err = err
return 0 , err
} else if dec .called &1 == 0 {
err := dec .skipData ()
if err != nil {
return 0 , err
}
} else {
dec .keysDone ++
}
dec .called &= 0
}
} else {
for (dec .cursor < dec .length || dec .read ()) && dec .keysDone < keys {
k , done , err := dec .nextKey ()
if err != nil {
return 0 , err
} else if done {
return dec .cursor , nil
}
err = j .UnmarshalJSONObject (dec , k )
if err != nil {
dec .err = err
return 0 , err
} else if dec .called &1 == 0 {
err := dec .skipData ()
if err != nil {
return 0 , err
}
} else {
dec .keysDone ++
}
dec .called &= 0
}
}
if dec .child &1 != 0 {
end , err := dec .skipObject ()
dec .cursor = end
return dec .cursor , err
}
return dec .cursor , nil
case 'n' :
dec .cursor ++
err := dec .assertNull ()
if err != nil {
return 0 , err
}
return dec .cursor , nil
default :
dec .err = dec .makeInvalidUnmarshalErr ((UnmarshalerJSONObject )(nil ))
err := dec .skipData ()
if err != nil {
return 0 , err
}
return dec .cursor , nil
}
}
return 0 , dec .raiseInvalidJSONErr (dec .cursor )
}
func (dec *Decoder ) skipObject () (int , error ) {
var objectsOpen = 1
var objectsClosed = 0
for j := dec .cursor ; j < dec .length || dec .read (); j ++ {
switch dec .data [j ] {
case '}' :
objectsClosed ++
if objectsOpen == objectsClosed {
return j + 1 , nil
}
case '{' :
objectsOpen ++
case '"' :
j ++
var isInEscapeSeq bool
var isFirstQuote = true
for ; j < dec .length || dec .read (); j ++ {
if dec .data [j ] != '"' {
continue
}
if dec .data [j -1 ] != '\\' || (!isInEscapeSeq && !isFirstQuote ) {
break
} else {
isInEscapeSeq = false
}
if isFirstQuote {
isFirstQuote = false
}
ct := 0
for i := j - 1 ; i > 0 ; i -- {
if dec .data [i ] != '\\' {
break
}
ct ++
}
if ct &1 == 0 {
break
}
isInEscapeSeq = true
}
default :
continue
}
}
return 0 , dec .raiseInvalidJSONErr (dec .cursor )
}
func (dec *Decoder ) nextKey () (string , bool , error ) {
for ; dec .cursor < dec .length || dec .read (); dec .cursor ++ {
switch dec .data [dec .cursor ] {
case ' ' , '\n' , '\t' , '\r' , ',' :
continue
case '"' :
dec .cursor = dec .cursor + 1
start , end , err := dec .getString ()
if err != nil {
return "" , false , err
}
var found byte
for ; dec .cursor < dec .length || dec .read (); dec .cursor ++ {
if dec .data [dec .cursor ] == ':' {
found |= 1
break
}
}
if found &1 != 0 {
dec .cursor ++
d := dec .data [start : end -1 ]
return *(*string )(unsafe .Pointer (&d )), false , nil
}
return "" , false , dec .raiseInvalidJSONErr (dec .cursor )
case '}' :
dec .cursor = dec .cursor + 1
return "" , true , nil
default :
return "" , false , dec .raiseInvalidJSONErr (dec .cursor )
}
}
return "" , false , dec .raiseInvalidJSONErr (dec .cursor )
}
func (dec *Decoder ) skipData () error {
for ; dec .cursor < dec .length || dec .read (); dec .cursor ++ {
switch dec .data [dec .cursor ] {
case ' ' , '\n' , '\t' , '\r' , ',' :
continue
case 'n' :
dec .cursor ++
err := dec .assertNull ()
if err != nil {
return err
}
return nil
case 't' :
dec .cursor ++
err := dec .assertTrue ()
if err != nil {
return err
}
return nil
case 'f' :
dec .cursor ++
err := dec .assertFalse ()
if err != nil {
return err
}
return nil
case '{' :
dec .cursor = dec .cursor + 1
end , err := dec .skipObject ()
dec .cursor = end
return err
case '"' :
dec .cursor = dec .cursor + 1
err := dec .skipString ()
return err
case '[' :
dec .cursor = dec .cursor + 1
end , err := dec .skipArray ()
dec .cursor = end
return err
case '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '-' :
end , err := dec .skipNumber ()
dec .cursor = end
return err
}
return dec .raiseInvalidJSONErr (dec .cursor )
}
return dec .raiseInvalidJSONErr (dec .cursor )
}
type DecodeObjectFunc func (*Decoder , string ) error
func (f DecodeObjectFunc ) UnmarshalJSONObject (dec *Decoder , k string ) error {
return f (dec , k )
}
func (f DecodeObjectFunc ) NKeys () int {
return 0
}
func (dec *Decoder ) AddObject (v UnmarshalerJSONObject ) error {
return dec .Object (v )
}
func (dec *Decoder ) AddObjectNull (v interface {}) error {
return dec .ObjectNull (v )
}
func (dec *Decoder ) Object (value UnmarshalerJSONObject ) error {
initialKeysDone := dec .keysDone
initialChild := dec .child
dec .keysDone = 0
dec .called = 0
dec .child |= 1
newCursor , err := dec .decodeObject (value )
if err != nil {
return err
}
dec .cursor = newCursor
dec .keysDone = initialKeysDone
dec .child = initialChild
dec .called |= 1
return nil
}
func (dec *Decoder ) ObjectNull (v interface {}) error {
initialKeysDone := dec .keysDone
initialChild := dec .child
dec .keysDone = 0
dec .called = 0
dec .child |= 1
newCursor , err := dec .decodeObjectNull (v )
if err != nil {
return err
}
dec .cursor = newCursor
dec .keysDone = initialKeysDone
dec .child = initialChild
dec .called |= 1
return nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .