v2 / vlib / x / json2 / encode.v
872 lines · 799 sloc · 21.87 KB · 4df08e9c8f8548c0107f3834927287074079fd88
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 {
467 variant_value := val
468 encoder.encode_value(variant_value)
469 }
470 }
471 }
472 }
473}
474
475fn (mut encoder Encoder) encode_object_key(is_first bool, key string) bool {
476 if is_first {
477 if encoder.prettify {
478 encoder.increment_level()
479 }
480 } else {
481 encoder.output << `,`
482 }
483 if encoder.prettify {
484 encoder.add_indent()
485 }
486 encoder.encode_string(key)
487 encoder.output << `:`
488 if encoder.prettify {
489 encoder.output << ` `
490 }
491 return false
492}
493
494fn (mut encoder Encoder) encode_sumtype_struct_variant[T](val T, variant_name string) {
495 $for field in T.fields {
496 $if field.is_embed {
497 unsafe { encoder.encode_sumtype_struct_variant_with_embeds(val, variant_name) }
498 return
499 }
500 }
501 encoder.output << `{`
502 mut is_first := unsafe { encoder.encode_struct_fields[T](val, true, [], '') }
503 is_first = encoder.encode_object_key(is_first, '_type')
504 encoder.encode_string(variant_name)
505 if encoder.prettify && !is_first {
506 encoder.decrement_level()
507 encoder.add_indent()
508 }
509 encoder.output << `}`
510}
511
512@[markused]
513fn (mut encoder Encoder) encode_sumtype_time_variant(val time.Time, variant_name string) {
514 encoder.output << `{`
515 mut is_first := true
516 is_first = encoder.encode_object_key(is_first, '_type')
517 encoder.encode_string(variant_name)
518 is_first = encoder.encode_object_key(is_first, 'value')
519 encoder.encode_number(val.unix())
520 if encoder.prettify && !is_first {
521 encoder.decrement_level()
522 encoder.add_indent()
523 }
524 encoder.output << `}`
525}
526
527struct EncoderFieldInfo {
528 key_name string
529
530 is_skip bool
531 is_omitempty bool
532 is_required bool
533 is_json_null bool
534}
535
536fn get_value_from_optional[T](val ?T) T {
537 return val or { T{} }
538}
539
540fn check_not_empty[T](val T) ?bool {
541 $if T.indirections != 0 {
542 return val != unsafe { nil }
543 } $else $if T.unaliased_typ is string {
544 if val == '' {
545 return false
546 }
547 } $else $if T.unaliased_typ is $int || T.unaliased_typ is $float {
548 if val == 0 {
549 return false
550 }
551 } $else $if T.unaliased_typ is $array || T.unaliased_typ is $map {
552 return val.len != 0
553 } $else $if val is ?string {
554 opt := ?string(val)
555 if sval := opt {
556 return sval != ''
557 }
558 return false
559 } $else $if val is ?int {
560 opt := ?int(val)
561 if ival := opt {
562 return ival != 0
563 }
564 return false
565 } $else $if val is ?f64 {
566 opt := ?f64(val)
567 if fval := opt {
568 return fval != 0.0
569 }
570 return false
571 } $else $if val is ?f32 {
572 opt := ?f32(val)
573 if fval := opt {
574 return fval != 0.0
575 }
576 return false
577 }
578 return true
579}
580
581// TODO: fix compilation with -autofree, and remove the tag @[manualfree] here:
582@[manualfree; unsafe]
583fn (mut encoder Encoder) cached_field_infos[T]() []EncoderFieldInfo {
584 static field_infos := &[]EncoderFieldInfo(nil)
585 if field_infos == nil {
586 field_infos = &[]EncoderFieldInfo{}
587 $for field in T.fields {
588 mut is_skip := false
589 mut key_name := ''
590 mut is_omitempty := false
591 mut is_required := false
592 mut is_json_null := false
593 for attr in field.attrs {
594 match attr {
595 'skip' {
596 is_skip = true
597 break
598 }
599 'omitempty' {
600 is_omitempty = true
601 }
602 'required' {
603 is_required = true
604 }
605 'json_null' {
606 is_json_null = true
607 }
608 else {}
609 }
610
611 if attr.starts_with('json:') {
612 json_attr := json_attr_value(attr) or { continue }
613 if json_attr == '-' {
614 is_skip = true
615 break
616 }
617 key_name = json_attr
618 }
619 }
620 field_infos << EncoderFieldInfo{
621 key_name: if key_name == '' { field.name } else { key_name }
622 is_skip: is_skip
623 is_omitempty: is_omitempty
624 is_required: is_required
625 is_json_null: is_json_null
626 }
627 }
628 }
629 return *field_infos
630}
631
632fn (mut encoder Encoder) encode_struct_field_value[T](val T) {
633 $if T is $interface {
634 encoder.encode_null()
635 } $else $if T.unaliased_typ is voidptr {
636 encoder.encode_null()
637 } $else $if T.pointee_type is $interface {
638 encoder.encode_null()
639 } $else $if T is $option {
640 if val == none {
641 unsafe { encoder.output.push_many(null_string.str, null_string.len) }
642 } else {
643 encoder.encode_value(get_value_from_optional(val))
644 }
645 } $else $if T.indirections == 1 {
646 encoder.encode_value(*val)
647 } $else $if T.indirections == 2 {
648 encoder.encode_value(**val)
649 } $else $if T.indirections == 3 {
650 encoder.encode_value(***val)
651 } $else {
652 encoder.encode_value(val)
653 }
654}
655
656fn struct_field_is_none[T](val T) bool {
657 $if T is $option {
658 return val == none
659 }
660 return false
661}
662
663fn struct_field_is_nil[T](val T) bool {
664 $if T.indirections != 0 {
665 return val == unsafe { nil }
666 }
667 return false
668}
669
670fn struct_field_should_encode[T](field_info EncoderFieldInfo, val T) bool {
671 if field_info.is_skip {
672 return false
673 }
674 if field_info.is_omitempty {
675 if !(check_not_empty(val) or { false }) {
676 return false
677 }
678 }
679 if !field_info.is_required && !field_info.is_json_null && struct_field_is_none(val) {
680 return false
681 }
682 if struct_field_is_nil(val) {
683 return false
684 }
685 return true
686}
687
688@[unsafe]
689fn (mut encoder Encoder) encode_struct_with_embeds[T](val T) {
690 encoder.output << `{`
691 is_first := encoder.encode_embedded_struct_fields[T](val, true, [], [], '')
692 if encoder.prettify && !is_first {
693 encoder.decrement_level()
694 encoder.add_indent()
695 }
696 encoder.output << `}`
697}
698
699@[unsafe]
700fn (mut encoder Encoder) encode_sumtype_struct_variant_with_embeds[T](val T, variant_name string) {
701 encoder.output << `{`
702 mut is_first := encoder.encode_embedded_struct_fields[T](val, true, [], [], '')
703 is_first = encoder.encode_object_key(is_first, '_type')
704 encoder.encode_string(variant_name)
705 if encoder.prettify && !is_first {
706 encoder.decrement_level()
707 encoder.add_indent()
708 }
709 encoder.output << `}`
710}
711
712@[unsafe]
713fn (mut encoder Encoder) encode_struct_fields[T](val T, was_first bool, old_used_keys []string, prefix string) bool {
714 field_infos := encoder.cached_field_infos[T]()
715 mut is_first := was_first
716 mut used_keys := old_used_keys
717 mut i := 0
718
719 $for field in T.fields {
720 $if !field.is_embed {
721 field_info := field_infos[i]
722 mut write_field := true
723
724 $if field.typ is $shared {
725 shared field_value := unsafe { val.$(field.name) }
726 rlock field_value {
727 write_field = struct_field_should_encode(field_info, field_value)
728
729 if write_field {
730 if field_info.key_name in old_used_keys {
731 is_first = encoder.encode_object_key(is_first, prefix +
732 field_info.key_name)
733 } else {
734 is_first = encoder.encode_object_key(is_first, field_info.key_name)
735 used_keys << field_info.key_name
736 }
737 encoder.encode_struct_field_value(field_value)
738 }
739 }
740 } $else {
741 write_field = struct_field_should_encode(field_info, val.$(field.name))
742
743 if write_field {
744 if field_info.key_name in old_used_keys {
745 is_first = encoder.encode_object_key(is_first, prefix + field_info.key_name)
746 } else {
747 is_first = encoder.encode_object_key(is_first, field_info.key_name)
748 used_keys << field_info.key_name
749 }
750 encoder.encode_struct_field_value(val.$(field.name))
751 }
752 }
753 }
754 i++
755 }
756 $for field in T.fields {
757 $if field.is_embed {
758 new_prefix := prefix + field.name + '.'
759 $if field.typ is $shared {
760 shared field_value := unsafe { val.$(field.name) }
761 rlock field_value {
762 is_first = encoder.encode_struct_fields(field_value, is_first, used_keys,
763 new_prefix)
764 }
765 } $else {
766 is_first = encoder.encode_struct_fields(val.$(field.name), is_first, used_keys,
767 new_prefix)
768 }
769 }
770 }
771 return is_first
772}
773
774@[unsafe]
775fn (mut encoder Encoder) encode_embedded_struct_fields[T](val T, was_first bool, old_used_keys []string, reserved_keys []string, prefix string) bool {
776 field_infos := encoder.cached_field_infos[T]()
777 mut is_first := was_first
778 mut used_keys := old_used_keys.clone()
779 mut i := 0
780
781 $for field in T.fields {
782 $if field.is_embed {
783 mut child_reserved_keys := reserved_keys.clone()
784 mut reserved_i := 0
785 $for reserved_field in T.fields {
786 reserved_field_info := field_infos[reserved_i]
787 $if !reserved_field.is_embed {
788 if !reserved_field_info.is_skip {
789 child_reserved_keys << reserved_field_info.key_name
790 }
791 }
792 reserved_i++
793 }
794 new_prefix := prefix + field.name + '.'
795 $if field.typ is $shared {
796 shared field_value := unsafe { val.$(field.name) }
797 rlock field_value {
798 is_first = encoder.encode_embedded_struct_fields(field_value, is_first,
799 used_keys, child_reserved_keys, new_prefix)
800 }
801 } $else {
802 is_first = encoder.encode_embedded_struct_fields(val.$(field.name), is_first,
803 used_keys, child_reserved_keys, new_prefix)
804 }
805 } $else {
806 field_info := field_infos[i]
807 mut write_field := true
808 $if field.typ is $shared {
809 shared field_value := unsafe { val.$(field.name) }
810 rlock field_value {
811 write_field = struct_field_should_encode(field_info, field_value)
812 if write_field {
813 should_prefix := field_info.key_name in used_keys
814 || field_info.key_name in reserved_keys
815 json_key := if should_prefix {
816 prefix + field_info.key_name
817 } else {
818 field_info.key_name
819 }
820 is_first = encoder.encode_object_key(is_first, json_key)
821 if !should_prefix {
822 used_keys << field_info.key_name
823 }
824 encoder.encode_struct_field_value(field_value)
825 }
826 }
827 } $else {
828 write_field = struct_field_should_encode(field_info, val.$(field.name))
829 if write_field {
830 should_prefix := field_info.key_name in used_keys
831 || field_info.key_name in reserved_keys
832 json_key := if should_prefix {
833 prefix + field_info.key_name
834 } else {
835 field_info.key_name
836 }
837 is_first = encoder.encode_object_key(is_first, json_key)
838 if !should_prefix {
839 used_keys << field_info.key_name
840 }
841 encoder.encode_struct_field_value(val.$(field.name))
842 }
843 }
844 }
845 i++
846 }
847 return is_first
848}
849
850fn (mut encoder Encoder) encode_custom[T](val T) {
851 integer_val := val.to_json()
852 unsafe { encoder.output.push_many(integer_val.str, integer_val.len) }
853}
854
855fn (mut encoder Encoder) encode_custom2[T](val T) {
856 integer_val := val.json_str()
857 unsafe { encoder.output.push_many(integer_val.str, integer_val.len) }
858}
859
860fn (mut encoder Encoder) increment_level() {
861 encoder.level++
862 encoder.prefix = encoder.newline_string + encoder.indent_string.repeat(encoder.level)
863}
864
865fn (mut encoder Encoder) decrement_level() {
866 encoder.level--
867 encoder.prefix = encoder.newline_string + encoder.indent_string.repeat(encoder.level)
868}
869
870fn (mut encoder Encoder) add_indent() {
871 unsafe { encoder.output.push_many(encoder.prefix.str, encoder.prefix.len) }
872}
873