v

Зеркало из https://github.com/vlang/v
Форк
0
/x
/
decode.v 
420 строк · 12.7 Кб
1
module decoder2
2

3
import time
4

5
// Node represents a node in a JSON decoder tree.
6
struct Node {
7
	key_pos  int     // The position of the key in the JSON string.
8
	key_len  int     // The length of the key in the JSON string.
9
	children ?[]Node // The children nodes of the current node.
10
}
11

12
// Decoder represents a JSON decoder.
13
struct Decoder {
14
	json string // json is the JSON data to be decoded.
15
mut:
16
	idx int // idx is the current index of the decoder.
17
}
18

19
pub enum ValueKind {
20
	unknown
21
	array
22
	object
23
	string_
24
	number
25
	boolean
26
}
27

28
// check_json checks if the JSON string is valid.
29
fn check_json(val string) ! {
30
	if val == '' {
31
		return error('empty string')
32
	}
33
}
34

35
// decode decodes a JSON string into a specified type.
36
pub fn decode[T](val string) !T {
37
	check_json(val)!
38

39
	mut nodes := []Node{}
40
	mut decoder := Decoder{
41
		json: val
42
	}
43

44
	// TODO: needs performance improvements
45
	decoder.fulfill_nodes(mut nodes)
46

47
	mut result := T{}
48
	decoder.decode_value(nodes, &result)
49
	return result
50
}
51

