summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/francoispqt/gojay/decode_interface.go
blob: 015790d85414160533344efb3ac9065200ca69d3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package gojay

// TODO @afiune for now we are using the standard json unmarshaling but in
// the future it would be great to implement one here inside this repo
import "encoding/json"

// DecodeInterface reads the next JSON-encoded value from the decoder's input (io.Reader) and stores it in the value pointed to by i.
//
// i must be an interface poiter
func (dec *Decoder) DecodeInterface(i *interface{}) error {
	if dec.isPooled == 1 {
		panic(InvalidUsagePooledDecoderError("Invalid usage of pooled decoder"))
	}
	err := dec.decodeInterface(i)
	return err
}

func (dec *Decoder) decodeInterface(i *interface{}) error {
	start, end, err := dec.getObject()
	if err != nil {
		dec.cursor = start
		return err
	}

	// if start & end are equal the object is a null, don't unmarshal
	if start == end {
		return nil
	}

	object := dec.data[start:end]
	if err = json.Unmarshal(object, i); err != nil {
		return err
	}

	dec.cursor = end
	return nil
}

// @afiune Maybe return the type as well?
func (dec *Decoder) getObject() (start int, end int, err error) {
	// start cursor
	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
			}
			// Set start & end to the same cursor to indicate the object
			// is a null and should not be unmarshal
			start = dec.cursor
			end = dec.cursor
			return
		case 't':
			start = dec.cursor
			dec.cursor++
			err = dec.assertTrue()
			if err != nil {
				return
			}
			end = dec.cursor
			dec.cursor++
			return
		// is false
		case 'f':
			start = dec.cursor
			dec.cursor++
			err = dec.assertFalse()
			if err != nil {
				return
			}
			end = dec.cursor
			dec.cursor++
			return
		// is an object
		case '{':
			start = dec.cursor
			dec.cursor++
			end, err = dec.skipObject()
			dec.cursor = end
			return
		// is string
		case '"':
			start = dec.cursor
			dec.cursor++
			start, end, err = dec.getString()
			start--
			dec.cursor = end
			return
		// is array
		case '[':
			start = dec.cursor
			dec.cursor++
			end, err = dec.skipArray()
			dec.cursor = end
			return
		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-':
			start = dec.cursor
			end, err = dec.skipNumber()
			dec.cursor = end
			return
		default:
			err = dec.raiseInvalidJSONErr(dec.cursor)
			return
		}
	}
	err = dec.raiseInvalidJSONErr(dec.cursor)
	return
}

// Add Values functions

// AddInterface decodes the JSON value within an object or an array to a interface{}.
func (dec *Decoder) AddInterface(v *interface{}) error {
	return dec.Interface(v)
}

// Interface decodes the JSON value within an object or an array to an interface{}.
func (dec *Decoder) Interface(value *interface{}) error {
	err := dec.decodeInterface(value)
	if err != nil {
		return err
	}
	dec.called |= 1
	return nil
}