v / vlib / x / json2 / decode.v
1612 lines · 1451 sloc · 45.97 KB · 390efe46a1f46f302ae98c803b8ffbbb333fdb28
Raw
1module json2
2
3import strconv
4import time
5
6const null_in_string = 'null'
7
8const true_in_string = 'true'
9
10const false_in_string = 'false'
11
12const float_zero_in_string = '0.0'
13
14const whitespace_chars = [` `, `\t`, `\n`, `\r`]!
15
16// Node represents a node in a linked list to store ValueInfo.
17struct Node[T] {
18mut:
19 value T
20 next &Node[T] = unsafe { nil } // next is the next node in the linked list.
21}
22
23// ValueInfo represents the position and length of a value, such as string, number, array, object key, and object value in a JSON string.
24struct ValueInfo {
25 position int // The position of the value in the JSON string.
26 value_kind ValueKind // The kind of the value.
27mut:
28 length int // The length of the value in the JSON string.
29}
30
31struct DecoderFieldInfo {
32 key_name string
33
34 is_omitempty bool
35 is_skip bool
36 is_required bool
37 is_raw bool
38}
39
40@[markused]
41struct StructFieldInfo {
42 json_name_ptr voidptr
43 json_name_len int
44 is_omitempty bool
45 is_skip bool
46 is_required bool
47 is_raw bool
48}
49
50struct StructKeyDecodeResult[T] {
51 matched bool
52 value T
53}
54
55// DecoderOptions provides options for JSON decoding.
56// By default, decoding is lenient. Use `strict: true` for strict JSON spec compliance.
57@[markused; params]
58pub struct DecoderOptions {
59pub:
60 // In strict mode, quoted strings are not accepted as numbers.
61 // For example, '"123"' will fail to decode as int in strict mode,
62 // but will succeed in default mode.
63 strict bool
64}
65
66// Decoder is the internal decoding state.
67@[markused]
68struct Decoder {
69 json string // json is the JSON data to be decoded.
70 strict bool // strict mode rejects quoted strings as numbers
71mut:
72 values_info LinkedList[ValueInfo] // A linked list to store ValueInfo.
73 checker_idx int // checker_idx is the current index of the decoder.
74 current_node &Node[ValueInfo] = unsafe { nil } // The current node in the linked list.
75}
76
77// LinkedList represents a linked list to store ValueInfo.
78struct LinkedList[T] {
79mut:
80 head &Node[T] = unsafe { nil } // head is the first node in the linked list.
81 tail &Node[T] = unsafe { nil } // tail is the last node in the linked list.
82 len int // len is the length of the linked list.
83}
84
85// push adds a new element to the linked list.
86fn (mut list LinkedList[T]) push(value T) {
87 node := &Node[T]{
88 value: value
89 }
90 if list.head == unsafe { nil } {
91 list.head = node
92 list.tail = node
93 } else {
94 list.tail.next = node
95 list.tail = node
96 }
97 list.len++
98}
99
100// last returns the last element added to the linked list.
101fn (list &LinkedList[T]) last() &T {
102 return &list.tail.value
103}
104
105// str returns a string representation of the linked list.
106fn (list &LinkedList[ValueInfo]) str() string {
107 mut result_buffer := []u8{}
108 mut current := list.head
109 for current != unsafe { nil } {
110 value_kind_as_string := current.value.value_kind.str()
111 unsafe { result_buffer.push_many(value_kind_as_string.str, value_kind_as_string.len) }
112 result_buffer << u8(` `)
113
114 current = current.next
115 }
116 return result_buffer.bytestr()
117}
118
119@[unsafe]
120fn (list &LinkedList[T]) free() {
121 mut current := list.head
122 for current != unsafe { nil } {
123 mut next := current.next
124 current.next = unsafe { nil }
125 unsafe { free(current) }
126 current = next
127 }
128 list.head = unsafe { nil }
129 list.tail = unsafe { nil }
130 list.len = 0
131}
132
133const max_context_length = 50
134const max_extra_characters = 5
135const tab_width = 8
136
137pub struct JsonDecodeError {
138 Error
139 context string
140pub:
141 message string
142
143 line int
144 character int
145}
146
147fn (e JsonDecodeError) msg() string {
148 return '\n${e.line}:${e.character}: Invalid json: ${e.message}\n${e.context}'
149}
150
151// checker_error generates a checker error message showing the position in the json string
152@[markused]
153fn (mut checker Decoder) checker_error(message string) ! {
154 position := checker.checker_idx
155
156 mut line_number := 0
157 mut character_number := 0
158 mut last_newline := 0
159
160 for i := position - 1; i >= 0; i-- {
161 if last_newline == 0 {
162 if checker.json[i] == `\n` {
163 last_newline = i + 1
164 } else if checker.json[i] == `\t` {
165 character_number += tab_width
166 } else {
167 character_number++
168 }
169 }
170 if checker.json[i] == `\n` {
171 line_number++
172 }
173 }
174
175 cutoff := character_number > max_context_length
176
177 // either start of string, last newline or a limited amount of characters
178 context_start := if cutoff { position - max_context_length } else { last_newline }
179
180 // print some extra characters
181 mut context_end := int_min(checker.json.len, position + max_extra_characters)
182 context_end_newline := checker.json[position..context_end].index_u8(`\n`)
183
184 if context_end_newline != -1 {
185 context_end = position + context_end_newline
186 }
187
188 mut context := ''
189
190 if cutoff {
191 context += '...'
192 }
193 context += checker.json[context_start..position]
194 context += '\e[31m${checker.json[position].ascii_str()}\e[0m'
195 context += checker.json[position + 1..context_end]
196 context += '\n'
197
198 if cutoff {
199 context += ' '.repeat(max_context_length + 3)
200 } else {
201 context += ' '.repeat(character_number)
202 }
203 context += '\e[31m^\e[0m'
204
205 return JsonDecodeError{
206 context: context
207 message: 'Syntax: ${message}'
208 line: line_number + 1
209 character: character_number + 1
210 }
211}
212
213// decode_error generates a decoding error from the decoding stage
214@[markused]
215fn (mut decoder Decoder) decode_error(message string) ! {
216 mut error_info := ValueInfo{}
217 if decoder.current_node != unsafe { nil } {
218 error_info = decoder.current_node.value
219 } else {
220 error_info = decoder.values_info.tail.value
221 }
222
223 start := error_info.position
224 end := start + int_min(error_info.length, max_context_length)
225
226 mut line_number := 0
227 mut character_number := 0
228 mut last_newline := 0
229
230 for i := start - 1; i >= 0; i-- {
231 if last_newline == 0 {
232 if decoder.json[i] == `\n` {
233 last_newline = i + 1
234 } else if decoder.json[i] == `\t` {
235 character_number += tab_width
236 } else {
237 character_number++
238 }
239 }
240 if decoder.json[i] == `\n` {
241 line_number++
242 }
243 }
244
245 cutoff := character_number > max_context_length
246
247 // either start of string, last newline or a limited amount of characters
248 context_start := if cutoff { start - max_context_length } else { last_newline }
249
250 // print some extra characters
251 mut context_end := int_min(decoder.json.len, end + max_extra_characters)
252 context_end_newline := decoder.json[end..context_end].index_u8(`\n`)
253
254 if context_end_newline != -1 {
255 context_end = end + context_end_newline
256 }
257
258 mut context := ''
259
260 if cutoff {
261 context += '...'
262 }
263 context += decoder.json[context_start..start]
264 context += '\e[31m${decoder.json[start..end]}\e[0m'
265 context += decoder.json[end..context_end]
266 context += '\n'
267
268 if cutoff {
269 context += ' '.repeat(max_context_length + 3)
270 } else {
271 context += ' '.repeat(character_number)
272 }
273 context += '\e[31m${'~'.repeat(error_info.length)}\e[0m'
274
275 return JsonDecodeError{
276 context: context
277 message: 'Data: ${message}'
278 line: line_number + 1
279 character: character_number + 1
280 }
281}
282
283// decode decodes a JSON string into a specified type.
284// By default, decoding is lenient. Use `strict: true` for strict JSON spec compliance.
285@[manualfree]
286pub fn decode[T](val string, params DecoderOptions) !T {
287 if val == '' {
288 return JsonDecodeError{
289 message: 'empty string'
290 line: 1
291 character: 1
292 }
293 }
294 mut decoder := Decoder{
295 json: val
296 strict: params.strict
297 }
298
299 decoder.check_json_format()!
300
301 mut result := T{}
302 decoder.current_node = decoder.values_info.head
303 $if T.unaliased_typ is $array_dynamic {
304 result.clear()
305 decoder.decode_array(mut result)!
306 } $else $if T.unaliased_typ is $map {
307 decoder.decode_map(mut result)!
308 } $else $if T.indirections == 1 {
309 if decoder.current_node.value.value_kind == .null {
310 if decoder.current_node != unsafe { nil } {
311 decoder.current_node = decoder.current_node.next
312 }
313 } else {
314 mut decoded_ptr := create_decoded_ptr(result)
315 decoder.decode_value(mut decoded_ptr)!
316 result = decoded_ptr
317 }
318 } $else {
319 decoder.decode_value(mut result)!
320 }
321 return result
322}
323
324fn get_dynamic_from_element[T](_t T) []T {
325 return []T{}
326}
327
328fn create_decoded_ptr[T](_ &T) &T {
329 $if T is $interface {
330 return unsafe { nil }
331 } $else $if T.unaliased_typ is voidptr {
332 return unsafe { nil }
333 } $else {
334 return unsafe { &T(vcalloc(sizeof(T))) }
335 }
336}
337
338fn create_decoded_option_ptr[U](_ ?&U) &U {
339 return &U{}
340}
341
342fn decoder_field_infos[T]() []DecoderFieldInfo {
343 mut field_infos := []DecoderFieldInfo{}
344 $for field in T.fields {
345 mut key_name := field.name
346 mut is_json_skip := false
347 for attr in field.attrs {
348 if start, end := json_attr_value_range(attr) {
349 if end <= start {
350 continue
351 }
352 if end == start + 1 && attr[start] == `-` {
353 is_json_skip = true
354 break
355 }
356 key_name = attr[start..end]
357 break
358 }
359 }
360 field_infos << DecoderFieldInfo{
361 key_name: key_name
362 is_omitempty: field.attrs.contains('omitempty')
363 is_skip: field.attrs.contains('skip') || is_json_skip
364 is_required: field.attrs.contains('required')
365 is_raw: field.attrs.contains('raw')
366 }
367 }
368 return field_infos
369}
370
371@[manualfree; unsafe]
372fn (mut decoder Decoder) cached_struct_field_infos[T]() []StructFieldInfo {
373 static field_infos := &[]StructFieldInfo(nil)
374 if field_infos == nil {
375 field_infos = &[]StructFieldInfo{}
376 $for field in T.fields {
377 mut json_name_str := field.name.str
378 mut json_name_len := field.name.len
379 mut is_json_skip := false
380 for attr in field.attrs {
381 if start, end := json_attr_value_range(attr) {
382 if end <= start {
383 continue
384 }
385 if end == start + 1 && attr[start] == `-` {
386 is_json_skip = true
387 break
388 }
389 json_name_str = unsafe { attr.str + start }
390 json_name_len = end - start
391 break
392 }
393 }
394 field_infos << StructFieldInfo{
395 json_name_ptr: voidptr(json_name_str)
396 json_name_len: json_name_len
397 is_omitempty: field.attrs.contains('omitempty')
398 is_skip: field.attrs.contains('skip') || is_json_skip
399 is_required: field.attrs.contains('required')
400 is_raw: field.attrs.contains('raw')
401 }
402 }
403 }
404 return *field_infos
405}
406
407@[inline; markused]
408fn struct_field_is_decoded(decoded_mask u64, decoded_fields []bool, field_idx int) bool {
409 if field_idx < 64 {
410 return (decoded_mask & (u64(1) << u64(field_idx))) != 0
411 }
412 return decoded_fields[field_idx]
413}
414
415@[inline; markused]
416fn mark_struct_field_decoded(decoded_mask u64, mut decoded_fields []bool, field_idx int) u64 {
417 if field_idx < 64 {
418 return decoded_mask | (u64(1) << u64(field_idx))
419 }
420 decoded_fields[field_idx] = true
421 return decoded_mask
422}
423
424@[inline]
425fn (decoder &Decoder) json_key_matches(key_info ValueInfo, key_name string) bool {
426 if key_info.length - 2 != key_name.len {
427 return false
428 }
429 return unsafe {
430 vmemcmp(decoder.json.str + key_info.position + 1, key_name.str, key_name.len) == 0
431 }
432}
433
434@[inline; markused]
435fn (decoder &Decoder) is_empty_value(value_info ValueInfo) bool {
436 match value_info.value_kind {
437 .null {
438 return true
439 }
440 .string {
441 return value_info.length == 2
442 }
443 .number {
444 if decoder.json[value_info.position] == `0` {
445 if value_info.length == 1 {
446 return true
447 }
448 if value_info.length == 3 {
449 return unsafe {
450 vmemcmp(decoder.json.str + value_info.position, float_zero_in_string.str,
451 float_zero_in_string.len) == 0
452 }
453 }
454 }
455 }
456 else {}
457 }
458
459 return false
460}
461
462@[markused]
463fn (mut decoder Decoder) skip_current_value() {
464 if decoder.current_node == unsafe { nil } {
465 return
466 }
467 value_end := decoder.current_node.value.position + decoder.current_node.value.length
468 for decoder.current_node != unsafe { nil } && decoder.current_node.value.position < value_end {
469 decoder.current_node = decoder.current_node.next
470 }
471}
472
473@[manualfree]
474fn decode_struct_key[T](mut decoder Decoder, val T, key_info ValueInfo, prefix string, mut seen_required []string) !StructKeyDecodeResult[T] {
475 field_infos := decoder_field_infos[T]()
476 mut new_val := val
477 mut i := 0
478 $for field in T.fields {
479 field_info := field_infos[i]
480 $if !field.is_embed {
481 if decoder.json_key_matches(key_info, field_info.key_name)
482 || (prefix != ''
483 && decoder.json_key_matches(key_info, prefix + field_info.key_name)) {
484 decoder.current_node = decoder.current_node.next
485
486 if field_info.is_skip {
487 if field_info.is_required {
488 seen_required << prefix + field.name
489 }
490 decoder.skip_current_value()
491 return StructKeyDecodeResult[T]{
492 matched: true
493 value: new_val
494 }
495 }
496
497 if field_info.is_omitempty && decoder.current_node != unsafe { nil }
498 && decoder.is_empty_value(decoder.current_node.value) {
499 decoder.skip_current_value()
500 return StructKeyDecodeResult[T]{
501 matched: true
502 value: new_val
503 }
504 }
505
506 if field_info.is_required {
507 seen_required << prefix + field.name
508 }
509
510 if field_info.is_raw {
511 $if field.unaliased_typ is $enum {
512 decoder.decode_error('`raw` attribute cannot be used with enum fields')!
513 } $else $if field.typ is ?string {
514 position := decoder.current_node.value.position
515 end := position + decoder.current_node.value.length
516
517 new_val.$(field.name) = decoder.json[position..end]
518 decoder.current_node = decoder.current_node.next
519
520 for {
521 if decoder.current_node == unsafe { nil }
522 || decoder.current_node.value.position + decoder.current_node.value.length >= end {
523 break
524 }
525 decoder.current_node = decoder.current_node.next
526 }
527 } $else $if field.typ is string {
528 position := decoder.current_node.value.position
529 end := position + decoder.current_node.value.length
530
531 new_val.$(field.name) = decoder.json[position..end]
532 decoder.current_node = decoder.current_node.next
533
534 for {
535 if decoder.current_node == unsafe { nil }
536 || decoder.current_node.value.position + decoder.current_node.value.length >= end {
537 break
538 }
539 decoder.current_node = decoder.current_node.next
540 }
541 } $else {
542 decoder.decode_error('`raw` attribute can only be used with string fields')!
543 }
544 } else {
545 $if field.typ is $option {
546 if decoder.current_node.value.value_kind == .null {
547 new_val.$(field.name) = none
548
549 if decoder.current_node != unsafe { nil } {
550 decoder.current_node = decoder.current_node.next
551 }
552 } else {
553 $if field.indirections == 1 {
554 mut decoded_ptr := create_decoded_option_ptr(new_val.$(field.name))
555 decoder.decode_value(mut decoded_ptr)!
556 new_val.$(field.name) = decoded_ptr
557 } $else {
558 mut unwrapped_val := create_value_from_optional(new_val.$(field.name)) or {
559 return StructKeyDecodeResult[T]{
560 matched: false
561 value: val
562 }
563 }
564 decoder.decode_value(mut unwrapped_val)!
565 new_val.$(field.name) = unwrapped_val
566 }
567 }
568 } $else $if field.unaliased_typ is $array_dynamic {
569 if decoder.current_node.value.value_kind == .null && !field_info.is_required {
570 new_val.$(field.name).clear()
571 decoder.skip_current_value()
572 } else {
573 new_val.$(field.name).clear()
574 decoder.decode_array(mut new_val.$(field.name))!
575 }
576 } $else $if field.unaliased_typ is $map {
577 if decoder.current_node.value.value_kind == .null && !field_info.is_required {
578 new_val.$(field.name).clear()
579 decoder.skip_current_value()
580 } else {
581 decoder.decode_map(mut new_val.$(field.name))!
582 }
583 } $else $if field.unaliased_typ is string {
584 value_info := decoder.current_node.value
585 if value_info.value_kind == .object || value_info.value_kind == .array {
586 new_val.$(field.name) = decoder.json[value_info.position..
587 value_info.position + value_info.length]
588 decoder.skip_current_value()
589 } else if value_info.value_kind == .null && !field_info.is_required {
590 new_val.$(field.name) = ''
591 decoder.skip_current_value()
592 } else {
593 decoder.decode_value(mut new_val.$(field.name))!
594 }
595 } $else $if field.indirections == 1 {
596 if decoder.current_node.value.value_kind == .null {
597 new_val.$(field.name) = unsafe { nil }
598
599 if decoder.current_node != unsafe { nil } {
600 decoder.current_node = decoder.current_node.next
601 }
602 } else {
603 mut decoded_ptr := create_decoded_ptr(new_val.$(field.name))
604 decoder.decode_value(mut decoded_ptr)!
605 new_val.$(field.name) = decoded_ptr
606 }
607 } $else {
608 decoder.decode_value(mut new_val.$(field.name))!
609 }
610 }
611 return StructKeyDecodeResult[T]{
612 matched: true
613 value: new_val
614 }
615 }
616 }
617 i++
618 }
619 i = 0
620 $for field in T.fields {
621 field_info := field_infos[i]
622 $if field.is_embed {
623 if decoder.json_key_matches(key_info, field_info.key_name)
624 && decoder.current_node.next != unsafe { nil }
625 && decoder.current_node.next.value.value_kind == .object {
626 if field_info.is_required {
627 seen_required << prefix + field.name
628 }
629 decoder.current_node = decoder.current_node.next
630 decoder.decode_value(mut new_val.$(field.name))!
631 return StructKeyDecodeResult[T]{
632 matched: true
633 value: new_val
634 }
635 }
636 {
637 embed_result := decode_struct_key(mut decoder, new_val.$(field.name), key_info,
638
639 prefix + field.name + '.', mut seen_required)!
640 if embed_result.matched {
641 new_val.$(field.name) = embed_result.value
642 return StructKeyDecodeResult[T]{
643 matched: true
644 value: new_val
645 }
646 }
647 }
648 }
649 i++
650 }
651 return StructKeyDecodeResult[T]{
652 matched: false
653 value: val
654 }
655}
656
657fn check_required_struct_fields[T](mut decoder Decoder, val T, seen_required []string, prefix string) ! {
658 field_infos := decoder_field_infos[T]()
659 mut i := 0
660 $for field in T.fields {
661 field_info := field_infos[i]
662 if field_info.is_required && prefix + field.name !in seen_required {
663 decoder.decode_error('missing required field `${field.name}`')!
664 }
665 $if field.is_embed {
666 check_required_struct_fields(mut decoder, val.$(field.name), seen_required, prefix +
667 field.name + '.')!
668 }
669 i++
670 }
671}
672
673// decode_value decodes a value from the JSON nodes.
674@[manualfree]
675fn (mut decoder Decoder) decode_value[T](mut val T) ! {
676 $if T.unaliased_typ is voidptr {
677 // skip voidptr fields - they cannot be decoded from JSON
678 if decoder.current_node != unsafe { nil } {
679 decoder.current_node = decoder.current_node.next
680 }
681 return
682 } $else $if T is $interface {
683 // skip interface fields - they cannot be decoded from JSON
684 if decoder.current_node != unsafe { nil } {
685 decoder.current_node = decoder.current_node.next
686 }
687 return
688 } $else {
689 // Custom Decoders
690 $if val is StringDecoder {
691 struct_info := decoder.current_node.value
692
693 if struct_info.value_kind == .string {
694 val.from_json_string(decoder.json[struct_info.position + 1..struct_info.position +
695 struct_info.length - 1]) or {
696 decoder.decode_error('${typeof(val).name}: ${err.msg()}')!
697 }
698 if decoder.current_node != unsafe { nil } {
699 decoder.current_node = decoder.current_node.next
700 }
701
702 return
703 }
704 }
705 $if val is NumberDecoder {
706 struct_info := decoder.current_node.value
707
708 if struct_info.value_kind == .number {
709 val.from_json_number(decoder.json[struct_info.position..struct_info.position +
710 struct_info.length]) or {
711 decoder.decode_error('${typeof(val).name}: ${err.msg()}')!
712 }
713 if decoder.current_node != unsafe { nil } {
714 decoder.current_node = decoder.current_node.next
715 }
716
717 return
718 }
719 }
720 $if val is BooleanDecoder {
721 struct_info := decoder.current_node.value
722
723 if struct_info.value_kind == .boolean {
724 val.from_json_boolean(decoder.json[struct_info.position] == `t`)
725 if decoder.current_node != unsafe { nil } {
726 decoder.current_node = decoder.current_node.next
727 }
728
729 return
730 }
731 }
732 $if val is NullDecoder {
733 struct_info := decoder.current_node.value
734
735 if struct_info.value_kind == .null {
736 val.from_json_null()
737 if decoder.current_node != unsafe { nil } {
738 decoder.current_node = decoder.current_node.next
739 }
740
741 return
742 }
743 }
744 $if T.unaliased_typ is voidptr {
745 // skip voidptr fields - they cannot be decoded from JSON
746 if decoder.current_node != unsafe { nil } {
747 decoder.current_node = decoder.current_node.next
748 }
749 return
750 } $else $if T.unaliased_typ is string {
751 decoder.decode_string(mut val)!
752 } $else $if T.unaliased_typ is time.Time {
753 value_info := decoder.current_node.value
754 mut decoded_time := time.Time{}
755 if value_info.value_kind == .string {
756 decoded_time.from_json_string(decoder.json[value_info.position + 1..
757 value_info.position + value_info.length - 1]) or {
758 decoder.decode_error('${typeof(val).name}: ${err.msg()}')!
759 }
760 } else if value_info.value_kind == .number {
761 decoded_time.from_json_number(decoder.json[value_info.position..
762 value_info.position + value_info.length]) or {
763 decoder.decode_error('${typeof(val).name}: ${err.msg()}')!
764 }
765 } else {
766 decoder.decode_error('Expected string or number, but got ${value_info.value_kind}')!
767 }
768 val = T(decoded_time)
769 } $else $if T.unaliased_typ is $sumtype {
770 decoder.decode_sumtype(mut val)!
771 return
772 } $else $if T.unaliased_typ is $map {
773 decoder.decode_map(mut val)!
774 return
775 } $else $if T.unaliased_typ is $array_dynamic {
776 val.clear()
777 decoder.decode_array(mut val)!
778 // return to avoid the next increment of the current node
779 // this is because the current node is already incremented in the decode_array function
780 // remove this line will cause the current node to be incremented twice
781 // and bug recursive array decoding like `[][]int{}`
782 return
783 } $else $if T.unaliased_typ is $array_fixed {
784 mut dynamic_val := get_dynamic_from_element(val[0])
785
786 // avoid copying by pointing dynamic_val to val
787 unsafe {
788 dynamic_val.len = 0
789 dynamic_val.cap = val.len // ensures data wont reallocate
790 dynamic_val.data = &val
791 }
792 decoder.decode_array(mut dynamic_val)!
793
794 if dynamic_val.len != val.len {
795 decoder.decode_error('Fixed size array expected ${val.len} elements but got ${dynamic_val.len} elements')!
796 }
797 return
798 } $else $if T.unaliased_typ is $struct {
799 struct_info := decoder.current_node.value
800
801 if struct_info.value_kind == .object {
802 struct_position := struct_info.position
803 struct_end := struct_position + struct_info.length
804 mut has_embeds := false
805 $for field in T.fields {
806 $if field.is_embed {
807 has_embeds = true
808 }
809 }
810 decoder.current_node = decoder.current_node.next
811 if has_embeds {
812 mut seen_required := []string{}
813
814 // json object loop
815 for {
816 if decoder.current_node == unsafe { nil } {
817 break
818 }
819
820 key_info := decoder.current_node.value
821
822 if key_info.position >= struct_end {
823 break
824 }
825
826 decode_result := decode_struct_key(mut decoder, val, key_info, '', mut
827 seen_required)!
828 if decode_result.matched {
829 val = decode_result.value
830 } else {
831 // The key doesn't match any field in the struct, skip the entire value
832 // including all nested objects/arrays.
833 decoder.current_node = decoder.current_node.next
834 decoder.skip_current_value()
835 }
836 }
837
838 check_required_struct_fields(mut decoder, val, seen_required, '')!
839 } else {
840 field_infos := unsafe { decoder.cached_struct_field_infos[T]() }
841 mut decoded_mask := u64(0)
842 mut decoded_fields := []bool{}
843 if field_infos.len > 64 {
844 decoded_fields = []bool{len: field_infos.len}
845 }
846
847 mut field_idx := 0
848 // json object loop
849 for {
850 if decoder.current_node == unsafe { nil } {
851 break
852 }
853
854 key_info := decoder.current_node.value
855
856 if key_info.position >= struct_end {
857 break
858 }
859
860 mut matched := false
861 field_idx = 0
862 $for field in T.fields {
863 if !matched {
864 field_info := field_infos[field_idx]
865 field_can_match := (!field_info.is_skip || field_info.is_required)
866 && !(field_info.is_omitempty
867 && decoder.is_empty_value(decoder.current_node.next.value))
868 field_name_matches := key_info.length - 2 == field_info.json_name_len && unsafe {
869 vmemcmp(decoder.json.str + key_info.position + 1, field_info.json_name_ptr, field_info.json_name_len) == 0
870 }
871 if field_can_match && field_name_matches {
872 // value node
873 decoder.current_node = decoder.current_node.next
874
875 if field_info.is_skip {
876 // Preserve the existing inline decode behavior for `skip`+`required`.
877 decoded_mask = mark_struct_field_decoded(decoded_mask, mut
878 decoded_fields, field_idx)
879 if decoder.current_node != unsafe { nil } {
880 decoder.current_node = decoder.current_node.next
881 }
882 } else if field_info.is_raw {
883 $if field.unaliased_typ is $enum {
884 // workaround to avoid the error: enums can only be assigned `int` values
885 decoder.decode_error('`raw` attribute cannot be used with enum fields')!
886 } $else $if field.typ is ?string {
887 position := decoder.current_node.value.position
888 end := position + decoder.current_node.value.length
889
890 val.$(field.name) = decoder.json[position..end]
891 decoder.current_node = decoder.current_node.next
892
893 for {
894 if decoder.current_node == unsafe { nil }
895 || decoder.current_node.value.position + decoder.current_node.value.length >= end {
896 break
897 }
898 decoder.current_node = decoder.current_node.next
899 }
900 } $else $if field.typ is string {
901 position := decoder.current_node.value.position
902 end := position + decoder.current_node.value.length
903
904 val.$(field.name) = decoder.json[position..end]
905 decoder.current_node = decoder.current_node.next
906
907 for {
908 if decoder.current_node == unsafe { nil }
909 || decoder.current_node.value.position + decoder.current_node.value.length >= end {
910 break
911 }
912 decoder.current_node = decoder.current_node.next
913 }
914 } $else {
915 decoder.decode_error('`raw` attribute can only be used with string fields')!
916 }
917 } else {
918 $if field.typ is $option {
919 // it would be nicer to do this at the start of the function
920 // but options cant be passed to generic functions
921 if decoder.current_node.value.value_kind == .null {
922 val.$(field.name) = none
923
924 if decoder.current_node != unsafe { nil } {
925 decoder.current_node = decoder.current_node.next
926 }
927 } else {
928 $if field.indirections == 1 {
929 mut decoded_ptr :=
930 create_decoded_option_ptr(val.$(field.name))
931 decoder.decode_value(mut decoded_ptr)!
932 val.$(field.name) = decoded_ptr
933 } $else {
934 mut unwrapped_val := create_value_from_optional(val.$(field.name)) or {
935 return
936 }
937 decoder.decode_value(mut unwrapped_val)!
938 val.$(field.name) = unwrapped_val
939 }
940 }
941 } $else $if field.unaliased_typ is $array_dynamic {
942 if decoder.current_node.value.value_kind == .null
943 && !field_info.is_required {
944 val.$(field.name).clear()
945 decoder.skip_current_value()
946 } else {
947 val.$(field.name).clear()
948 decoder.decode_array(mut val.$(field.name))!
949 }
950 } $else $if field.unaliased_typ is $map {
951 if decoder.current_node.value.value_kind == .null
952 && !field_info.is_required {
953 val.$(field.name).clear()
954 decoder.skip_current_value()
955 } else {
956 decoder.decode_map(mut val.$(field.name))!
957 }
958 } $else $if field.unaliased_typ is string {
959 value_info := decoder.current_node.value
960 if value_info.value_kind == .object
961 || value_info.value_kind == .array {
962 val.$(field.name) = decoder.json[value_info.position..
963 value_info.position + value_info.length]
964 decoder.skip_current_value()
965 } else if value_info.value_kind == .null
966 && !field_info.is_required {
967 val.$(field.name) = ''
968 decoder.skip_current_value()
969 } else {
970 mut decoded_field_value := val.$(field.name)
971 decoder.decode_value(mut decoded_field_value)!
972 val.$(field.name) = decoded_field_value
973 }
974 } $else $if field.indirections == 1 {
975 if decoder.current_node.value.value_kind == .null {
976 val.$(field.name) = unsafe { nil }
977
978 if decoder.current_node != unsafe { nil } {
979 decoder.current_node = decoder.current_node.next
980 }
981 } else {
982 mut decoded_ptr :=
983 create_decoded_ptr(val.$(field.name))
984 decoder.decode_value(mut decoded_ptr)!
985 val.$(field.name) = decoded_ptr
986 }
987 } $else {
988 mut decoded_field_value := val.$(field.name)
989 decoder.decode_value(mut decoded_field_value)!
990 $if field.unaliased_typ is $map {
991 val.$(field.name) = decoded_field_value.move()
992 } $else {
993 val.$(field.name) = decoded_field_value
994 }
995 }
996 }
997
998 decoded_mask = mark_struct_field_decoded(decoded_mask, mut
999 decoded_fields, field_idx)
1000 matched = true
1001 }
1002 }
1003 field_idx++
1004 }
1005 if !matched {
1006 // The key doesn't match any field in the struct, skip the entire value
1007 // including all nested objects/arrays.
1008 decoder.current_node = decoder.current_node.next
1009 decoder.skip_current_value()
1010 }
1011 }
1012
1013 // check if all required fields are present
1014 field_idx = 0
1015 $for field in T.fields {
1016 field_info := field_infos[field_idx]
1017 if field_info.is_required
1018 && !struct_field_is_decoded(decoded_mask, decoded_fields, field_idx) {
1019 decoder.decode_error('missing required field `${field.name}`')!
1020 }
1021 field_idx++
1022 }
1023 }
1024 } else {
1025 decoder.decode_error('Expected object, but got ${struct_info.value_kind}')!
1026 }
1027 return
1028 } $else $if T.unaliased_typ is bool {
1029 value_info := decoder.current_node.value
1030
1031 if value_info.value_kind != .boolean {
1032 decoder.decode_error('Expected boolean, but got ${value_info.value_kind}')!
1033 }
1034
1035 unsafe {
1036 val = vmemcmp(decoder.json.str + value_info.position, c'true', 'true'.len) == 0
1037 }
1038 } $else $if T.unaliased_typ is $float || T.unaliased_typ is $int {
1039 value_info := decoder.current_node.value
1040
1041 if value_info.value_kind == .number {
1042 unsafe { decoder.decode_number(&val)! }
1043 } else if value_info.value_kind == .string && !decoder.strict {
1044 // In default mode, try to parse quoted strings as numbers
1045 val = decoder.decode_number_from_string[T]()!
1046 } else {
1047 decoder.decode_error('Expected number, but got ${value_info.value_kind}')!
1048 }
1049 } $else $if T.unaliased_typ is $enum {
1050 decoder.decode_enum(mut val)!
1051 } $else {
1052 decoder.decode_error('cannot decode value with ${typeof(val).name} type')!
1053 }
1054
1055 if decoder.current_node != unsafe { nil } {
1056 decoder.current_node = decoder.current_node.next
1057 }
1058 } // $else (not voidptr / interface)
1059}
1060
1061fn (mut decoder Decoder) decode_string[T](mut val T) ! {
1062 _ = val
1063 string_info := decoder.current_node.value
1064
1065 if string_info.value_kind == .string {
1066 string_start := string_info.position + 1
1067 string_end := string_info.position + string_info.length - 1
1068 string_body := decoder.json[string_start..string_end]
1069 if string_body.index_u8(`\\`) == -1 {
1070 val = string_body
1071 return
1072 }
1073
1074 mut string_buffer := []u8{cap: string_info.length} // might be too long but most json strings don't contain many escape characters anyways
1075
1076 mut buffer_index := 1
1077 mut string_index := 1
1078
1079 for string_index < string_info.length - 1 {
1080 current_byte := decoder.json[string_info.position + string_index]
1081
1082 if current_byte == `\\` {
1083 // push all characters up to this point
1084 unsafe {
1085 string_buffer.push_many(decoder.json.str + string_info.position + buffer_index,
1086 string_index - buffer_index)
1087 }
1088
1089 string_index++
1090
1091 escaped_char := decoder.json[string_info.position + string_index]
1092
1093 string_index++
1094
1095 match escaped_char {
1096 `/`, `"`, `\\` {
1097 string_buffer << escaped_char
1098 }
1099 `b` {
1100 string_buffer << `\b`
1101 }
1102 `f` {
1103 string_buffer << `\f`
1104 }
1105 `n` {
1106 string_buffer << `\n`
1107 }
1108 `r` {
1109 string_buffer << `\r`
1110 }
1111 `t` {
1112 string_buffer << `\t`
1113 }
1114 `u` {
1115 unicode_point := rune(strconv.parse_uint(decoder.json[
1116 string_info.position + string_index..string_info.position +
1117 string_index + 4], 16, 32)!)
1118
1119 string_index += 4
1120
1121 if unicode_point < 0xD800 || unicode_point > 0xDFFF { // normal utf-8
1122 string_buffer << unicode_point.bytes()
1123 } else if unicode_point >= 0xDC00 { // trail surrogate -> invalid
1124 decoder.decode_error('Got trail surrogate: ${u32(unicode_point):04X} before head surrogate.')!
1125 } else { // head surrogate -> treat as utf-16
1126 if string_index > string_info.length - 6 {
1127 decoder.decode_error('Expected a trail surrogate after a head surrogate, but got no valid escape sequence.')!
1128 }
1129 if decoder.json[string_info.position + string_index..
1130 string_info.position + string_index + 2] != '\\u' {
1131 decoder.decode_error('Expected a trail surrogate after a head surrogate, but got no valid escape sequence.')!
1132 }
1133
1134 string_index += 2
1135
1136 unicode_point2 := rune(strconv.parse_uint(decoder.json[
1137 string_info.position + string_index..string_info.position +
1138 string_index + 4], 16, 32)!)
1139
1140 string_index += 4
1141
1142 if unicode_point2 < 0xDC00 {
1143 decoder.decode_error('Expected a trail surrogate after a head surrogate, but got ${u32(unicode_point):04X}.')!
1144 }
1145
1146 final_unicode_point := (unicode_point2 & 0x3FF) +
1147 ((unicode_point & 0x3FF) << 10) + 0x10000
1148 string_buffer << final_unicode_point.bytes()
1149 }
1150 }
1151 else {} // has already been checked
1152 }
1153
1154 buffer_index = string_index
1155 } else {
1156 string_index++
1157 }
1158 }
1159
1160 // push the rest
1161 unsafe {
1162 string_buffer.push_many(decoder.json.str + string_info.position + buffer_index,
1163 string_index - buffer_index)
1164 }
1165
1166 val = string_buffer.bytestr()
1167 } else {
1168 decoder.decode_error('Expected string, but got ${string_info.value_kind}')!
1169 }
1170}
1171
1172fn (mut decoder Decoder) decode_array[T](mut val []T) ! {
1173 $if T is $interface {
1174 decoder.skip_current_value()
1175 return
1176 } $else $if T.unaliased_typ is voidptr {
1177 decoder.skip_current_value()
1178 return
1179 } $else {
1180 array_info := decoder.current_node.value
1181
1182 if array_info.value_kind == .array {
1183 decoder.current_node = decoder.current_node.next
1184
1185 array_position := array_info.position
1186 array_end := array_position + array_info.length
1187
1188 for {
1189 if decoder.current_node == unsafe { nil }
1190 || decoder.current_node.value.position >= array_end {
1191 break
1192 }
1193
1194 mut array_element := T{}
1195
1196 $if T.indirections == 1 {
1197 if decoder.current_node.value.value_kind == .null {
1198 if decoder.current_node != unsafe { nil } {
1199 decoder.current_node = decoder.current_node.next
1200 }
1201 } else {
1202 mut decoded_ptr := create_decoded_ptr(array_element)
1203 decoder.decode_value(mut decoded_ptr)!
1204 array_element = decoded_ptr
1205 }
1206 } $else {
1207 decoder.decode_value(mut array_element)!
1208 }
1209
1210 val << array_element
1211 }
1212 } else {
1213 decoder.decode_error('Expected array, but got ${array_info.value_kind}')!
1214 }
1215 }
1216}
1217
1218fn (mut decoder Decoder) decode_map[V](mut val map[string]V) ! {
1219 $if V is $interface {
1220 decoder.skip_current_value()
1221 return
1222 } $else $if V.unaliased_typ is voidptr {
1223 decoder.skip_current_value()
1224 return
1225 } $else {
1226 map_info := decoder.current_node.value
1227
1228 if map_info.value_kind == .object {
1229 map_position := map_info.position
1230 map_end := map_position + map_info.length
1231
1232 decoder.current_node = decoder.current_node.next
1233 for {
1234 if decoder.current_node == unsafe { nil }
1235 || decoder.current_node.value.position >= map_end {
1236 break
1237 }
1238
1239 key_info := decoder.current_node.value
1240
1241 if key_info.position >= map_end {
1242 break
1243 }
1244
1245 key_str := decoder.json[key_info.position + 1..key_info.position + key_info.length -
1246 1]
1247
1248 decoder.current_node = decoder.current_node.next
1249
1250 value_info := decoder.current_node.value
1251
1252 if value_info.position + value_info.length > map_end {
1253 break
1254 }
1255
1256 mut map_value := V{}
1257
1258 $if V.indirections == 1 {
1259 if decoder.current_node.value.value_kind == .null {
1260 if decoder.current_node != unsafe { nil } {
1261 decoder.current_node = decoder.current_node.next
1262 }
1263 } else {
1264 mut decoded_ptr := create_decoded_ptr(map_value)
1265 decoder.decode_value(mut decoded_ptr)!
1266 map_value = decoded_ptr
1267 }
1268 } $else {
1269 decoder.decode_value(mut map_value)!
1270 }
1271
1272 $if V is $alias && V.unaliased_typ is $map {
1273 // V is a map alias (e.g. `type SyntaxStyle = map[string]X`).
1274 // V's checker reports `val[key]` as the unaliased element type
1275 // while `map_value` keeps the alias type, so direct assignment
1276 // fails to type-check. Skip to keep generic instantiations
1277 // compilable; decoding into map-alias map values is unsupported.
1278 } $else $if K is string {
1279 $if V is $map {
1280 val[key_str] = map_value.move()
1281 } $else {
1282 val[key_str] = map_value
1283 }
1284 } $else $if K is rune {
1285 $if V is $map {
1286 val[rune(key_str.int())] = map_value.move()
1287 } $else {
1288 val[rune(key_str.int())] = map_value
1289 }
1290 } $else $if K is $int {
1291 $if V is $map {
1292 val[K(key_str.int())] = map_value.move()
1293 } $else {
1294 val[K(key_str.int())] = map_value
1295 }
1296 } $else {
1297 $if V is $map {
1298 val[key_str] = map_value.move()
1299 } $else {
1300 val[key_str] = map_value
1301 }
1302 }
1303 }
1304 } else {
1305 decoder.decode_error('Expected object, but got ${map_info.value_kind}')!
1306 }
1307 }
1308}
1309
1310fn create_value_from_optional[T](_val ?T) ?T {
1311 return T{}
1312}
1313
1314fn (mut decoder Decoder) decode_enum[T](mut val T) ! {
1315 enum_info := decoder.current_node.value
1316
1317 if enum_info.value_kind == .number {
1318 mut result := 0
1319 unsafe { decoder.decode_number(&result)! }
1320
1321 $for value in T.values {
1322 if int(value.value) == result {
1323 val = value.value
1324 return
1325 }
1326 }
1327 decoder.decode_error('Number value: `${result}` does not match any field in enum: ${typeof(val).name}')!
1328 } else if enum_info.value_kind == .string {
1329 mut result := ''
1330 decoder.decode_string(mut result)!
1331
1332 $for value in T.values {
1333 for attr in value.attrs {
1334 if json_attr := json_attr_value(attr) {
1335 if json_attr == result {
1336 val = value.value
1337 return
1338 }
1339 }
1340 }
1341 if value.name == result {
1342 val = value.value
1343 return
1344 }
1345 }
1346 decoder.decode_error('String value: `${result}` does not match any field in enum: ${typeof(val).name}')!
1347 }
1348
1349 decoder.decode_error('Expected number or string value for enum, got: ${enum_info.value_kind}')!
1350}
1351
1352const max_integer_number_digits = 20
1353
1354@[markused]
1355fn has_exponent_number_syntax(str string) bool {
1356 for c in str {
1357 if c == `e` || c == `E` {
1358 return true
1359 }
1360 }
1361 return false
1362}
1363
1364@[markused]
1365fn scientific_number_to_integer_string(str string) !string {
1366 if !has_exponent_number_syntax(str) {
1367 // Handle plain decimal numbers with zero fractional part (e.g., "-123.0")
1368 dot_pos := str.index_u8(`.`)
1369 if dot_pos >= 0 {
1370 frac := str[dot_pos + 1..]
1371 mut all_zeros := frac.len > 0
1372 for c in frac {
1373 if c != `0` {
1374 all_zeros = false
1375 break
1376 }
1377 }
1378 if all_zeros {
1379 result := str[..dot_pos]
1380 if result.len == 0 || result == '-' || result == '+' {
1381 return '0'
1382 }
1383 return result
1384 }
1385 }
1386 return str
1387 }
1388 if str.len == 0 {
1389 return error('invalid scientific notation number')
1390 }
1391 mut i := 0
1392 mut is_negative := false
1393 if str[i] == `+` || str[i] == `-` {
1394 is_negative = str[i] == `-`
1395 i++
1396 }
1397 if i >= str.len {
1398 return error('invalid scientific notation number')
1399 }
1400 mut digits := []u8{cap: str.len}
1401 mut fractional_digits := 0
1402 mut seen_digit := false
1403 mut seen_dot := false
1404 for i < str.len {
1405 c := str[i]
1406 if c >= `0` && c <= `9` {
1407 digits << c
1408 seen_digit = true
1409 if seen_dot {
1410 fractional_digits++
1411 }
1412 i++
1413 continue
1414 }
1415 if c == `.` && !seen_dot {
1416 seen_dot = true
1417 i++
1418 continue
1419 }
1420 break
1421 }
1422 if !seen_digit || i >= str.len || (str[i] != `e` && str[i] != `E`) {
1423 return error('invalid scientific notation number')
1424 }
1425 i++
1426 mut exponent_sign := 1
1427 if i < str.len && (str[i] == `+` || str[i] == `-`) {
1428 if str[i] == `-` {
1429 exponent_sign = -1
1430 }
1431 i++
1432 }
1433 if i >= str.len || str[i] < `0` || str[i] > `9` {
1434 return error('invalid scientific notation number')
1435 }
1436 mut exponent := 0
1437 exponent_cap := max_integer_number_digits + fractional_digits + 1
1438 for i < str.len && str[i] >= `0` && str[i] <= `9` {
1439 if exponent < exponent_cap {
1440 exponent = (exponent * 10) + int(str[i] - `0`)
1441 }
1442 i++
1443 }
1444 if i != str.len {
1445 return error('invalid scientific notation number')
1446 }
1447 if exponent_sign == -1 {
1448 exponent = -exponent
1449 }
1450 mut first_non_zero := 0
1451 for first_non_zero < digits.len && digits[first_non_zero] == `0` {
1452 first_non_zero++
1453 }
1454 if first_non_zero == digits.len {
1455 return '0'
1456 }
1457 digits = digits[first_non_zero..].clone()
1458 scale := exponent - fractional_digits
1459 if scale < 0 {
1460 truncated_digits := -scale
1461 if truncated_digits >= digits.len {
1462 return '0'
1463 }
1464 digits = digits[..digits.len - truncated_digits].clone()
1465 } else if scale > 0 {
1466 final_len := digits.len + scale
1467 if final_len > max_integer_number_digits {
1468 return error('number `${str}` exceeds 64-bit integer range')
1469 }
1470 mut out := []u8{cap: final_len + if is_negative { 1 } else { 0 }}
1471 if is_negative {
1472 out << `-`
1473 }
1474 out << digits
1475 for _ in 0 .. scale {
1476 out << `0`
1477 }
1478 return out.bytestr()
1479 }
1480 if digits.len == 0 {
1481 return '0'
1482 }
1483 mut out := []u8{cap: digits.len + if is_negative { 1 } else { 0 }}
1484 if is_negative {
1485 out << `-`
1486 }
1487 out << digits
1488 return out.bytestr()
1489}
1490
1491fn parse_integer_number[T](str string) !T {
1492 int_str := scientific_number_to_integer_string(str)!
1493 $if T.unaliased_typ is i8 {
1494 return T(strconv.atoi8(int_str)!)
1495 } $else $if T.unaliased_typ is i16 {
1496 return T(strconv.atoi16(int_str)!)
1497 } $else $if T.unaliased_typ is i32 {
1498 return T(strconv.atoi32(int_str)!)
1499 } $else $if T.unaliased_typ is i64 {
1500 return T(strconv.atoi64(int_str)!)
1501 } $else $if T.unaliased_typ is u8 {
1502 return T(strconv.atou8(int_str)!)
1503 } $else $if T.unaliased_typ is u16 {
1504 return T(strconv.atou16(int_str)!)
1505 } $else $if T.unaliased_typ is u32 {
1506 return T(strconv.atou32(int_str)!)
1507 } $else $if T.unaliased_typ is u64 {
1508 return T(strconv.atou64(int_str)!)
1509 } $else $if T is int {
1510 return int(strconv.atoi64(int_str)!)
1511 } $else $if T.unaliased_typ is int {
1512 return T(int(strconv.atoi64(int_str)!))
1513 } $else $if T.unaliased_typ is isize {
1514 return T(isize(strconv.atoi64(int_str)!))
1515 } $else $if T.unaliased_typ is usize {
1516 return T(usize(strconv.atou64(int_str)!))
1517 } $else {
1518 return error('`parse_integer_number` cannot decode ${T.name} type')
1519 }
1520}
1521
1522@[markused]
1523fn parse_int_number(str string) !int {
1524 int_str := scientific_number_to_integer_string(str)!
1525 return int(strconv.atoi64(int_str)!)
1526}
1527
1528fn parse_float_number[T](str string) !T {
1529 $if js {
1530 $if T.unaliased_typ is f32 {
1531 return T(f32(strconv.atof64(str)!))
1532 } $else $if T.unaliased_typ is f64 {
1533 return T(strconv.atof64(str)!)
1534 } $else {
1535 return error('`parse_float_number` cannot decode ${T.name} type')
1536 }
1537 } $else {
1538 $if T.unaliased_typ is f32 {
1539 return T(f32(strconv.atof64(str, allow_extra_chars: false)!))
1540 } $else $if T.unaliased_typ is f64 {
1541 return T(strconv.atof64(str, allow_extra_chars: false)!)
1542 } $else {
1543 return error('`parse_float_number` cannot decode ${T.name} type')
1544 }
1545 }
1546}
1547
1548// use pointer instead of mut so enum cast works
1549@[unsafe]
1550fn (mut decoder Decoder) decode_number[T](val &T) ! {
1551 _ = val
1552 number_info := decoder.current_node.value
1553 str := decoder.json[number_info.position..number_info.position + number_info.length]
1554 $match T.unaliased_typ {
1555 i8 { *val = parse_integer_number[T](str)! }
1556 i16 { *val = parse_integer_number[T](str)! }
1557 i32 { *val = parse_integer_number[T](str)! }
1558 i64 { *val = parse_integer_number[T](str)! }
1559 u8 { *val = parse_integer_number[T](str)! }
1560 u16 { *val = parse_integer_number[T](str)! }
1561 u32 { *val = parse_integer_number[T](str)! }
1562 u64 { *val = parse_integer_number[T](str)! }
1563 int { *val = parse_int_number(str)! }
1564 isize { *val = parse_integer_number[T](str)! }
1565 usize { *val = parse_integer_number[T](str)! }
1566 f32 { *val = parse_float_number[T](str)! }
1567 f64 { *val = parse_float_number[T](str)! }
1568 $else { return error('`decode_number` can not decode ${T.name} type') }
1569 }
1570}
1571
1572// decode_number_from_string parses a number from a JSON string value (default mode).
1573// This extracts the content between quotes and parses it as a number.
1574fn (mut decoder Decoder) decode_number_from_string[T]() !T {
1575 string_info := decoder.current_node.value
1576 // Extract string content without quotes (position+1 to skip opening quote, length-2 to exclude both quotes)
1577 if string_info.length < 2 {
1578 return error('invalid string for number conversion')
1579 }
1580 str := decoder.json[string_info.position + 1..string_info.position + string_info.length - 1]
1581 $if T.unaliased_typ is i8 {
1582 return parse_integer_number[T](str)!
1583 } $else $if T.unaliased_typ is i16 {
1584 return parse_integer_number[T](str)!
1585 } $else $if T.unaliased_typ is i32 {
1586 return parse_integer_number[T](str)!
1587 } $else $if T.unaliased_typ is i64 {
1588 return parse_integer_number[T](str)!
1589 } $else $if T.unaliased_typ is u8 {
1590 return parse_integer_number[T](str)!
1591 } $else $if T.unaliased_typ is u16 {
1592 return parse_integer_number[T](str)!
1593 } $else $if T.unaliased_typ is u32 {
1594 return parse_integer_number[T](str)!
1595 } $else $if T.unaliased_typ is u64 {
1596 return parse_integer_number[T](str)!
1597 } $else $if T is int {
1598 return parse_int_number(str)!
1599 } $else $if T.unaliased_typ is int {
1600 return parse_integer_number[T](str)!
1601 } $else $if T.unaliased_typ is isize {
1602 return parse_integer_number[T](str)!
1603 } $else $if T.unaliased_typ is usize {
1604 return parse_integer_number[T](str)!
1605 } $else $if T.unaliased_typ is f32 {
1606 return parse_float_number[T](str)!
1607 } $else $if T.unaliased_typ is f64 {
1608 return parse_float_number[T](str)!
1609 } $else {
1610 return error('`decode_number_from_string` cannot decode ${T.name} type')
1611 }
1612}
1613