52
// decode_value decodes a value from the JSON nodes.
53
fn (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 {
58
			if val is v {
59
				decoder.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 {
67
		decoder.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 {
73
		return error('cannot encode value with ${typeof(val).name} type')
74
	}
75
}
76

77
// get_value_kind returns the kind of a JSON value.
78
fn get_value_kind(value rune) ValueKind {
79
	return match value {
80
		`"` { .string_ }
81
		`t`, `f` { .boolean }
82
		`{` { .object }
83
		`[` { .array }
84
		`0`...`9` { .number }
85
		else { .unknown }
86
	}
87
}
88

89
// decode_optional_value_in_actual_node decodes an optional value in a node.
90
fn (mut decoder Decoder) decode_optional_value_in_actual_node[T](node Node, val ?T) T {
91
	start := (node.key_pos + node.key_len) + 3
92
	mut end := start
93
	for decoder.json[end] != `,` && decoder.json[end] != `}` {
94
		end++
95
	}
96
	mut value_kind := get_value_kind(decoder.json[start])
97

98
	$if T is string {
99
		if value_kind == .string_ {
100
			return decoder.json[start + 1..end - 1]
101
		} else if value_kind == .object {
102
		} else if value_kind == .array {
103
		} else {
104
			return decoder.json[start..end]
105
		}
106
		return ''
107
	} $else $if T is $int {
108
		if value_kind == .string_ {
109
			return decoder.json[start + 1..end - 1].int()
110
		} else if value_kind == .object {
111
		} else if value_kind == .array {
112
		} else {
113
			return decoder.json[start..end].int()
114
		}
115
	}
116
	return T{}
117
}
118

119
// decode_struct decodes a struct from the JSON nodes.
120
fn (mut decoder Decoder) decode_struct[T](nodes []Node, value &T) {
121
	$for field in T.fields {
122
		for i := 0; i < nodes.len; i++ {
123
			mut node := nodes[i]
124

125
			if node.key_len == field.name.len {
126
				// This `vmemcmp` compares the name of a key in a JSON with a given struct field.
127
				if unsafe {
128
					vmemcmp(decoder.json.str + node.key_pos, field.name.str, field.name.len) == 0
129
				} {
130
					start := (node.key_pos + node.key_len) + 3
131
					mut end := start
132
					for decoder.json[end] != `,` && decoder.json[end] != `}` {
133
						end++
134
					}
135
					value_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 {
155
						value.$(field.name) = decoder.decode_optional_value_in_actual_node(node,
156
							value.$(field.name))
157
					} $else $if field.typ is $sumtype {
158
						// dump(value.$(field.name))
159

160
						workaround := value.$(field.name)
161
						// z := value.$(field.name)
162

163
						$for v in workaround.variants {
164
							$if v.typ is string {
165
								if 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 {
172
									value.$(field.name) = decoder.json[start..end].u32()
173
								} $else $if v.typ is u32 {
174
								}
175

176
								$if v.typ is i8 {
177
									value.$(field.name) = decoder.json[start..end].i8()
178
								} $else $if v.typ is i16 {
179
									value.$(field.name) = decoder.json[start..end].i16()
180
								} $else $if v.typ is i32 {
181
									value.$(field.name) = decoder.json[start..end].i32()
182
								} $else $if v.typ is int {
183
									value.$(field.name) = decoder.json[start..end].int()
184
								} $else $if v.typ is i64 {
185
									value.$(field.name) = decoder.json[start..end].i64()
186
								} $else $if v.typ is u8 {
187
									value.$(field.name) = decoder.json[start..end].u8()
188
								} $else $if v.typ is u16 {
189
									value.$(field.name) = decoder.json[start..end].u16()
190
								} $else $if v.typ is u32 {
191
									value.$(field.name) = decoder.json[start..end].u32()
192
								} $else $if v.typ is u64 {
193
									value.$(field.name) = decoder.json[start..end].u64()
194
								} $else $if v.typ is f32 {
195
									value.$(field.name) = decoder.json[start..end].f32()
196
								} $else $if v.typ is f64 {
197
									value.$(field.name) = decoder.json[start..end].f64()
198
								}
199
							} $else $if v.typ is bool {
200
								if decoder.json[start] == `t` {
201
									value.$(field.name) = true
202
								} else if decoder.json[start] == `f` {
203
									value.$(field.name) = false
204
								}
205
							} $else $if v.typ is time.Time {
206
								if value_kind == .string_ {
207
									value.$(field.name) = time.parse(decoder.json[start + 1..end - 1]) or {
208
										time.Time{}
209
									}
210
								}
211
							} $else $if v.typ is $struct {
212
								if 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 {
219
								if value_kind == .array {
220
									// TODO
221
								}
222
							} $else $if v.typ is $map {
223
								if value_kind == .object {
224
									// TODO
225
								}
226
							} $else $if T is $enum {
227
							} $else {
228
								eprintln('not supported')
229
							}
230
						}
231
						if value_kind == .string_ {
232
							// value.$(field.name) = decoder.json[start + 1..end - 1]
233
						} else if decoder.json[start] == `t` {
234
							value.$(field.name) = true
235
						} else if decoder.json[start] == `f` {
236
							value.$(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 {
244
						value.$(field.name) = if value_kind == .string_ {
245
							decoder.json[start + 1..end - 1]
246
						} else {
247
							decoder.json[start..end]
248
						}
249
					} $else $if field.typ in [$int, $float] {
250
						$if field.typ is i8 {
251
							value.$(field.name) = decoder.json[start..end].i8()
252
						} $else $if field.typ is i16 {
253
							value.$(field.name) = decoder.json[start..end].i16()
254
						} $else $if field.typ is i32 {
255
							value.$(field.name) = decoder.json[start..end].i32()
256
						} $else $if field.typ is int {
257
							value.$(field.name) = decoder.json[start..end].int()
258
						} $else $if field.typ is i64 {
259
							value.$(field.name) = decoder.json[start..end].i64()
260
						} $else $if field.typ is u8 {
261
							value.$(field.name) = decoder.json[start..end].u8()
262
						} $else $if field.typ is u16 {
263
							value.$(field.name) = decoder.json[start..end].u16()
264
						} $else $if field.typ is u32 {
265
							value.$(field.name) = decoder.json[start..end].u32()
266
						} $else $if field.typ is u64 {
267
							value.$(field.name) = decoder.json[start..end].u64()
268
						} $else $if field.typ is f32 {
269
							value.$(field.name) = decoder.json[start..end].f32()
270
						} $else $if field.typ is f64 {
271
							value.$(field.name) = decoder.json[start..end].f64()
272
						}
273
					} $else $if field.typ is bool {
274
						value.$(field.name) = decoder.json[start] == `t`
275
					} $else $if field.typ is time.Time {
276
						if value_kind == .string_ {
277
							value.$(field.name) = time.parse_rfc3339(decoder.json[start + 1..end - 1]) or {
278
								time.Time{}
279
							}
280
						}
281
					} $else $if field.typ is $struct {
282
						if node.children != none {
283
							decoder.decode_value(node.children or { panic('It will never happen') },
284
								value.$(field.name))
285
						}
286
					} $else $if field.typ is $array {
287
						if value_kind == .array {
288
							// TODO
289
						}
290
					} $else $if field.typ is $map {
291
						if value_kind == .object && node.children != none {
292
							decoder.decode_map(node.children or { panic('It will never happen') }, mut
293
								value.$(field.name))
294
						}
295
					} $else $if field.typ is $enum {
296
						value.$(field.name) = decoder.json[start..end].int()
297
					} $else $if field.typ is $alias {
298
						$if field.unaliased_typ is string {
299
							if value_kind == .string_ {
300
								value.$(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 {
306
								value.$(field.name) = decoder.json[start..end].i8()
307
							} $else $if field.unaliased_typ is i16 {
308
								value.$(field.name) = decoder.json[start..end].i16()
309
							} $else $if field.unaliased_typ is i32 {
310
								value.$(field.name) = decoder.json[start..end].i32()
311
							} $else $if field.unaliased_typ is int {
312
								value.$(field.name) = decoder.json[start..end].int()
313
							} $else $if field.unaliased_typ is i64 {
314
								value.$(field.name) = decoder.json[start..end].i64()
315
							} $else $if field.unaliased_typ is u8 {
316
								value.$(field.name) = decoder.json[start..end].u8()
317
							} $else $if field.unaliased_typ is u16 {
318
								value.$(field.name) = decoder.json[start..end].u16()
319
							} $else $if field.unaliased_typ is u32 {
320
								value.$(field.name) = decoder.json[start..end].u32()
321
							} $else $if field.unaliased_typ is u64 {
322
								value.$(field.name) = decoder.json[start..end].u64()
323
							} $else $if field.unaliased_typ is f32 {
324
								value.$(field.name) = decoder.json[start..end].f32()
325
							} $else $if field.unaliased_typ is f64 {
326
								value.$(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 {
336
							eprintln('the alias ${field.unaliased_typ} cannot be encoded')
337
						}
338
					} $else {
339
						eprintln('not supported')
340
					}
341
					break
342
				}
343
			}
344
		}
345
	}
346
}
347

348
// decode_map decodes a map from the JSON nodes.
349
fn (mut decoder Decoder) decode_map[T](nodes []Node, mut val T) {
350
	for i := 0; i < nodes.len; i++ {
351
		mut node := nodes[i]
352

353
		start := (node.key_pos + node.key_len) + 3
354
		mut end := start
355
		for decoder.json[end] != `,` && decoder.json[end] != `}` {
356
			end++
357
		}
358
		value_kind := get_value_kind(decoder.json[start])
359
		val[decoder.json[node.key_pos..node.key_pos + node.key_len]] = if value_kind == .string_ {
360
			decoder.json[start + 1..end - 1]
361
		} else {
362
			decoder.json[start..end]
363
		}
364
	}
365
}
366

367
// fulfill_nodes fills the nodes from the JSON string.
368
fn (mut decoder Decoder) fulfill_nodes(mut nodes []Node) {
369
	mut inside_string := false
370
	mut inside_key := false
371
	mut actual_key_len := 0
372

373
	for decoder.idx < decoder.json.len {
374
		letter := decoder.json[decoder.idx]
375
		match letter {
376
			` ` {
377
				if !inside_string {
378
				}
379
			}
380
			`\"` {
381
				if decoder.json[decoder.idx - 1] == `{` || decoder.json[decoder.idx - 2] == `,` {
382
					inside_key = true
383
				} else if decoder.json[decoder.idx + 1] == `:` {
384
					if decoder.json[decoder.idx + 3] == `{` {
385
						mut children := []Node{}
386
						key_pos := decoder.idx - actual_key_len
387
						key_len := actual_key_len
388

389
						decoder.idx += 3
390
						decoder.fulfill_nodes(mut children)
391

392
						nodes << Node{
393
							key_pos:  key_pos
394
							key_len:  key_len
395
							children: children
396
						}
397
					} else {
398
						nodes << Node{
399
							key_pos: decoder.idx - actual_key_len
400
							key_len: actual_key_len
401
						}
402
					}
403
					inside_key = false
404
				}
405
				inside_string = !inside_string
406
				decoder.idx++
407
				continue
408
			}
409
			`:` {
410
				actual_key_len = 0
411
			}
412
			`,`, `{`, `}`, `[`, `]` {}
413
			else {}
414
		}
415
		if inside_key {
416
			actual_key_len++
417
		}
418
		decoder.idx++
419
	}
420
}
421

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.