vxx2 / vlib / x / json2 / encode.v
916 lines · 842 sloc · 22.97 KB · 27ea3955e8b2a3813338a8788c00fff9db28dfbc
Raw
1module json2
2
3import time
4
5// EncoderOptions provides a list of options for encoding
6@[params]
7pub struct EncoderOptions {
8pub:
9 prettify bool
10 indent_string string = ' '
11 newline_string string = '\n'
12
13 enum_as_int bool
14
15 escape_unicode bool
16}
17
18struct Encoder {
19 EncoderOptions
20mut:
21 level int
22 prefix string
23
24 output []u8 = []u8{cap: 2048}
25}
26
27// encode is a generic function that encodes a type into a JSON string.
28pub fn encode[T](val T, config EncoderOptions) string {
29 mut encoder := Encoder{
30 EncoderOptions: config
31 }
32
33 encoder.encode_value[T](val)
34
35 return encoder.output.bytestr()
36}
37
38fn (mut encoder Encoder) encode_value[T](val T) {
39 $if T is $interface {
40 encoder.encode_null()
41 } $else $if T.unaliased_typ is voidptr {
42 encoder.encode_null()
43 } $else $if T.unaliased_typ is string {
44 encoder.encode_string(string(val))
45 } $else $if T.unaliased_typ is bool {
46 encoder.encode_boolean(bool(val))
47 } $else $if T.unaliased_typ is u8 {
48 encoder.encode_number(u8(val))
49 } $else $if T.unaliased_typ is u16 {
50 encoder.encode_number(u16(val))
51 } $else $if T.unaliased_typ is u32 {
52 encoder.encode_number(u32(val))
53 } $else $if T.unaliased_typ is u64 {
54 encoder.encode_number(u64(val))
55 } $else $if T.unaliased_typ is i8 {
56 encoder.encode_number(i8(val))
57 } $else $if T.unaliased_typ is i16 {
58 encoder.encode_number(i16(val))
59 } $else $if T.unaliased_typ is int || T.unaliased_typ is i32 {
60 encoder.encode_number(i32(val))
61 } $else $if T.unaliased_typ is i64 {
62 encoder.encode_number(i64(val))
63 } $else $if T.unaliased_typ is usize {
64 encoder.encode_number(usize(val))
65 } $else $if T.unaliased_typ is isize {
66 encoder.encode_number(isize(val))
67 } $else $if T.unaliased_typ is f32 {
68 encoder.encode_number(f32(val))
69 } $else $if T.unaliased_typ is f64 {
70 encoder.encode_number(f64(val))
71 } $else $if T.unaliased_typ is voidptr {
72 encoder.encode_number(0)
73 } $else $if T is $pointer {
74 if voidptr(val) == unsafe { nil } {
75 encoder.encode_null()
76 } else {
77 encoder.encode_value(*val)
78 }
79 } $else $if T.unaliased_typ is $array_fixed {
80 encoder.output << `[`
81 for i in 0 .. val.len {
82 encoder.encode_value(val[i])
83 if i < val.len - 1 {
84 encoder.output << `,`
85 }
86 }
87 encoder.output << `]`
88 } $else $if T.unaliased_typ is $array {
89 encoder.encode_array(val)
90 } $else $if T.unaliased_typ is $map {
91 encoder.output << `{`
92 if encoder.prettify {
93 encoder.increment_level()
94 encoder.add_indent()
95 }
96 mut mi := 0
97 for key, value in val {
98 encoder.encode_string('${key}')
99 encoder.output << `:`
100 if encoder.prettify {
101 encoder.output << ` `
102 }
103 encoder.encode_value(value)
104 if mi < val.len - 1 {
105 encoder.output << `,`
106 if encoder.prettify {
107 encoder.add_indent()
108 }
109 } else {
110 if encoder.prettify {
111 encoder.decrement_level()
112 encoder.add_indent()
113 }
114 }
115 mi++
116 }
117 encoder.output << `}`
118 } $else $if T.unaliased_typ is $enum {
119 if encoder.enum_as_int || enum_uses_json_as_number[T]() {
120 encoder.encode_number(int(val))
121 } else {
122 mut enum_val := 'unknown enum value'
123 $for member in T.values {
124 if member.value == val {
125 enum_val = member.name
126 for attr in member.attrs {
127 if json_attr := json_attr_value(attr) {
128 enum_val = json_attr
129 }
130 }
131 }
132 }
133 encoder.output << `"`
134 unsafe { encoder.output.push_many(enum_val.str, enum_val.len) }
135 encoder.output << `"`
136 }
137 } $else $if T.unaliased_typ is $sumtype {
138 encoder.encode_sumtype[T](val)
139 } $else $if T is JsonEncoder { // uses T, because alias could be implementing JsonEncoder, while the base type does not
140 integer_val := val.to_json()
141 unsafe { encoder.output.push_many(integer_val.str, integer_val.len) }
142 } $else $if T is Encodable { // uses T, because alias could be implementing JsonEncoder, while the base type does not
143 integer_val := val.json_str()
144 unsafe { encoder.output.push_many(integer_val.str, integer_val.len) }
145 } $else $if T.unaliased_typ is $struct {
146 unsafe {
147 $for field in T.fields {
148 $if field.is_embed {
149 encoder.encode_struct_with_embeds(val)
150 return
151 }
152 }
153 encoder.output << `{`
154 is_first := encoder.encode_struct_fields[T](val, true, [], '')
155 if encoder.prettify && !is_first {
156 encoder.decrement_level()
157 encoder.add_indent()
158 }
159 encoder.output << `}`
160 }
161 }
162}
163
164fn (mut encoder Encoder) encode_string(val string) {
165 encoder.output << `"`
166 mut buffer_start := 0
167 mut buffer_end := 0
168 for buffer_end < val.len {
169 character := val[buffer_end]
170 match character {
171 `"`, `\\` {
172 unsafe { encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start) }
173 buffer_end++
174 buffer_start = buffer_end
175
176 encoder.output << `\\`
177 encoder.output << character
178 }
179 `\b` {
180 unsafe { encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start) }
181 buffer_end++
182 buffer_start = buffer_end
183
184 encoder.output << `\\`
185 encoder.output << `b`
186 }
187 `\n` {
188 unsafe { encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start) }
189 buffer_end++
190 buffer_start = buffer_end
191
192 encoder.output << `\\`
193 encoder.output << `n`
194 }
195 `\f` {
196 unsafe { encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start) }
197 buffer_end++
198 buffer_start = buffer_end
199
200 encoder.output << `\\`
201 encoder.output << `f`
202 }
203 `\t` {
204 unsafe { encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start) }
205 buffer_end++
206 buffer_start = buffer_end
207
208 encoder.output << `\\`
209 encoder.output << `t`
210 }
211 `\r` {
212 unsafe { encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start) }
213 buffer_end++
214 buffer_start = buffer_end
215
216 encoder.output << `\\`
217 encoder.output << `r`
218 }
219 else {
220 if character < 0x20 { // control characters
221 unsafe {
222 encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start)
223 }
224 buffer_end++
225 buffer_start = buffer_end
226
227 encoder.output << `\\`
228 encoder.output << `u`
229
230 hex_string := '${character:04x}'
231
232 unsafe { encoder.output.push_many(hex_string.str, 4) }
233
234 continue
235 }
236 if encoder.escape_unicode {
237 if character >= 0b1111_0000 { // four bytes
238 unsafe {
239 encoder.output.push_many(val.str + buffer_start,
240 buffer_end - buffer_start)
241 }
242 unicode_point_low := val[buffer_end..buffer_end + 4].bytes().byterune() or {
243 0
244 } - 0x10000
245
246 hex_string := '\\u${0xD800 + ((unicode_point_low >> 10) & 0x3FF):04X}\\u${
247 0xDC00 + (unicode_point_low & 0x3FF):04x}'
248
249 buffer_end += 4
250 buffer_start = buffer_end
251
252 unsafe { encoder.output.push_many(hex_string.str, 12) }
253
254 continue
255 } else if character >= 0b1110_0000 { // three bytes
256 unsafe {
257 encoder.output.push_many(val.str + buffer_start,
258 buffer_end - buffer_start)
259 }
260 hex_string := '\\u${val[buffer_end..buffer_end + 3].bytes().byterune() or {
261 0
262 }:04x}'
263
264 buffer_end += 3
265 buffer_start = buffer_end
266
267 unsafe { encoder.output.push_many(hex_string.str, 6) }
268
269 continue
270 } else if character >= 0b1100_0000 { // two bytes
271 unsafe {
272 encoder.output.push_many(val.str + buffer_start,
273 buffer_end - buffer_start)
274 }
275 hex_string := '\\u${val[buffer_end..buffer_end + 2].bytes().byterune() or {
276 0
277 }:04x}'
278
279 buffer_end += 2
280 buffer_start = buffer_end
281
282 unsafe { encoder.output.push_many(hex_string.str, 6) }
283
284 continue
285 }
286 }
287
288 buffer_end++
289 }
290 }
291 }
292 unsafe { encoder.output.push_many(val.str + buffer_start, buffer_end - buffer_start) }
293
294 encoder.output << `"`
295}
296
297fn (mut encoder Encoder) encode_boolean(val bool) {
298 if val {
299 unsafe { encoder.output.push_many(true_string.str, true_string.len) }
300 } else {
301 unsafe { encoder.output.push_many(false_string.str, false_string.len) }
302 }
303}
304
305fn (mut encoder Encoder) encode_number[T](val T) {
306 mut integer_val := ''
307 $if T is u8 {
308 integer_val = u8(val).str()
309 } $else $if T is u16 {
310 integer_val = u16(val).str()
311 } $else $if T is u32 {
312 integer_val = u32(val).str()
313 } $else $if T is u64 {
314 integer_val = u64(val).str()
315 } $else $if T is i8 {
316 integer_val = i8(val).str()
317 } $else $if T is i16 {
318 integer_val = i16(val).str()
319 } $else $if T is int || T is i32 {
320 integer_val = i32(val).str()
321 } $else $if T is i64 {
322 integer_val = i64(val).str()
323 } $else $if T is usize {
324 integer_val = usize(val).str()
325 } $else $if T is isize {
326 integer_val = isize(val).str()
327 } $else $if T is f32 {
328 integer_val = f32(val).str()
329 } $else $if T is f64 {
330 integer_val = f64(val).str()
331 }
332 $if T is $float {
333 if integer_val.len > 2 && integer_val[integer_val.len - 2] == `.`
334 && integer_val[integer_val.len - 1] == `0` { // ends in .0
335 // `2.0` = > `2`
336 // but skip float in scientific notation, `1e+10`
337 unsafe {
338 integer_val.len -= 2
339 }
340 }
341 }
342 unsafe { encoder.output.push_many(integer_val.str, integer_val.len) }
343}
344
345@[markused]
346fn (mut encoder Encoder) encode_null() {
347 unsafe { encoder.output.push_many(null_string.str, null_string.len) }
348}
349
350fn (mut encoder Encoder) encode_array[T](val T) {
351 encoder.output << `[`
352 if encoder.prettify {
353 encoder.increment_level()
354 encoder.add_indent()
355 }
356
357 for i, item in val {
358 $if T is $pointer {
359 if voidptr(item) == unsafe { nil } {
360 encoder.encode_null()
361 } else {
362 unsafe { encoder.encode_pointer_array_item(item) }
363 }
364 } $else {
365 encoder.encode_value(item)
366 }
367 if i < val.len - 1 {
368 encoder.output << `,`
369 if encoder.prettify {
370 encoder.add_indent()
371 }
372 } else {
373 if encoder.prettify {
374 encoder.decrement_level()
375 encoder.add_indent()
376 }
377 }
378 }
379
380 encoder.output << `]`
381}
382
383@[unsafe]
384fn (mut encoder Encoder) encode_pointer_array_item[T](item T) {
385 encoder.encode_value(*item)
386}
387
388fn (mut encoder Encoder) encode_map[K, T](val map[K]T) {
389 encoder.output << `{`
390 if encoder.prettify {
391 encoder.increment_level()
392 encoder.add_indent()
393 }
394
395 mut i := 0
396 for key, value in val {
397 encoder.encode_string('${key}')
398 encoder.output << `:`
399 if encoder.prettify {
400 encoder.output << ` `
401 }
402 encoder.encode_value[T](value)
403 if i < val.len - 1 {
404 encoder.output << `,`
405 if encoder.prettify {
406 encoder.add_indent()
407 }
408 } else {
409 if encoder.prettify {
410 encoder.decrement_level()
411 encoder.add_indent()
412 }
413 }
414
415 i++
416 }
417
418 encoder.output << `}`
419}
420
421fn (mut encoder Encoder) encode_enum[T](val T) {
422 if encoder.enum_as_int || enum_uses_json_as_number[T]() {
423 encoder.encode_number(int(val))
424 } else {
425 mut enum_val := 'unknown enum value'
426 $for member in T.values {
427 if member.value == val {
428 enum_val = member.name
429 for attr in member.attrs {
430 if json_attr := json_attr_value(attr) {
431 enum_val = json_attr
432 }
433 }
434 }
435 }
436 encoder.output << `"`
437 unsafe { encoder.output.push_many(enum_val.str, enum_val.len) }
438 encoder.output << `"`
439 }
440}
441
442fn (mut encoder Encoder) encode_sumtype[T](val T) {
443 $if T is $pointer {
444 // Pointer types are handled by encode_value's $pointer branch;
445 // this instantiation is generated but never called.
446 } $else {
447 $for variant in T.variants {
448 if val is variant {
449 variant_name := sumtype_variant_name(typeof(variant.typ).name)
450 $if variant.typ is time.Time {
451 if T.name in ['x.json2.Any', 'json2.Any', 'Any'] {
452 variant_value := val
453 encoder.encode_value(variant_value)
454 } else {
455 encoder.encode_sumtype_time_variant(val, variant_name)
456 }
457 } $else $if variant.typ is $struct {
458 if T.name in ['x.json2.Any', 'json2.Any', 'Any'] {
459 variant_value := val
460 encoder.encode_value(variant_value)
461 } else {
462 encoder.encode_sumtype_struct_variant(val, variant_name)
463 }
464 } $else $if variant.typ is $map {
465 encoder.encode_value(val)
466 } $else $if variant.typ is $array_dynamic {
467 if T.name in ['x.json2.Any', 'json2.Any', 'Any'] {
468 variant_value := val
469 encoder.encode_value(variant_value)
470 } else {
471 variant_value := val
472 encoder.encode_array_of_sumtype_variants(variant_value)
473 }
474 } $else {
475 variant_value := val
476 encoder.encode_value(variant_value)
477 }
478 }
479 }
480 }
481}
482
483fn (mut encoder Encoder) encode_object_key(is_first bool, key string) bool {
484 if is_first {
485 if encoder.prettify {
486 encoder.increment_level()
487 }
488 } else {
489 encoder.output << `,`
490 }
491 if encoder.prettify {
492 encoder.add_indent()
493 }
494 encoder.encode_string(key)
495 encoder.output << `:`
496 if encoder.prettify {
497 encoder.output << ` `
498 }
499 return false
500}
501
502fn (mut encoder Encoder) encode_sumtype_struct_variant[T](val T, variant_name string) {
503 $for field in T.fields {
504 $if field.is_embed {
505 unsafe { encoder.encode_sumtype_struct_variant_with_embeds(val, variant_name) }
506 return
507 }
508 }
509 encoder.output << `{`
510 mut is_first := unsafe { encoder.encode_struct_fields[T](val, true, [], '') }
511 is_first = encoder.encode_object_key(is_first, '_type')
512 encoder.encode_string(variant_name)
513 if encoder.prettify && !is_first {
514 encoder.decrement_level()
515 encoder.add_indent()
516 }
517 encoder.output << `}`
518}
519
520fn (mut encoder Encoder) encode_array_of_sumtype_variants[T](val []T) {
521 encoder.output << `[`
522 if encoder.prettify {
523 encoder.increment_level()
524 encoder.add_indent()
525 }
526 for i, item in val {
527 $if T is time.Time {
528 encoder.encode_value(item)
529 } $else $if T is JsonEncoder {
530 encoder.encode_value(item)
531 } $else $if T is Encodable {
532 encoder.encode_value(item)
533 } $else $if T is $struct {
534 elem_name := sumtype_variant_name(T.name)
535 encoder.encode_sumtype_struct_variant(item, elem_name)
536 } $else {
537 encoder.encode_value(item)
538 }
539 if i < val.len - 1 {
540 encoder.output << `,`
541 if encoder.prettify {
542 encoder.add_indent()
543 }
544 } else {
545 if encoder.prettify {
546 encoder.decrement_level()
547 encoder.add_indent()
548 }
549 }
550 }
551 encoder.output << `]`
552}
553
554@[markused]
555fn (mut encoder Encoder) encode_sumtype_time_variant(val time.Time, variant_name string) {
556 encoder.output << `{`
557 mut is_first := true
558 is_first = encoder.encode_object_key(is_first, '_type')
559 encoder.encode_string(variant_name)
560 is_first = encoder.encode_object_key(is_first, 'value')
561 encoder.encode_number(val.unix())
562 if encoder.prettify && !is_first {
563 encoder.decrement_level()
564 encoder.add_indent()
565 }
566 encoder.output << `}`
567}
568
569struct EncoderFieldInfo {
570 key_name string
571
572 is_skip bool
573 is_omitempty bool
574 is_required bool
575 is_json_null bool
576}
577
578fn get_value_from_optional[T](val ?T) T {
579 return val or { T{} }
580}
581
582fn check_not_empty[T](val T) ?bool {
583 $if val is ?string {
584 opt := ?string(val)
585 if sval := opt {
586 return sval != ''
587 }
588 return false
589 } $else $if val is ?int {
590 opt := ?int(val)
591 if ival := opt {
592 return ival != 0
593 }
594 return false
595 } $else $if val is ?f64 {
596 opt := ?f64(val)
597 if fval := opt {
598 return fval != 0.0
599 }
600 return false
601 } $else $if val is ?f32 {
602 opt := ?f32(val)
603 if fval := opt {
604 return fval != 0.0
605 }
606 return false
607 } $else $if T is $option {
608 return !struct_field_is_none(val)
609 } $else $if T.indirections != 0 {
610 return val != unsafe { nil }
611 } $else $if T.unaliased_typ is string {
612 if val == '' {
613 return false
614 }
615 } $else $if T.unaliased_typ is $int || T.unaliased_typ is $float {
616 if val == 0 {
617 return false
618 }
619 } $else $if T.unaliased_typ is $array || T.unaliased_typ is $map {
620 return val.len != 0
621 }
622 return true
623}
624
625// TODO: fix compilation with -autofree, and remove the tag @[manualfree] here:
626@[manualfree; unsafe]
627fn (mut encoder Encoder) cached_field_infos[T]() []EncoderFieldInfo {
628 static field_infos := &[]EncoderFieldInfo(nil)
629 if field_infos == nil {
630 field_infos = &[]EncoderFieldInfo{}
631 $for field in T.fields {
632 mut is_skip := false
633 mut key_name := ''
634 mut is_omitempty := false
635 mut is_required := false
636 mut is_json_null := false
637 for attr in field.attrs {
638 match attr {
639 'skip' {
640 is_skip = true
641 break
642 }
643 'omitempty' {
644 is_omitempty = true
645 }
646 'required' {
647 is_required = true
648 }
649 'json_null' {
650 is_json_null = true
651 }
652 else {}
653 }
654
655 if attr.starts_with('json:') {
656 json_attr := json_attr_value(attr) or { continue }
657 if json_attr == '-' {
658 is_skip = true
659 break
660 }
661 key_name = json_attr
662 }
663 }
664 field_infos << EncoderFieldInfo{
665 key_name: if key_name == '' { field.name } else { key_name }
666 is_skip: is_skip
667 is_omitempty: is_omitempty
668 is_required: is_required
669 is_json_null: is_json_null
670 }
671 }
672 }
673 return *field_infos
674}
675
676fn (mut encoder Encoder) encode_struct_field_value[T](val T) {
677 $if T is $interface {
678 encoder.encode_null()
679 } $else $if T.unaliased_typ is voidptr {
680 encoder.encode_null()
681 } $else $if T.pointee_type is $interface {
682 encoder.encode_null()
683 } $else $if T is $option {
684 if val == none {
685 unsafe { encoder.output.push_many(null_string.str, null_string.len) }
686 } else {
687 encoder.encode_value(get_value_from_optional(val))
688 }
689 } $else $if T.indirections == 1 {
690 encoder.encode_value(*val)
691 } $else $if T.indirections == 2 {
692 encoder.encode_value(**val)
693 } $else $if T.indirections == 3 {
694 encoder.encode_value(***val)
695 } $else {
696 encoder.encode_value(val)
697 }
698}
699
700fn struct_field_is_none[T](val T) bool {
701 $if T is $option {
702 return val == none
703 }
704 return false
705}
706
707fn struct_field_is_nil[T](val T) bool {
708 $if T.indirections != 0 {
709 return val == unsafe { nil }
710 }
711 return false
712}
713
714fn struct_field_should_encode[T](field_info EncoderFieldInfo, val T) bool {
715 if field_info.is_skip {
716 return false
717 }
718 if field_info.is_omitempty {
719 if !(check_not_empty(val) or { false }) {
720 return false
721 }
722 }
723 if !field_info.is_required && !field_info.is_json_null && struct_field_is_none(val) {
724 return false
725 }
726 if struct_field_is_nil(val) {
727 return false
728 }
729 return true
730}
731
732@[unsafe]
733fn (mut encoder Encoder) encode_struct_with_embeds[T](val T) {
734 encoder.output << `{`
735 is_first := encoder.encode_embedded_struct_fields[T](val, true, [], [], '')
736 if encoder.prettify && !is_first {
737 encoder.decrement_level()
738 encoder.add_indent()
739 }
740 encoder.output << `}`
741}
742
743@[unsafe]
744fn (mut encoder Encoder) encode_sumtype_struct_variant_with_embeds[T](val T, variant_name string) {
745 encoder.output << `{`
746 mut is_first := encoder.encode_embedded_struct_fields[T](val, true, [], [], '')
747 is_first = encoder.encode_object_key(is_first, '_type')
748 encoder.encode_string(variant_name)
749 if encoder.prettify && !is_first {
750 encoder.decrement_level()
751 encoder.add_indent()
752 }
753 encoder.output << `}`
754}
755
756@[unsafe]
757fn (mut encoder Encoder) encode_struct_fields[T](val T, was_first bool, old_used_keys []string, prefix string) bool {
758 field_infos := encoder.cached_field_infos[T]()
759 mut is_first := was_first
760 mut used_keys := old_used_keys
761 mut i := 0
762
763 $for field in T.fields {
764 $if !field.is_embed {
765 field_info := field_infos[i]
766 mut write_field := true
767
768 $if field.typ is $shared {
769 shared field_value := unsafe { val.$(field.name) }
770 rlock field_value {
771 write_field = struct_field_should_encode(field_info, field_value)
772
773 if write_field {
774 if field_info.key_name in old_used_keys {
775 is_first = encoder.encode_object_key(is_first, prefix +
776 field_info.key_name)
777 } else {
778 is_first = encoder.encode_object_key(is_first, field_info.key_name)
779 used_keys << field_info.key_name
780 }
781 encoder.encode_struct_field_value(field_value)
782 }
783 }
784 } $else {
785 write_field = struct_field_should_encode(field_info, val.$(field.name))
786
787 if write_field {
788 if field_info.key_name in old_used_keys {
789 is_first = encoder.encode_object_key(is_first, prefix + field_info.key_name)
790 } else {
791 is_first = encoder.encode_object_key(is_first, field_info.key_name)
792 used_keys << field_info.key_name
793 }
794 encoder.encode_struct_field_value(val.$(field.name))
795 }
796 }
797 }
798 i++
799 }
800 $for field in T.fields {
801 $if field.is_embed {
802 new_prefix := prefix + field.name + '.'
803 $if field.typ is $shared {
804 shared field_value := unsafe { val.$(field.name) }
805 rlock field_value {
806 is_first = encoder.encode_struct_fields(field_value, is_first, used_keys,
807 new_prefix)
808 }
809 } $else {
810 is_first = encoder.encode_struct_fields(val.$(field.name), is_first, used_keys,
811 new_prefix)
812 }
813 }
814 }
815 return is_first
816}
817
818@[unsafe]
819fn (mut encoder Encoder) encode_embedded_struct_fields[T](val T, was_first bool, old_used_keys []string, reserved_keys []string, prefix string) bool {
820 field_infos := encoder.cached_field_infos[T]()
821 mut is_first := was_first
822 mut used_keys := old_used_keys.clone()
823 mut i := 0
824
825 $for field in T.fields {
826 $if field.is_embed {
827 mut child_reserved_keys := reserved_keys.clone()
828 mut reserved_i := 0
829 $for reserved_field in T.fields {
830 reserved_field_info := field_infos[reserved_i]
831 $if !reserved_field.is_embed {
832 if !reserved_field_info.is_skip {
833 child_reserved_keys << reserved_field_info.key_name
834 }
835 }
836 reserved_i++
837 }
838 new_prefix := prefix + field.name + '.'
839 $if field.typ is $shared {
840 shared field_value := unsafe { val.$(field.name) }
841 rlock field_value {
842 is_first = encoder.encode_embedded_struct_fields(field_value, is_first,
843 used_keys, child_reserved_keys, new_prefix)
844 }
845 } $else {
846 is_first = encoder.encode_embedded_struct_fields(val.$(field.name), is_first,
847 used_keys, child_reserved_keys, new_prefix)
848 }
849 } $else {
850 field_info := field_infos[i]
851 mut write_field := true
852 $if field.typ is $shared {
853 shared field_value := unsafe { val.$(field.name) }
854 rlock field_value {
855 write_field = struct_field_should_encode(field_info, field_value)
856 if write_field {
857 should_prefix := field_info.key_name in used_keys
858 || field_info.key_name in reserved_keys
859 json_key := if should_prefix {
860 prefix + field_info.key_name
861 } else {
862 field_info.key_name
863 }
864 is_first = encoder.encode_object_key(is_first, json_key)
865 if !should_prefix {
866 used_keys << field_info.key_name
867 }
868 encoder.encode_struct_field_value(field_value)
869 }
870 }
871 } $else {
872 write_field = struct_field_should_encode(field_info, val.$(field.name))
873 if write_field {
874 should_prefix := field_info.key_name in used_keys
875 || field_info.key_name in reserved_keys
876 json_key := if should_prefix {
877 prefix + field_info.key_name
878 } else {
879 field_info.key_name
880 }
881 is_first = encoder.encode_object_key(is_first, json_key)
882 if !should_prefix {
883 used_keys << field_info.key_name
884 }
885 encoder.encode_struct_field_value(val.$(field.name))
886 }
887 }
888 }
889 i++
890 }
891 return is_first
892}
893
894fn (mut encoder Encoder) encode_custom[T](val T) {
895 integer_val := val.to_json()
896 unsafe { encoder.output.push_many(integer_val.str, integer_val.len) }
897}
898
899fn (mut encoder Encoder) encode_custom2[T](val T) {
900 integer_val := val.json_str()
901 unsafe { encoder.output.push_many(integer_val.str, integer_val.len) }
902}
903
904fn (mut encoder Encoder) increment_level() {
905 encoder.level++
906 encoder.prefix = encoder.newline_string + encoder.indent_string.repeat(encoder.level)
907}
908
909fn (mut encoder Encoder) decrement_level() {
910 encoder.level--
911 encoder.prefix = encoder.newline_string + encoder.indent_string.repeat(encoder.level)
912}
913
914fn (mut encoder Encoder) add_indent() {
915 unsafe { encoder.output.push_many(encoder.prefix.str, encoder.prefix.len) }
916}
917