package gojay import ( "reflect" "unsafe" ) // DecodeObject reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by v. // // v must implement UnmarshalerJSONObject. // // See the documentation for Unmarshal for details about the conversion of JSON into a Go value. 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 is zero we will parse all keys // we run two loops for micro optimization 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 } } // will get to that point when keysDone is not lower than keys anymore // in that case, we make sure cursor goes to the end of object, but we skip // unmarshalling 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: // can't unmarshal to struct 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) { // make sure the value is a pointer 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 is zero we will parse all keys // we run two loops for micro optimization 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 } } // will get to that point when keysDone is not lower than keys anymore // in that case, we make sure cursor goes to the end of object, but we skip // unmarshalling 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: // can't unmarshal to struct 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++ // everything is closed return if objectsOpen == objectsClosed { // add char to object data 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 } // loop backward and count how many anti slash found // to see if string is effectively escaped ct := 0 for i := j - 1; i > 0; i-- { if dec.data[i] != '\\' { break } ct++ } // is pair number of slashes, quote is not escaped 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: // can't unmarshall to struct 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 // is null 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 // is false case 'f': dec.cursor++ err := dec.assertFalse() if err != nil { return err } return nil // is an object case '{': dec.cursor = dec.cursor + 1 end, err := dec.skipObject() dec.cursor = end return err // is string case '"': dec.cursor = dec.cursor + 1 err := dec.skipString() return err // is array 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) } // DecodeObjectFunc is a func type implementing UnmarshalerJSONObject. // Use it to cast a `func(*Decoder, k string) error` to Unmarshal an object on the fly. type DecodeObjectFunc func(*Decoder, string) error // UnmarshalJSONObject implements UnmarshalerJSONObject. func (f DecodeObjectFunc) UnmarshalJSONObject(dec *Decoder, k string) error { return f(dec, k) } // NKeys implements UnmarshalerJSONObject. func (f DecodeObjectFunc) NKeys() int { return 0 } // Add Values functions // AddObject decodes the JSON value within an object or an array to a UnmarshalerJSONObject. func (dec *Decoder) AddObject(v UnmarshalerJSONObject) error { return dec.Object(v) } // AddObjectNull decodes the JSON value within an object or an array to a UnmarshalerJSONObject. func (dec *Decoder) AddObjectNull(v interface{}) error { return dec.ObjectNull(v) } // Object decodes the JSON value within an object or an array to a UnmarshalerJSONObject. 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 } // ObjectNull decodes the JSON value within an object or an array to a UnmarshalerJSONObject. // v should be a pointer to an UnmarshalerJSONObject, // if `null` value is encountered in JSON, it will leave the value v untouched, // else it will create a new instance of the UnmarshalerJSONObject behind v. 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 }