v
Зеркало из https://github.com/vlang/v
1module decoder2
2
3import time
4
5// Node represents a node in a JSON decoder tree.
6struct Node {
7key_pos int // The position of the key in the JSON string.
8key_len int // The length of the key in the JSON string.
9children ?[]Node // The children nodes of the current node.
10}
11
12// Decoder represents a JSON decoder.
13struct Decoder {
14json string // json is the JSON data to be decoded.
15mut:
16idx int // idx is the current index of the decoder.
17}
18
19pub enum ValueKind {
20unknown
21array
22object
23string_
24number
25boolean
26}
27
28// check_json checks if the JSON string is valid.
29fn check_json(val string) ! {
30if val == '' {
31return error('empty string')
32}
33}
34
35// decode decodes a JSON string into a specified type.
36pub fn decode[T](val string) !T {
37check_json(val)!
38
39mut nodes := []Node{}
40mut decoder := Decoder{
41json: val
42}
43
44// TODO: needs performance improvements
45decoder.fulfill_nodes(mut nodes)
46
47mut result := T{}
48decoder.decode_value(nodes, &result)
49return result
50}
51
52// decode_value decodes a value from the JSON nodes.
53fn (mut decoder Decoder) decode_value[T](nodes []Node, val &T) {
54$if val is $option {
55} $else $if T is string {
56} $else $if T is $sumtype {
57$for v in val.variants {
58if val is v {
59decoder.decode_value(nodes, val)
60}
61}
62} $else $if T is $alias {
63} $else $if T is time.Time {
64} $else $if T is $map {
65} $else $if T is $array {
66} $else $if T is $struct {
67decoder.decode_struct(nodes, val)
68} $else $if T is $enum {
69} $else $if T is $int {
70} $else $if T is $float {
71} $else $if T is bool {
72} $else {
73return error('cannot encode value with ${typeof(val).name} type')
74}
75}
76
77// get_value_kind returns the kind of a JSON value.
78fn get_value_kind(value rune) ValueKind {
79return match value {
80`"` { .string_ }
81`t`, `f` { .boolean }
82`{` { .object }
83`[` { .array }
84`0`...`9` { .number }
85else { .unknown }
86}
87}
88
89// decode_optional_value_in_actual_node decodes an optional value in a node.
90fn (mut decoder Decoder) decode_optional_value_in_actual_node[T](node Node, val ?T) T {
91start := (node.key_pos + node.key_len) + 3
92mut end := start
93for decoder.json[end] != `,` && decoder.json[end] != `}` {
94end++
95}
96mut value_kind := get_value_kind(decoder.json[start])
97
98$if T is string {
99if value_kind == .string_ {
100return decoder.json[start + 1..end - 1]
101} else if value_kind == .object {
102} else if value_kind == .array {
103} else {
104return decoder.json[start..end]
105}
106return ''
107} $else $if T is $int {
108if value_kind == .string_ {
109return decoder.json[start + 1..end - 1].int()
110} else if value_kind == .object {
111} else if value_kind == .array {
112} else {
113return decoder.json[start..end].int()
114}
115}
116return T{}
117}
118
119// decode_struct decodes a struct from the JSON nodes.
120fn (mut decoder Decoder) decode_struct[T](nodes []Node, value &T) {
121$for field in T.fields {
122for i := 0; i < nodes.len; i++ {
123mut node := nodes[i]
124
125if node.key_len == field.name.len {
126// This `vmemcmp` compares the name of a key in a JSON with a given struct field.
127if unsafe {
128vmemcmp(decoder.json.str + node.key_pos, field.name.str, field.name.len) == 0
129} {
130start := (node.key_pos + node.key_len) + 3
131mut end := start
132for decoder.json[end] != `,` && decoder.json[end] != `}` {
133end++
134}
135value_kind := get_value_kind(decoder.json[start])
136$if field.indirections != 0 {
137// REVIEW Needs clone?
138$if field.indirections == 1 {
139// TODO
140// unsafe {
141// value.$(field.name) = &(decoder.json[start + 1..end - 1])
142// }
143} $else $if field.indirections == 2 {
144// TODO
145// unsafe {
146// value.$(field.name) = &&(decoder.json[start + 1..end - 1])
147// }
148} $else $if field.indirections == 3 {
149// TODO
150// unsafe {
151// value.$(field.name) = &&&(decoder.json[start + 1..end - 1])
152// }
153}
154} $else $if field.typ is $option {
155value.$(field.name) = decoder.decode_optional_value_in_actual_node(node,
156value.$(field.name))
157} $else $if field.typ is $sumtype {
158// dump(value.$(field.name))
159
160workaround := value.$(field.name)
161// z := value.$(field.name)
162
163$for v in workaround.variants {
164$if v.typ is string {
165if value_kind == .string_ {
166// value.$(field.name) = decoder.json[start + 1..end - 1]
167} else {
168// value.$(field.name) = decoder.json[start..end]
169}
170} $else $if v.typ in [$int, $float] {
171$if v.typ is u32 {
172value.$(field.name) = decoder.json[start..end].u32()
173} $else $if v.typ is u32 {
174}
175
176$if v.typ is i8 {
177value.$(field.name) = decoder.json[start..end].i8()
178} $else $if v.typ is i16 {
179value.$(field.name) = decoder.json[start..end].i16()
180} $else $if v.typ is i32 {
181value.$(field.name) = decoder.json[start..end].i32()
182} $else $if v.typ is int {
183value.$(field.name) = decoder.json[start..end].int()
184} $else $if v.typ is i64 {
185value.$(field.name) = decoder.json[start..end].i64()
186} $else $if v.typ is u8 {
187value.$(field.name) = decoder.json[start..end].u8()
188} $else $if v.typ is u16 {
189value.$(field.name) = decoder.json[start..end].u16()
190} $else $if v.typ is u32 {
191value.$(field.name) = decoder.json[start..end].u32()
192} $else $if v.typ is u64 {
193value.$(field.name) = decoder.json[start..end].u64()
194} $else $if v.typ is f32 {
195value.$(field.name) = decoder.json[start..end].f32()
196} $else $if v.typ is f64 {
197value.$(field.name) = decoder.json[start..end].f64()
198}
199} $else $if v.typ is bool {
200if decoder.json[start] == `t` {
201value.$(field.name) = true
202} else if decoder.json[start] == `f` {
203value.$(field.name) = false
204}
205} $else $if v.typ is time.Time {
206if value_kind == .string_ {
207value.$(field.name) = time.parse(decoder.json[start + 1..end - 1]) or {
208time.Time{}
209}
210}
211} $else $if v.typ is $struct {
212if node.children != none {
213// FIXME
214// decoder.decode_value(node.children or {
215// panic('It will never happens')
216// }, value.$(field.name))
217}
218} $else $if v.typ is $array {
219if value_kind == .array {
220// TODO
221}
222} $else $if v.typ is $map {
223if value_kind == .object {
224// TODO
225}
226} $else $if T is $enum {
227} $else {
228eprintln('not supported')
229}
230}
231if value_kind == .string_ {
232// value.$(field.name) = decoder.json[start + 1..end - 1]
233} else if decoder.json[start] == `t` {
234value.$(field.name) = true
235} else if decoder.json[start] == `f` {
236value.$(field.name) = false
237} else if value_kind == .object {
238} else if value_kind == .array {
239} else if value_kind == .number {
240// value.$(field.name) = decoder.json[start..end].int()
241} else {
242}
243} $else $if field.typ is string {
244value.$(field.name) = if value_kind == .string_ {
245decoder.json[start + 1..end - 1]
246} else {
247decoder.json[start..end]
248}
249} $else $if field.typ in [$int, $float] {
250$if field.typ is i8 {
251value.$(field.name) = decoder.json[start..end].i8()
252} $else $if field.typ is i16 {
253value.$(field.name) = decoder.json[start..end].i16()
254} $else $if field.typ is i32 {
255value.$(field.name) = decoder.json[start..end].i32()
256} $else $if field.typ is int {
257value.$(field.name) = decoder.json[start..end].int()
258} $else $if field.typ is i64 {
259value.$(field.name) = decoder.json[start..end].i64()
260} $else $if field.typ is u8 {
261value.$(field.name) = decoder.json[start..end].u8()
262} $else $if field.typ is u16 {
263value.$(field.name) = decoder.json[start..end].u16()
264} $else $if field.typ is u32 {
265value.$(field.name) = decoder.json[start..end].u32()
266} $else $if field.typ is u64 {
267value.$(field.name) = decoder.json[start..end].u64()
268} $else $if field.typ is f32 {
269value.$(field.name) = decoder.json[start..end].f32()
270} $else $if field.typ is f64 {
271value.$(field.name) = decoder.json[start..end].f64()
272}
273} $else $if field.typ is bool {
274value.$(field.name) = decoder.json[start] == `t`
275} $else $if field.typ is time.Time {
276if value_kind == .string_ {
277value.$(field.name) = time.parse_rfc3339(decoder.json[start + 1..end - 1]) or {
278time.Time{}
279}
280}
281} $else $if field.typ is $struct {
282if node.children != none {
283decoder.decode_value(node.children or { panic('It will never happen') },
284value.$(field.name))
285}
286} $else $if field.typ is $array {
287if value_kind == .array {
288// TODO
289}
290} $else $if field.typ is $map {
291if value_kind == .object && node.children != none {
292decoder.decode_map(node.children or { panic('It will never happen') }, mut
293value.$(field.name))
294}
295} $else $if field.typ is $enum {
296value.$(field.name) = decoder.json[start..end].int()
297} $else $if field.typ is $alias {
298$if field.unaliased_typ is string {
299if value_kind == .string_ {
300value.$(field.name) = decoder.json[start + 1..end - 1]
301}
302} $else $if field.unaliased_typ is time.Time {
303} $else $if field.unaliased_typ is bool {
304} $else $if field.unaliased_typ in [$float, $int] {
305$if field.unaliased_typ is i8 {
306value.$(field.name) = decoder.json[start..end].i8()
307} $else $if field.unaliased_typ is i16 {
308value.$(field.name) = decoder.json[start..end].i16()
309} $else $if field.unaliased_typ is i32 {
310value.$(field.name) = decoder.json[start..end].i32()
311} $else $if field.unaliased_typ is int {
312value.$(field.name) = decoder.json[start..end].int()
313} $else $if field.unaliased_typ is i64 {
314value.$(field.name) = decoder.json[start..end].i64()
315} $else $if field.unaliased_typ is u8 {
316value.$(field.name) = decoder.json[start..end].u8()
317} $else $if field.unaliased_typ is u16 {
318value.$(field.name) = decoder.json[start..end].u16()
319} $else $if field.unaliased_typ is u32 {
320value.$(field.name) = decoder.json[start..end].u32()
321} $else $if field.unaliased_typ is u64 {
322value.$(field.name) = decoder.json[start..end].u64()
323} $else $if field.unaliased_typ is f32 {
324value.$(field.name) = decoder.json[start..end].f32()
325} $else $if field.unaliased_typ is f64 {
326value.$(field.name) = decoder.json[start..end].f64()
327}
328} $else $if field.unaliased_typ is $array {
329// TODO
330} $else $if field.unaliased_typ is $struct {
331} $else $if field.unaliased_typ is $enum {
332// TODO
333} $else $if field.unaliased_typ is $sumtype {
334// TODO
335} $else {
336eprintln('the alias ${field.unaliased_typ} cannot be encoded')
337}
338} $else {
339eprintln('not supported')
340}
341break
342}
343}
344}
345}
346}
347
348// decode_map decodes a map from the JSON nodes.
349fn (mut decoder Decoder) decode_map[T](nodes []Node, mut val T) {
350for i := 0; i < nodes.len; i++ {
351mut node := nodes[i]
352
353start := (node.key_pos + node.key_len) + 3
354mut end := start
355for decoder.json[end] != `,` && decoder.json[end] != `}` {
356end++
357}
358value_kind := get_value_kind(decoder.json[start])
359val[decoder.json[node.key_pos..node.key_pos + node.key_len]] = if value_kind == .string_ {
360decoder.json[start + 1..end - 1]
361} else {
362decoder.json[start..end]
363}
364}
365}
366
367// fulfill_nodes fills the nodes from the JSON string.
368fn (mut decoder Decoder) fulfill_nodes(mut nodes []Node) {
369mut inside_string := false
370mut inside_key := false
371mut actual_key_len := 0
372
373for decoder.idx < decoder.json.len {
374letter := decoder.json[decoder.idx]
375match letter {
376` ` {
377if !inside_string {
378}
379}
380`\"` {
381if decoder.json[decoder.idx - 1] == `{` || decoder.json[decoder.idx - 2] == `,` {
382inside_key = true
383} else if decoder.json[decoder.idx + 1] == `:` {
384if decoder.json[decoder.idx + 3] == `{` {
385mut children := []Node{}
386key_pos := decoder.idx - actual_key_len
387key_len := actual_key_len
388
389decoder.idx += 3
390decoder.fulfill_nodes(mut children)
391
392nodes << Node{
393key_pos: key_pos
394key_len: key_len
395children: children
396}
397} else {
398nodes << Node{
399key_pos: decoder.idx - actual_key_len
400key_len: actual_key_len
401}
402}
403inside_key = false
404}
405inside_string = !inside_string
406decoder.idx++
407continue
408}
409`:` {
410actual_key_len = 0
411}
412`,`, `{`, `}`, `[`, `]` {}
413else {}
414}
415if inside_key {
416actual_key_len++
417}
418decoder.idx++
419}
420}
421