1use crate::ast::*;
4use crate::c_codegen::{generate_c_alphabet_expr, get_c_type};
5use crate::naming::{to_pascal_case, to_snake_case};
6use std::fmt::Write;
7
8#[derive(Debug, Clone, Default, PartialEq, Eq)]
13pub enum PatternMode {
14 #[default]
16 Skip,
17 Posix,
23 Pcre2,
28}
29
30#[derive(Debug, Clone, Default)]
32pub struct CImplConfig {
33 pub header_file: String,
35 pub arena_mode: bool,
37 pub pattern_mode: PatternMode,
39 pub with_containing: bool,
45}
46
47struct EncodeCtx<'a> {
49 mode: &'a PatternMode,
50 with_containing: bool,
51 defs: &'a [Definition],
52}
53
54pub fn generate_c_impl(
56 module: &Module,
57 config: CImplConfig,
58) -> Result<String, Box<dyn std::error::Error>> {
59 let mut output = String::new();
60
61 writeln!(
63 &mut output,
64 "/* Generated implementation from ASN.1 module {} */",
65 module.name
66 )?;
67 writeln!(&mut output, "/* DO NOT EDIT - auto-generated code */")?;
68 writeln!(&mut output)?;
69
70 writeln!(&mut output, "#include \"{}\"", config.header_file)?;
72 writeln!(&mut output, "#include <string.h>")?;
73 writeln!(&mut output, "#include <stdlib.h>")?;
74 match config.pattern_mode {
75 PatternMode::Posix => {
76 writeln!(&mut output, "#include <regex.h>")?;
77 }
78 PatternMode::Pcre2 => {
79 writeln!(&mut output, "#define PCRE2_CODE_UNIT_WIDTH 8")?;
80 writeln!(&mut output, "#include <pcre2.h>")?;
81 }
82 PatternMode::Skip => {}
83 }
84 writeln!(&mut output)?;
85
86 let mode = config.pattern_mode;
87 let with_containing = config.with_containing;
88
89 for def in &module.definitions {
91 generate_type_impl(
92 &mut output,
93 def,
94 &mode,
95 with_containing,
96 &module.definitions,
97 )?;
98 writeln!(&mut output)?;
99 }
100
101 if config.arena_mode {
103 for def in &module.definitions {
104 generate_type_arena_impl(&mut output, def, &module.definitions)?;
105 writeln!(&mut output)?;
106 }
107 }
108
109 Ok(output)
110}
111
112fn generate_type_impl(
121 output: &mut String,
122 def: &Definition,
123 mode: &PatternMode,
124 with_containing: bool,
125 defs: &[Definition],
126) -> Result<(), Box<dyn std::error::Error>> {
127 match &def.ty {
128 Type::Sequence(fields) => {
129 generate_sequence_impl(
130 output,
131 &def.name,
132 fields,
133 mode,
134 with_containing,
135 defs,
136 false,
137 )?;
138 if fields.iter().all(|f| f.optional || f.default.is_some()) {
139 writeln!(output)?;
140 generate_sequence_default_impl(output, &def.name, fields)?;
141 }
142 }
143 Type::Set(fields) => {
144 generate_sequence_impl(output, &def.name, fields, mode, with_containing, defs, true)?;
145 if fields.iter().all(|f| f.optional || f.default.is_some()) {
146 writeln!(output)?;
147 generate_sequence_default_impl(output, &def.name, fields)?;
148 }
149 }
150 Type::Choice(variants) => {
151 generate_choice_impl(output, &def.name, variants, defs)?;
152 }
153 Type::Integer(_, named_numbers) if !named_numbers.is_empty() => {
154 generate_named_integer_impl(output, &def.name)?;
155 }
156 Type::Enumerated(_) => {
157 generate_enum_impl(output, &def.name)?;
158 }
159 Type::SequenceOf(inner, opt_constraint) => {
160 let size_c = opt_constraint.as_ref().map(legacy_size_to_bounds);
161 generate_array_impl(output, &def.name, inner, true, size_c, defs)?;
162 }
163 Type::SetOf(inner, opt_constraint) => {
164 let size_c = opt_constraint.as_ref().map(legacy_size_to_bounds);
165 generate_array_impl(output, &def.name, inner, false, size_c, defs)?;
166 }
167 Type::Constrained {
169 base_type,
170 constraint,
171 } => {
172 let size_c = modern_size_to_bounds(&constraint.spec);
173 match base_type.as_ref() {
174 Type::SequenceOf(inner, _) => {
175 generate_array_impl(output, &def.name, inner, true, size_c, defs)?;
176 }
177 Type::SetOf(inner, _) => {
178 generate_array_impl(output, &def.name, inner, false, size_c, defs)?;
179 }
180 _ => {
181 generate_simple_impl(output, &def.name, &def.ty)?;
182 }
183 }
184 }
185 _ => {
186 generate_simple_impl(output, &def.name, &def.ty)?;
188 }
189 }
190 Ok(())
191}
192
193fn legacy_size_to_bounds(sc: &SizeConstraint) -> ArraySizeBounds {
195 match sc {
196 SizeConstraint::Fixed(n) => (Some(*n), Some(*n)),
197 SizeConstraint::Range(min, max) => (*min, *max),
198 }
199}
200
201fn modern_size_to_bounds(spec: &ConstraintSpec) -> Option<ArraySizeBounds> {
205 if let ConstraintSpec::Subtype(SubtypeConstraint::SizeConstraint(inner)) = spec {
206 match inner.as_ref() {
207 SubtypeConstraint::ValueRange { min, max } => {
208 let lo = match min {
209 ConstraintValue::Integer(n) if *n >= 0 => Some(*n as u64),
210 _ => None,
211 };
212 let hi = match max {
213 ConstraintValue::Integer(n) if *n >= 0 => Some(*n as u64),
214 _ => None,
215 };
216 Some((lo, hi))
217 }
218 SubtypeConstraint::SingleValue(ConstraintValue::Integer(n)) if *n >= 0 => {
219 Some((Some(*n as u64), Some(*n as u64)))
220 }
221 _ => None,
222 }
223 } else {
224 None
225 }
226}
227
228fn generate_sequence_impl(
236 output: &mut String,
237 name: &str,
238 fields: &[SequenceField],
239 mode: &PatternMode,
240 with_containing: bool,
241 defs: &[Definition],
242 is_set: bool,
243) -> Result<(), Box<dyn std::error::Error>> {
244 let struct_name = to_pascal_case(name);
245 let fn_prefix = to_snake_case(name);
246 let container_kind = if is_set { "set" } else { "sequence" };
247 let enter_fn = if is_set {
248 "synta_decoder_enter_set"
249 } else {
250 "synta_decoder_enter_sequence"
251 };
252 let start_fn = if is_set {
253 "synta_encoder_start_set"
254 } else {
255 "synta_encoder_start_sequence"
256 };
257
258 writeln!(
260 output,
261 "SyntaErrorCode {}_decode(SyntaDecoder* decoder, {}* out) {{",
262 fn_prefix, struct_name
263 )?;
264 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
265 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
266 writeln!(output, " }}")?;
267 writeln!(output)?;
268 writeln!(output, " // Enter {}", container_kind.to_uppercase())?;
269 writeln!(output, " SyntaDecoder* seq_decoder = NULL;")?;
270 writeln!(
271 output,
272 " SyntaErrorCode err = {}(decoder, &seq_decoder);",
273 enter_fn
274 )?;
275 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
276 writeln!(output, " return err;")?;
277 writeln!(output, " }}")?;
278 writeln!(output)?;
279
280 for field in fields {
282 let field_name = to_snake_case(&field.name);
283
284 if field.optional {
285 writeln!(output, " // Decode optional field: {}", field_name)?;
286 let tag_check = get_tag_check_condition(&field.ty, defs);
287 writeln!(output, " {{")?;
288 writeln!(output, " SyntaTag tag;")?;
289 writeln!(
290 output,
291 " if (synta_decoder_peek_tag(seq_decoder, &tag) == SyntaErrorCode_Success &&"
292 )?;
293 writeln!(output, " ({})) {{", tag_check)?;
294 generate_field_decode(output, &field.ty, &format!("out->{}", field_name), 3, defs)?;
295 writeln!(output, " out->has_{} = true;", field_name)?;
296 writeln!(output, " }} else {{")?;
297 writeln!(output, " out->has_{} = false;", field_name)?;
298 writeln!(output, " }}")?;
299 writeln!(output, " }}")?;
300 } else {
301 writeln!(output, " // Decode field: {}", field_name)?;
302 generate_field_decode(output, &field.ty, &format!("out->{}", field_name), 1, defs)?;
303 }
304 writeln!(output)?;
305 }
306
307 writeln!(output, " synta_decoder_free(seq_decoder);")?;
308 writeln!(output, " return SyntaErrorCode_Success;")?;
309 writeln!(output, "}}")?;
310 writeln!(output)?;
311
312 writeln!(
314 output,
315 "SyntaErrorCode {}_encode(SyntaEncoder* encoder, const {}* value) {{",
316 fn_prefix, struct_name
317 )?;
318 writeln!(output, " if (encoder == NULL || value == NULL) {{")?;
319 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
320 writeln!(output, " }}")?;
321 writeln!(output)?;
322 writeln!(output, " // Start {}", container_kind.to_uppercase())?;
323 writeln!(output, " SyntaEncoder* seq_encoder = NULL;")?;
324 writeln!(
325 output,
326 " SyntaErrorCode err = {}(encoder, &seq_encoder);",
327 start_fn
328 )?;
329 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
330 writeln!(output)?;
331
332 let enc_ctx = EncodeCtx {
333 mode,
334 with_containing,
335 defs,
336 };
337 for field in fields {
338 let field_name = to_snake_case(&field.name);
339
340 if field.optional {
341 writeln!(output, " if (value->has_{}) {{", field_name)?;
342 generate_field_encode(
343 output,
344 &field.ty,
345 &format!("value->{}", field_name),
346 "seq_encoder",
347 2,
348 &enc_ctx,
349 )?;
350 writeln!(output, " }}")?;
351 } else {
352 generate_field_encode(
353 output,
354 &field.ty,
355 &format!("value->{}", field_name),
356 "seq_encoder",
357 1,
358 &enc_ctx,
359 )?;
360 }
361 }
362
363 writeln!(output)?;
364 writeln!(
365 output,
366 " err = synta_encoder_end_constructed(seq_encoder);"
367 )?;
368 writeln!(output, " return err;")?;
369 writeln!(output, "}}")?;
370 writeln!(output)?;
371
372 writeln!(output, "void {}_free({}* value) {{", fn_prefix, struct_name)?;
374 writeln!(output, " if (value == NULL) return;")?;
375 writeln!(output)?;
376
377 for field in fields {
378 let field_name = to_snake_case(&field.name);
379 match &field.ty {
380 Type::Integer(_, _) => {
381 if field.optional {
382 writeln!(output, " if (value->has_{}) {{", field_name)?;
383 writeln!(output, " synta_integer_free(value->{});", field_name)?;
384 writeln!(output, " }}")?;
385 } else {
386 writeln!(output, " synta_integer_free(value->{});", field_name)?;
387 }
388 }
389 Type::ObjectIdentifier => {
390 if field.optional {
391 writeln!(output, " if (value->has_{}) {{", field_name)?;
392 writeln!(output, " synta_oid_free(value->{});", field_name)?;
393 writeln!(output, " }}")?;
394 } else {
395 writeln!(output, " synta_oid_free(value->{});", field_name)?;
396 }
397 }
398 Type::OctetString(_)
399 | Type::Utf8String(_)
400 | Type::PrintableString(_)
401 | Type::IA5String(_)
402 | Type::UtcTime
403 | Type::GeneralizedTime
404 | Type::Any
405 | Type::AnyDefinedBy(_) => {
406 if field.optional {
407 writeln!(output, " if (value->has_{}) {{", field_name)?;
408 writeln!(
409 output,
410 " synta_octet_string_free(value->{});",
411 field_name
412 )?;
413 writeln!(output, " }}")?;
414 } else {
415 writeln!(
416 output,
417 " synta_octet_string_free(value->{});",
418 field_name
419 )?;
420 }
421 }
422 Type::BitString(_) => {
423 if field.optional {
424 writeln!(output, " if (value->has_{}) {{", field_name)?;
425 writeln!(
426 output,
427 " synta_byte_array_free(&value->{}.data);",
428 field_name
429 )?;
430 writeln!(output, " }}")?;
431 } else {
432 writeln!(
433 output,
434 " synta_byte_array_free(&value->{}.data);",
435 field_name
436 )?;
437 }
438 }
439 Type::SequenceOf(inner, _) | Type::SetOf(inner, _) => {
440 if needs_freeing(inner, defs) {
442 writeln!(output, " // Free array elements")?;
443 writeln!(
444 output,
445 " for (size_t i = 0; i < value->{}_count; i++) {{",
446 field_name
447 )?;
448 generate_free_element(
449 output,
450 inner,
451 &format!("value->{}[i]", field_name),
452 defs,
453 )?;
454 writeln!(output, " }}")?;
455 }
456 writeln!(output, " // Free array")?;
457 writeln!(output, " free(value->{});", field_name)?;
458 }
459 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
460 for inner_field in inner_fields {
462 if matches!(inner_field.ty, Type::Null) {
463 continue;
464 }
465
466 let inner_name = to_snake_case(&inner_field.name);
467 let nested_var = format!("value->{}.{}", field_name, inner_name);
468
469 match &inner_field.ty {
470 Type::Integer(_, _) => {
471 if inner_field.optional {
472 writeln!(
473 output,
474 " if (value->{}.has_{}) {{",
475 field_name, inner_name
476 )?;
477 writeln!(output, " synta_integer_free({});", nested_var)?;
478 writeln!(output, " }}")?;
479 } else {
480 writeln!(output, " synta_integer_free({});", nested_var)?;
481 }
482 }
483 Type::ObjectIdentifier => {
484 if inner_field.optional {
485 writeln!(
486 output,
487 " if (value->{}.has_{}) {{",
488 field_name, inner_name
489 )?;
490 writeln!(output, " synta_oid_free({});", nested_var)?;
491 writeln!(output, " }}")?;
492 } else {
493 writeln!(output, " synta_oid_free({});", nested_var)?;
494 }
495 }
496 Type::OctetString(_)
497 | Type::Utf8String(_)
498 | Type::PrintableString(_)
499 | Type::IA5String(_) => {
500 if inner_field.optional {
501 writeln!(
502 output,
503 " if (value->{}.has_{}) {{",
504 field_name, inner_name
505 )?;
506 writeln!(
507 output,
508 " synta_octet_string_free({});",
509 nested_var
510 )?;
511 writeln!(output, " }}")?;
512 } else {
513 writeln!(output, " synta_octet_string_free({});", nested_var)?;
514 }
515 }
516 Type::BitString(_) => {
517 if inner_field.optional {
518 writeln!(
519 output,
520 " if (value->{}.has_{}) {{",
521 field_name, inner_name
522 )?;
523 writeln!(
524 output,
525 " synta_byte_array_free(&{}.data);",
526 nested_var
527 )?;
528 writeln!(output, " }}")?;
529 } else {
530 writeln!(
531 output,
532 " synta_byte_array_free(&{}.data);",
533 nested_var
534 )?;
535 }
536 }
537 Type::TypeRef(type_name) => {
538 let name = type_name.clone();
539 if inner_field.optional {
540 writeln!(
541 output,
542 " if (value->{}.has_{}) {{",
543 field_name, inner_name
544 )?;
545 emit_typeref_free(output, &name, &nested_var, " ", defs)?;
546 writeln!(output, " }}")?;
547 } else {
548 emit_typeref_free(output, &name, &nested_var, " ", defs)?;
549 }
550 }
551 _ => {}
552 }
553 }
554 }
555 Type::TypeRef(type_name) => {
556 if needs_freeing(&field.ty, defs) {
558 let name = type_name.clone();
559 if field.optional {
560 writeln!(output, " if (value->has_{}) {{", field_name)?;
561 emit_typeref_free(
562 output,
563 &name,
564 &format!("value->{}", field_name),
565 " ",
566 defs,
567 )?;
568 writeln!(output, " }}")?;
569 } else {
570 emit_typeref_free(
571 output,
572 &name,
573 &format!("value->{}", field_name),
574 " ",
575 defs,
576 )?;
577 }
578 }
579 }
580 Type::Tagged { inner, .. }
581 | Type::Constrained {
582 base_type: inner, ..
583 } => {
584 let base_ty = unwrap_type(inner);
586 if field.optional {
587 writeln!(output, " if (value->has_{}) {{", field_name)?;
588 generate_free_stmt(
589 output,
590 base_ty,
591 &format!("value->{}", field_name),
592 " ",
593 )?;
594 writeln!(output, " }}")?;
595 } else {
596 generate_free_stmt(output, base_ty, &format!("value->{}", field_name), " ")?;
597 }
598 }
599 _ => {}
600 }
601 }
602
603 writeln!(output, "}}")?;
604
605 Ok(())
606}
607
608fn generate_sequence_default_impl(
620 output: &mut String,
621 name: &str,
622 fields: &[SequenceField],
623) -> Result<(), Box<dyn std::error::Error>> {
624 let c_name = to_pascal_case(name);
625 let fn_prefix = to_snake_case(name);
626
627 writeln!(output, "{c_name} {fn_prefix}_default(void) {{")?;
628 writeln!(output, " {c_name} out = {{0}};")?;
629
630 for field in fields {
631 let Some(ref default_val) = field.default else {
632 continue;
633 };
634 let field_name = to_snake_case(&field.name);
635 match unwrap_type(&field.ty) {
636 Type::Boolean => {
637 let is_true = default_val.eq_ignore_ascii_case("true");
639 if is_true {
640 writeln!(output, " out.{field_name} = true;")?;
641 }
642 }
643 Type::Real => {
644 writeln!(output, " out.{field_name} = {default_val};")?;
645 }
646 _ => {
647 writeln!(
648 output,
649 " /* out.{field_name}: DEFAULT {default_val} — set by caller or decoder */"
650 )?;
651 }
652 }
653 }
654
655 writeln!(output, " return out;")?;
656 writeln!(output, "}}")?;
657 Ok(())
658}
659
660fn generate_choice_impl(
668 output: &mut String,
669 name: &str,
670 variants: &[ChoiceVariant],
671 defs: &[Definition],
672) -> Result<(), Box<dyn std::error::Error>> {
673 let struct_name = to_pascal_case(name);
674 let fn_prefix = to_snake_case(name);
675 let tag_enum_name = format!("{}Tag", struct_name);
676
677 writeln!(
679 output,
680 "SyntaErrorCode {}_decode(SyntaDecoder* decoder, {}* out) {{",
681 fn_prefix, struct_name
682 )?;
683 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
684 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
685 writeln!(output, " }}")?;
686 writeln!(output)?;
687 writeln!(
688 output,
689 " // Peek at the next tag to determine which variant"
690 )?;
691 writeln!(output, " SyntaTag tag;")?;
692 writeln!(
693 output,
694 " SyntaErrorCode err = synta_decoder_peek_tag(decoder, &tag);"
695 )?;
696 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
697 writeln!(output, " return err;")?;
698 writeln!(output, " }}")?;
699 writeln!(output)?;
700
701 for (i, variant) in variants.iter().enumerate() {
703 let variant_name = to_snake_case(&variant.name);
704 let variant_pascal = to_pascal_case(&variant.name);
705 let tag_check = get_tag_check_condition(&variant.ty, defs);
706
707 let else_if = if i == 0 { "if" } else { "} else if" };
708
709 writeln!(output, " {} ({}) {{", else_if, tag_check)?;
710 writeln!(output, " // Decode {} variant", variant_name)?;
711 writeln!(
712 output,
713 " out->tag = {}_{};",
714 tag_enum_name, variant_pascal
715 )?;
716 generate_choice_variant_decode(
717 output,
718 &variant.ty,
719 &format!("out->value.{}", variant_name),
720 )?;
721 writeln!(output, " return SyntaErrorCode_Success;")?;
722 }
723
724 writeln!(output, " }} else {{")?;
725 writeln!(
726 output,
727 " /* no matching variant found for the observed tag */"
728 )?;
729 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
730 writeln!(output, " }}")?;
731 writeln!(output, "}}")?;
732 writeln!(output)?;
733
734 writeln!(
736 output,
737 "SyntaErrorCode {}_encode(SyntaEncoder* encoder, const {}* value) {{",
738 fn_prefix, struct_name
739 )?;
740 writeln!(output, " if (encoder == NULL || value == NULL) {{")?;
741 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
742 writeln!(output, " }}")?;
743 writeln!(output)?;
744 writeln!(output, " SyntaErrorCode err;")?;
745 writeln!(output, " switch (value->tag) {{")?;
746
747 for variant in variants {
749 let variant_name = to_snake_case(&variant.name);
750 let variant_pascal = to_pascal_case(&variant.name);
751
752 writeln!(
753 output,
754 " case {}_{}: {{",
755 tag_enum_name, variant_pascal
756 )?;
757 generate_choice_variant_encode(
758 output,
759 &variant.ty,
760 &format!("value->value.{}", variant_name),
761 )?;
762 writeln!(output, " return SyntaErrorCode_Success;")?;
763 writeln!(output, " }}")?;
764 }
765
766 writeln!(output, " default:")?;
767 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
768 writeln!(output, " }}")?;
769 writeln!(output, "}}")?;
770 writeln!(output)?;
771
772 writeln!(output, "void {}_free({}* value) {{", fn_prefix, struct_name)?;
774 writeln!(output, " if (value == NULL) return;")?;
775 writeln!(output)?;
776 writeln!(output, " switch (value->tag) {{")?;
777
778 for variant in variants {
780 let variant_name = to_snake_case(&variant.name);
781 let variant_pascal = to_pascal_case(&variant.name);
782
783 if needs_freeing(&variant.ty, defs) {
785 writeln!(
786 output,
787 " case {}_{}: {{",
788 tag_enum_name, variant_pascal
789 )?;
790 generate_choice_variant_free(
791 output,
792 &variant.ty,
793 &format!("value->value.{}", variant_name),
794 defs,
795 )?;
796 writeln!(output, " break;")?;
797 writeln!(output, " }}")?;
798 }
799 }
800
801 writeln!(output, " default:")?;
802 writeln!(output, " break;")?;
803 writeln!(output, " }}")?;
804 writeln!(output, "}}")?;
805
806 Ok(())
807}
808
809type ArraySizeBounds = (Option<u64>, Option<u64>);
812
813fn generate_array_impl(
824 output: &mut String,
825 name: &str,
826 inner_ty: &Type,
827 is_sequence: bool,
828 size_constraint: Option<ArraySizeBounds>,
829 defs: &[Definition],
830) -> Result<(), Box<dyn std::error::Error>> {
831 let struct_name = to_pascal_case(name);
832 let fn_prefix = to_snake_case(name);
833 let container_type = if is_sequence { "sequence" } else { "set" };
834 let elem_c_type = get_c_type(inner_ty);
835 let array_type = format!("{}*", elem_c_type);
836
837 writeln!(
839 output,
840 "SyntaErrorCode {}_decode(SyntaDecoder* decoder, struct {}* out) {{",
841 fn_prefix, struct_name
842 )?;
843 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
844 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
845 writeln!(output, " }}")?;
846 writeln!(output)?;
847
848 writeln!(output, " // Enter SEQUENCE/SET")?;
849 writeln!(output, " SyntaDecoder* array_decoder = NULL;")?;
850 writeln!(
851 output,
852 " SyntaErrorCode err = synta_decoder_enter_{}(decoder, &array_decoder);",
853 container_type
854 )?;
855 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
856 writeln!(output, " return err;")?;
857 writeln!(output, " }}")?;
858 writeln!(output)?;
859
860 writeln!(output, " // Allocate dynamic array for elements")?;
861 writeln!(output, " size_t capacity = 4; // Initial capacity")?;
862 writeln!(output, " size_t count = 0;")?;
863 writeln!(
864 output,
865 " {} array = ({})calloc(capacity, sizeof({}));",
866 array_type, array_type, elem_c_type
867 )?;
868 writeln!(output, " if (array == NULL) {{")?;
869 writeln!(output, " synta_decoder_free(array_decoder);")?;
870 writeln!(output, " return SyntaErrorCode_OutOfMemory;")?;
871 writeln!(output, " }}")?;
872 writeln!(output)?;
873
874 writeln!(
875 output,
876 " while (!synta_decoder_at_end(array_decoder)) {{"
877 )?;
878 writeln!(output, " // Grow array if needed")?;
879 writeln!(output, " if (count >= capacity) {{")?;
880 writeln!(output, " capacity *= 2;")?;
881 writeln!(
882 output,
883 " {} new_array = ({})realloc(array, capacity * sizeof({}));",
884 array_type, array_type, elem_c_type
885 )?;
886 writeln!(output, " if (new_array == NULL) {{")?;
887 writeln!(output, " free(array);")?;
888 writeln!(output, " synta_decoder_free(array_decoder);")?;
889 writeln!(output, " return SyntaErrorCode_OutOfMemory;")?;
890 writeln!(output, " }}")?;
891 writeln!(output, " array = new_array;")?;
892 writeln!(output, " }}")?;
893 writeln!(output)?;
894
895 writeln!(output, " // Decode element")?;
897 generate_decode_element_toplevel(output, inner_ty, "array_decoder", "array[count]")?;
898 writeln!(output, " count++;")?;
899 writeln!(output, " }}")?;
900 writeln!(output)?;
901
902 if let Some(size_spec) = size_constraint {
904 emit_array_size_check(output, size_spec, "count")?;
905 }
906
907 writeln!(output, " out->count = count;")?;
908 writeln!(output, " out->items = array;")?;
909 writeln!(output, " synta_decoder_free(array_decoder);")?;
910 writeln!(output, " return SyntaErrorCode_Success;")?;
911 writeln!(output, "}}")?;
912 writeln!(output)?;
913
914 writeln!(
916 output,
917 "SyntaErrorCode {}_encode(SyntaEncoder* encoder, const struct {}* value) {{",
918 fn_prefix, struct_name
919 )?;
920 writeln!(output, " if (encoder == NULL || value == NULL) {{")?;
921 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
922 writeln!(output, " }}")?;
923 writeln!(output)?;
924
925 if let Some(size_spec) = size_constraint {
927 emit_array_size_check_encode(output, size_spec, "value->count")?;
928 }
929
930 writeln!(output, " // Start SEQUENCE/SET")?;
931 writeln!(output, " SyntaEncoder* array_encoder = NULL;")?;
932 writeln!(
933 output,
934 " SyntaErrorCode err = synta_encoder_start_{}(encoder, &array_encoder);",
935 container_type
936 )?;
937 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
938 writeln!(output)?;
939
940 writeln!(output, " // Encode each element")?;
941 writeln!(output, " for (size_t i = 0; i < value->count; i++) {{")?;
942 generate_encode_element_toplevel(output, inner_ty, "array_encoder", "value->items[i]")?;
943 writeln!(output, " }}")?;
944 writeln!(output)?;
945
946 writeln!(
947 output,
948 " return synta_encoder_end_constructed(array_encoder);"
949 )?;
950 writeln!(output, "}}")?;
951 writeln!(output)?;
952
953 writeln!(output, "void {}_free({}* value) {{", fn_prefix, struct_name)?;
955 writeln!(output, " if (value == NULL) return;")?;
956 writeln!(output)?;
957
958 if needs_freeing(inner_ty, defs) {
959 writeln!(output, " // Free each element")?;
960 writeln!(output, " for (size_t i = 0; i < value->count; i++) {{")?;
961 generate_free_element(output, inner_ty, "value->items[i]", defs)?;
962 writeln!(output, " }}")?;
963 writeln!(output)?;
964 }
965
966 writeln!(output, " // Free array")?;
967 writeln!(output, " free(value->items);")?;
968 writeln!(output, "}}")?;
969
970 Ok(())
971}
972
973fn generate_enum_impl(output: &mut String, name: &str) -> Result<(), Box<dyn std::error::Error>> {
981 let fn_prefix = to_snake_case(name);
982
983 writeln!(
985 output,
986 "SyntaErrorCode {}_decode(SyntaDecoder* decoder, enum {}* out) {{",
987 fn_prefix,
988 to_pascal_case(name)
989 )?;
990 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
991 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
992 writeln!(output, " }}")?;
993 writeln!(output)?;
994 writeln!(output, " SyntaInteger* int_val = NULL;")?;
995 writeln!(
996 output,
997 " SyntaErrorCode err = synta_decode_integer(decoder, &int_val);"
998 )?;
999 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
1000 writeln!(output)?;
1001 writeln!(output, " int64_t val;")?;
1002 writeln!(output, " err = synta_integer_to_i64(int_val, &val);")?;
1003 writeln!(output, " synta_integer_free(int_val);")?;
1004 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
1005 writeln!(output)?;
1006 writeln!(output, " *out = (enum {})val;", to_pascal_case(name))?;
1007 writeln!(output, " return SyntaErrorCode_Success;")?;
1008 writeln!(output, "}}")?;
1009 writeln!(output)?;
1010
1011 writeln!(
1013 output,
1014 "SyntaErrorCode {}_encode(SyntaEncoder* encoder, const enum {}* value) {{",
1015 fn_prefix,
1016 to_pascal_case(name)
1017 )?;
1018 writeln!(output, " if (encoder == NULL || value == NULL) {{")?;
1019 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
1020 writeln!(output, " }}")?;
1021 writeln!(output)?;
1022 writeln!(
1023 output,
1024 " SyntaInteger* int_val = synta_integer_new_i64((int64_t)*value);"
1025 )?;
1026 writeln!(output, " if (int_val == NULL) {{")?;
1027 writeln!(output, " return SyntaErrorCode_OutOfMemory;")?;
1028 writeln!(output, " }}")?;
1029 writeln!(output)?;
1030 writeln!(
1031 output,
1032 " SyntaErrorCode err = synta_encode_integer(encoder, int_val);"
1033 )?;
1034 writeln!(output, " synta_integer_free(int_val);")?;
1035 writeln!(output, " return err;")?;
1036 writeln!(output, "}}")?;
1037
1038 Ok(())
1039}
1040
1041fn generate_named_integer_impl(
1050 output: &mut String,
1051 name: &str,
1052) -> Result<(), Box<dyn std::error::Error>> {
1053 let fn_prefix = to_snake_case(name);
1054 let c_name = to_pascal_case(name);
1055
1056 writeln!(
1058 output,
1059 "SyntaErrorCode {}_decode(SyntaDecoder* decoder, {}* out) {{",
1060 fn_prefix, c_name
1061 )?;
1062 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
1063 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
1064 writeln!(output, " }}")?;
1065 writeln!(output)?;
1066 writeln!(output, " SyntaInteger* int_val = NULL;")?;
1067 writeln!(
1068 output,
1069 " SyntaErrorCode err = synta_decode_integer(decoder, &int_val);"
1070 )?;
1071 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
1072 writeln!(output)?;
1073 writeln!(output, " int64_t val;")?;
1074 writeln!(output, " err = synta_integer_to_i64(int_val, &val);")?;
1075 writeln!(output, " synta_integer_free(int_val);")?;
1076 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
1077 writeln!(output)?;
1078 writeln!(output, " *out = val;")?;
1079 writeln!(output, " return SyntaErrorCode_Success;")?;
1080 writeln!(output, "}}")?;
1081 writeln!(output)?;
1082
1083 writeln!(
1085 output,
1086 "SyntaErrorCode {}_encode(SyntaEncoder* encoder, const {}* value) {{",
1087 fn_prefix, c_name
1088 )?;
1089 writeln!(output, " if (encoder == NULL || value == NULL) {{")?;
1090 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
1091 writeln!(output, " }}")?;
1092 writeln!(output)?;
1093 writeln!(
1094 output,
1095 " SyntaInteger* int_val = synta_integer_new_i64(*value);"
1096 )?;
1097 writeln!(output, " if (int_val == NULL) {{")?;
1098 writeln!(output, " return SyntaErrorCode_OutOfMemory;")?;
1099 writeln!(output, " }}")?;
1100 writeln!(output)?;
1101 writeln!(
1102 output,
1103 " SyntaErrorCode err = synta_encode_integer(encoder, int_val);"
1104 )?;
1105 writeln!(output, " synta_integer_free(int_val);")?;
1106 writeln!(output, " return err;")?;
1107 writeln!(output, "}}")?;
1108
1109 Ok(())
1110}
1111
1112fn unwrap_type(ty: &Type) -> &Type {
1114 match ty {
1115 Type::Tagged { inner, .. } => unwrap_type(inner),
1116 Type::Constrained { base_type, .. } => unwrap_type(base_type),
1117 other => other,
1118 }
1119}
1120
1121fn generate_simple_impl(
1127 output: &mut String,
1128 name: &str,
1129 ty: &Type,
1130) -> Result<(), Box<dyn std::error::Error>> {
1131 let fn_prefix = to_snake_case(name);
1132 let type_name = to_pascal_case(name);
1133 let base = unwrap_type(ty);
1134
1135 writeln!(
1137 output,
1138 "SyntaErrorCode {}_decode(SyntaDecoder* decoder, {}* out) {{",
1139 fn_prefix, type_name
1140 )?;
1141 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
1142 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
1143 writeln!(output, " }}")?;
1144 match base {
1145 Type::Boolean => {
1146 writeln!(output, " return synta_decode_boolean(decoder, out);")?;
1147 }
1148 Type::Integer(_, _) | Type::Enumerated(_) => {
1149 writeln!(output, " return synta_decode_integer(decoder, out);")?;
1150 }
1151 Type::Real => {
1152 writeln!(output, " return synta_decode_real(decoder, out);")?;
1153 }
1154 Type::Null => {
1155 writeln!(output, " (void)out;")?;
1156 writeln!(output, " return synta_decode_null(decoder);")?;
1157 }
1158 Type::ObjectIdentifier => {
1159 writeln!(
1160 output,
1161 " return synta_decode_object_identifier(decoder, out);"
1162 )?;
1163 }
1164 Type::BitString(_) => {
1165 writeln!(
1166 output,
1167 " return synta_decode_bit_string(decoder, &out->data, &out->unused_bits);"
1168 )?;
1169 }
1170 Type::OctetString(_) | Type::Any | Type::AnyDefinedBy(_) => {
1171 writeln!(
1172 output,
1173 " return synta_decode_octet_string(decoder, out);"
1174 )?;
1175 }
1176 Type::Utf8String(_) => {
1177 writeln!(
1178 output,
1179 " return synta_decode_utf8_string_os(decoder, out);"
1180 )?;
1181 }
1182 Type::PrintableString(_) => {
1183 writeln!(
1184 output,
1185 " return synta_decode_printable_string_os(decoder, out);"
1186 )?;
1187 }
1188 Type::IA5String(_) => {
1189 writeln!(
1190 output,
1191 " return synta_decode_ia5_string_os(decoder, out);"
1192 )?;
1193 }
1194 Type::UtcTime => {
1195 writeln!(output, " return synta_decode_utctime_os(decoder, out);")?;
1196 }
1197 Type::GeneralizedTime => {
1198 writeln!(
1199 output,
1200 " return synta_decode_generalized_time_os(decoder, out);"
1201 )?;
1202 }
1203 Type::TypeRef(ref_name) => {
1204 let ref_fn = to_snake_case(ref_name);
1205 writeln!(output, " return {}_decode(decoder, out);", ref_fn)?;
1206 }
1207 _ => {
1208 writeln!(output, " /* unsupported simple type alias */")?;
1209 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
1210 }
1211 }
1212 writeln!(output, "}}")?;
1213 writeln!(output)?;
1214
1215 writeln!(
1217 output,
1218 "SyntaErrorCode {}_encode(SyntaEncoder* encoder, const {}* value) {{",
1219 fn_prefix, type_name
1220 )?;
1221 writeln!(output, " if (encoder == NULL || value == NULL) {{")?;
1222 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
1223 writeln!(output, " }}")?;
1224 match base {
1225 Type::Boolean => {
1226 writeln!(output, " return synta_encode_boolean(encoder, *value);")?;
1227 }
1228 Type::Integer(_, _) | Type::Enumerated(_) => {
1229 writeln!(output, " return synta_encode_integer(encoder, value);")?;
1230 }
1231 Type::Real => {
1232 writeln!(output, " return synta_encode_real(encoder, *value);")?;
1233 }
1234 Type::Null => {
1235 writeln!(output, " (void)value;")?;
1236 writeln!(output, " return synta_encode_null(encoder);")?;
1237 }
1238 Type::ObjectIdentifier => {
1239 writeln!(
1240 output,
1241 " return synta_encode_object_identifier(encoder, value);"
1242 )?;
1243 }
1244 Type::BitString(_) => {
1245 writeln!(
1246 output,
1247 " return synta_encode_bit_string(encoder, value->data.data, value->data.len, value->unused_bits);"
1248 )?;
1249 }
1250 Type::OctetString(_) | Type::Any | Type::AnyDefinedBy(_) => {
1255 writeln!(
1256 output,
1257 " if (*value == NULL) return SyntaErrorCode_NullPointer;"
1258 )?;
1259 writeln!(
1260 output,
1261 " return synta_encode_octet_string(encoder, synta_octet_string_data(*value), synta_octet_string_len(*value));"
1262 )?;
1263 }
1264 Type::Utf8String(_) => {
1265 writeln!(
1266 output,
1267 " if (*value == NULL) return SyntaErrorCode_NullPointer;"
1268 )?;
1269 writeln!(
1270 output,
1271 " return synta_encode_utf8_string_bytes(encoder, synta_octet_string_data(*value), synta_octet_string_len(*value));"
1272 )?;
1273 }
1274 Type::PrintableString(_) => {
1275 writeln!(
1276 output,
1277 " if (*value == NULL) return SyntaErrorCode_NullPointer;"
1278 )?;
1279 writeln!(
1280 output,
1281 " return synta_encode_printable_string_bytes(encoder, synta_octet_string_data(*value), synta_octet_string_len(*value));"
1282 )?;
1283 }
1284 Type::IA5String(_) => {
1285 writeln!(
1286 output,
1287 " if (*value == NULL) return SyntaErrorCode_NullPointer;"
1288 )?;
1289 writeln!(
1290 output,
1291 " return synta_encode_ia5_string_bytes(encoder, synta_octet_string_data(*value), synta_octet_string_len(*value));"
1292 )?;
1293 }
1294 Type::UtcTime => {
1295 writeln!(
1296 output,
1297 " if (*value == NULL) return SyntaErrorCode_NullPointer;"
1298 )?;
1299 writeln!(
1300 output,
1301 " return synta_encode_utctime_bytes(encoder, synta_octet_string_data(*value), synta_octet_string_len(*value));"
1302 )?;
1303 }
1304 Type::GeneralizedTime => {
1305 writeln!(
1306 output,
1307 " if (*value == NULL) return SyntaErrorCode_NullPointer;"
1308 )?;
1309 writeln!(
1310 output,
1311 " return synta_encode_generalized_time_bytes(encoder, synta_octet_string_data(*value), synta_octet_string_len(*value));"
1312 )?;
1313 }
1314 Type::TypeRef(ref_name) => {
1315 let ref_fn = to_snake_case(ref_name);
1316 writeln!(output, " return {}_encode(encoder, value);", ref_fn)?;
1317 }
1318 _ => {
1319 writeln!(output, " /* unsupported simple type alias */")?;
1320 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
1321 }
1322 }
1323 writeln!(output, "}}")?;
1324
1325 Ok(())
1326}
1327
1328fn make_decode_call(ty: &Type, decoder: &str, var: &str) -> Option<String> {
1334 match ty {
1335 Type::Boolean => Some(format!("synta_decode_boolean({}, &{})", decoder, var)),
1336 Type::Integer(_, _) | Type::Enumerated(_) => {
1337 Some(format!("synta_decode_integer({}, &{})", decoder, var))
1338 }
1339 Type::Real => Some(format!("synta_decode_real({}, &{})", decoder, var)),
1340 Type::Null => Some(format!("synta_decode_null({})", decoder)),
1341 Type::ObjectIdentifier => Some(format!(
1342 "synta_decode_object_identifier({}, &{})",
1343 decoder, var
1344 )),
1345 Type::BitString(_) => Some(format!(
1346 "synta_decode_bit_string({}, &{}.data, &{}.unused_bits)",
1347 decoder, var, var
1348 )),
1349 Type::OctetString(_) | Type::Any | Type::AnyDefinedBy(_) => {
1350 Some(format!("synta_decode_octet_string({}, &{})", decoder, var))
1351 }
1352 Type::Utf8String(_) => Some(format!(
1353 "synta_decode_utf8_string_os({}, &{})",
1354 decoder, var
1355 )),
1356 Type::PrintableString(_) => Some(format!(
1357 "synta_decode_printable_string_os({}, &{})",
1358 decoder, var
1359 )),
1360 Type::IA5String(_) => Some(format!("synta_decode_ia5_string_os({}, &{})", decoder, var)),
1361 Type::UtcTime => Some(format!("synta_decode_utctime_os({}, &{})", decoder, var)),
1362 Type::GeneralizedTime => Some(format!(
1363 "synta_decode_generalized_time_os({}, &{})",
1364 decoder, var
1365 )),
1366 Type::TypeRef(name) => Some(format!(
1367 "{}_decode({}, &{})",
1368 to_snake_case(name),
1369 decoder,
1370 var
1371 )),
1372 Type::Tagged { tag, inner } => match tag.tagging {
1373 Tagging::Explicit => None,
1377 Tagging::Implicit => make_decode_call(inner, decoder, var),
1380 },
1381 Type::Constrained {
1382 base_type: inner, ..
1383 } => make_decode_call(inner, decoder, var),
1384 _ => None,
1385 }
1386}
1387
1388fn make_encode_call(ty: &Type, encoder: &str, var: &str) -> Option<String> {
1393 match ty {
1394 Type::Boolean => Some(format!("synta_encode_boolean({}, {})", encoder, var)),
1395 Type::Integer(_, _) | Type::Enumerated(_) => {
1396 Some(format!("synta_encode_integer({}, {})", encoder, var))
1397 }
1398 Type::Real => Some(format!("synta_encode_real({}, {})", encoder, var)),
1399 Type::Null => Some(format!("synta_encode_null({})", encoder)),
1400 Type::ObjectIdentifier => {
1401 Some(format!("synta_encode_object_identifier({}, {})", encoder, var))
1402 }
1403 Type::BitString(_) => Some(format!(
1404 "synta_encode_bit_string({}, {}.data.data, {}.data.len, {}.unused_bits)",
1405 encoder, var, var, var
1406 )),
1407 Type::OctetString(_) | Type::Any | Type::AnyDefinedBy(_) => Some(format!(
1408 "synta_encode_octet_string({}, synta_octet_string_data({}), synta_octet_string_len({}))",
1409 encoder, var, var
1410 )),
1411 Type::Utf8String(_) => Some(format!(
1412 "synta_encode_utf8_string_bytes({}, synta_octet_string_data({}), synta_octet_string_len({}))",
1413 encoder, var, var
1414 )),
1415 Type::PrintableString(_) => Some(format!(
1416 "synta_encode_printable_string_bytes({}, synta_octet_string_data({}), synta_octet_string_len({}))",
1417 encoder, var, var
1418 )),
1419 Type::IA5String(_) => Some(format!(
1420 "synta_encode_ia5_string_bytes({}, synta_octet_string_data({}), synta_octet_string_len({}))",
1421 encoder, var, var
1422 )),
1423 Type::UtcTime => Some(format!(
1424 "synta_encode_utctime_bytes({}, synta_octet_string_data({}), synta_octet_string_len({}))",
1425 encoder, var, var
1426 )),
1427 Type::GeneralizedTime => Some(format!(
1428 "synta_encode_generalized_time_bytes({}, synta_octet_string_data({}), synta_octet_string_len({}))",
1429 encoder, var, var
1430 )),
1431 Type::TypeRef(name) => Some(format!(
1432 "{}_encode({}, &{})",
1433 to_snake_case(name),
1434 encoder,
1435 var
1436 )),
1437 Type::Tagged { tag, inner } => match tag.tagging {
1438 Tagging::Explicit => None,
1439 Tagging::Implicit => make_encode_call(inner, encoder, var),
1440 },
1441 Type::Constrained { base_type: inner, .. } => make_encode_call(inner, encoder, var),
1442 _ => None,
1443 }
1444}
1445
1446fn generate_field_decode(
1459 output: &mut String,
1460 ty: &Type,
1461 var_name: &str,
1462 indent: usize,
1463 defs: &[Definition],
1464) -> Result<(), Box<dyn std::error::Error>> {
1465 let ind = " ".repeat(indent);
1466
1467 if let Type::Tagged {
1474 tag: tag_info,
1475 inner,
1476 } = ty
1477 {
1478 if matches!(tag_info.tagging, Tagging::Implicit) {
1479 let concrete = resolve_to_base(inner, defs);
1480 match concrete {
1481 Type::Sequence(_) | Type::Set(_) | Type::SequenceOf(_, _) | Type::SetOf(_, _) => {
1482 let class = tag_class_c_str(&tag_info.class);
1496 match concrete {
1497 Type::Sequence(seq_fields) | Type::Set(seq_fields) => {
1498 let is_set = matches!(concrete, Type::Set(_));
1499 let ct_label = if is_set { "SET" } else { "SEQUENCE" };
1500 writeln!(
1501 output,
1502 "{}// IMPLICIT [{}]: enter as CONSTRUCTED, decode {} fields inline",
1503 ind, tag_info.number, ct_label
1504 )?;
1505 writeln!(output, "{}SyntaDecoder* nested_decoder = NULL;", ind)?;
1506 writeln!(output, "{}{{", ind)?;
1507 writeln!(output, "{} SyntaTag impl_tag;", ind)?;
1508 writeln!(output, "{} impl_tag.class_ = {};", ind, class)?;
1509 writeln!(output, "{} impl_tag.constructed = true;", ind)?;
1510 writeln!(output, "{} impl_tag.number = {};", ind, tag_info.number)?;
1511 writeln!(
1512 output,
1513 "{} err = synta_decoder_enter_constructed(seq_decoder, impl_tag, &nested_decoder);",
1514 ind
1515 )?;
1516 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
1517 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1518 writeln!(output, "{} return err;", ind)?;
1519 writeln!(output, "{} }}", ind)?;
1520 writeln!(output, "{}}}", ind)?;
1521 writeln!(output)?;
1522 for seq_field in seq_fields {
1523 if matches!(seq_field.ty, Type::Null) {
1524 continue;
1525 }
1526 let inner_name = to_snake_case(&seq_field.name);
1527 let nested_var = format!("{}.{}", var_name, inner_name);
1528 if seq_field.optional {
1529 let tag_check = get_tag_check_condition(&seq_field.ty, defs);
1530 writeln!(
1531 output,
1532 "{}// Decode optional nested field: {}",
1533 ind, seq_field.name
1534 )?;
1535 writeln!(output, "{}{{", ind)?;
1536 writeln!(output, "{} SyntaTag tag;", ind)?;
1537 writeln!(
1538 output,
1539 "{} if (synta_decoder_peek_tag(nested_decoder, &tag) == SyntaErrorCode_Success &&",
1540 ind
1541 )?;
1542 writeln!(output, "{} ({})) {{", ind, tag_check)?;
1543 let deeper_ind = format!("{} ", ind);
1544 generate_nested_inline_field_decode(
1545 output,
1546 &seq_field.ty,
1547 &nested_var,
1548 &deeper_ind,
1549 )?;
1550 writeln!(
1551 output,
1552 "{} {}.has_{} = true;",
1553 ind, var_name, inner_name
1554 )?;
1555 writeln!(output, "{} }} else {{", ind)?;
1556 writeln!(
1557 output,
1558 "{} {}.has_{} = false;",
1559 ind, var_name, inner_name
1560 )?;
1561 writeln!(output, "{} }}", ind)?;
1562 writeln!(output, "{}}}", ind)?;
1563 } else {
1564 writeln!(output, "{}// Decode field: {}", ind, seq_field.name)?;
1565 generate_nested_inline_field_decode(
1566 output,
1567 &seq_field.ty,
1568 &nested_var,
1569 &ind,
1570 )?;
1571 }
1572 writeln!(output)?;
1573 }
1574 writeln!(output, "{}synta_decoder_free(nested_decoder);", ind)?;
1575 return Ok(());
1576 }
1577 Type::SequenceOf(elem_ty, _) | Type::SetOf(elem_ty, _) => {
1578 let is_seq = matches!(concrete, Type::SequenceOf(_, _));
1579 let ct_label = if is_seq { "SEQUENCE OF" } else { "SET OF" };
1580 writeln!(
1581 output,
1582 "{}// IMPLICIT [{}]: enter as CONSTRUCTED, decode {} elements inline",
1583 ind, tag_info.number, ct_label
1584 )?;
1585 writeln!(output, "{}SyntaDecoder* array_decoder = NULL;", ind)?;
1586 writeln!(output, "{}{{", ind)?;
1587 writeln!(output, "{} SyntaTag impl_tag;", ind)?;
1588 writeln!(output, "{} impl_tag.class_ = {};", ind, class)?;
1589 writeln!(output, "{} impl_tag.constructed = true;", ind)?;
1590 writeln!(output, "{} impl_tag.number = {};", ind, tag_info.number)?;
1591 writeln!(
1592 output,
1593 "{} err = synta_decoder_enter_constructed(seq_decoder, impl_tag, &array_decoder);",
1594 ind
1595 )?;
1596 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
1597 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1598 writeln!(output, "{} return err;", ind)?;
1599 writeln!(output, "{} }}", ind)?;
1600 writeln!(output, "{}}}", ind)?;
1601 writeln!(output)?;
1602 let elem_c_type = get_c_type(elem_ty);
1603 let array_type = format!("{}*", elem_c_type);
1604 writeln!(output, "{}size_t capacity = 4;", ind)?;
1605 writeln!(output, "{}size_t count = 0;", ind)?;
1606 writeln!(
1607 output,
1608 "{}{} array = ({})calloc(capacity, sizeof({}));",
1609 ind, array_type, array_type, elem_c_type
1610 )?;
1611 writeln!(output, "{}if (array == NULL) {{", ind)?;
1612 writeln!(output, "{} synta_decoder_free(array_decoder);", ind)?;
1613 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1614 writeln!(output, "{} return SyntaErrorCode_OutOfMemory;", ind)?;
1615 writeln!(output, "{}}}", ind)?;
1616 writeln!(output)?;
1617 writeln!(
1618 output,
1619 "{}while (!synta_decoder_at_end(array_decoder)) {{",
1620 ind
1621 )?;
1622 writeln!(output, "{} if (count >= capacity) {{", ind)?;
1623 writeln!(output, "{} capacity *= 2;", ind)?;
1624 writeln!(
1625 output,
1626 "{} {} new_array = ({})realloc(array, capacity * sizeof({}));",
1627 ind, array_type, array_type, elem_c_type
1628 )?;
1629 writeln!(output, "{} if (new_array == NULL) {{", ind)?;
1630 writeln!(output, "{} free(array);", ind)?;
1631 writeln!(
1632 output,
1633 "{} synta_decoder_free(array_decoder);",
1634 ind
1635 )?;
1636 writeln!(
1637 output,
1638 "{} synta_decoder_free(seq_decoder);",
1639 ind
1640 )?;
1641 writeln!(
1642 output,
1643 "{} return SyntaErrorCode_OutOfMemory;",
1644 ind
1645 )?;
1646 writeln!(output, "{} }}", ind)?;
1647 writeln!(output, "{} array = new_array;", ind)?;
1648 writeln!(output, "{} }}", ind)?;
1649 writeln!(output)?;
1650 generate_decode_element(
1651 output,
1652 elem_ty,
1653 "array_decoder",
1654 "array[count]",
1655 " ",
1656 )?;
1657 writeln!(output, "{} count++;", ind)?;
1658 writeln!(output, "{}}}", ind)?;
1659 writeln!(output)?;
1660 writeln!(output, "{}{}.items = array;", ind, var_name)?;
1661 writeln!(output, "{}{}.count = count;", ind, var_name)?;
1662 writeln!(output, "{}synta_decoder_free(array_decoder);", ind)?;
1663 return Ok(());
1664 }
1665 _ => unreachable!(),
1666 }
1667 }
1668 _ => {
1669 let cls = match tag_info.class {
1672 TagClass::ContextSpecific => tag_info.number.to_string(),
1673 TagClass::Application => format!("APPLICATION {}", tag_info.number),
1674 TagClass::Universal => format!("UNIVERSAL {}", tag_info.number),
1675 TagClass::Private => format!("PRIVATE {}", tag_info.number),
1676 };
1677 writeln!(
1678 output,
1679 "{}/* IMPLICIT [{}]: primitive inner type decoded directly (tag check relaxed) */",
1680 ind, cls
1681 )?;
1682 }
1683 }
1684 }
1685 }
1686
1687 if let Some(call) = make_decode_call(ty, "seq_decoder", var_name) {
1688 writeln!(output, "{}err = {};", ind, call)?;
1689 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
1690 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1691 writeln!(output, "{} return err;", ind)?;
1692 writeln!(output, "{}}}", ind)?;
1693 } else {
1694 match ty {
1695 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
1696 let is_sequence = matches!(ty, Type::Sequence(_));
1697 let container_type = if is_sequence { "sequence" } else { "set" };
1698
1699 writeln!(
1700 output,
1701 "{}// Decode nested {}",
1702 ind,
1703 container_type.to_uppercase()
1704 )?;
1705 writeln!(output, "{}SyntaDecoder* nested_decoder = NULL;", ind)?;
1706 writeln!(
1707 output,
1708 "{}err = synta_decoder_enter_{}(seq_decoder, &nested_decoder);",
1709 ind, container_type
1710 )?;
1711 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
1712 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1713 writeln!(output, "{} return err;", ind)?;
1714 writeln!(output, "{}}}", ind)?;
1715 writeln!(output)?;
1716
1717 for inner_field in inner_fields {
1719 if matches!(inner_field.ty, Type::Null) {
1720 continue;
1721 }
1722
1723 let inner_name = to_snake_case(&inner_field.name);
1724 let nested_var = format!("{}.{}", var_name, inner_name);
1725 if inner_field.optional {
1726 writeln!(
1727 output,
1728 "{}// Decode optional nested field: {}",
1729 ind, inner_field.name
1730 )?;
1731 let tag_check = get_tag_check_condition(&inner_field.ty, defs);
1732 writeln!(output, "{}{{", ind)?;
1733 writeln!(output, "{} SyntaTag tag;", ind)?;
1734 writeln!(
1735 output,
1736 "{} if (synta_decoder_peek_tag(nested_decoder, &tag) == SyntaErrorCode_Success &&",
1737 ind
1738 )?;
1739 writeln!(output, "{} ({})) {{", ind, tag_check)?;
1740 let deeper_ind = format!("{} ", ind);
1741 generate_nested_inline_field_decode(
1742 output,
1743 &inner_field.ty,
1744 &nested_var,
1745 &deeper_ind,
1746 )?;
1747 writeln!(
1748 output,
1749 "{} {}.has_{} = true;",
1750 ind, var_name, inner_name
1751 )?;
1752 writeln!(output, "{} }} else {{", ind)?;
1753 writeln!(
1754 output,
1755 "{} {}.has_{} = false;",
1756 ind, var_name, inner_name
1757 )?;
1758 writeln!(output, "{} }}", ind)?;
1759 writeln!(output, "{}}}", ind)?;
1760 } else {
1761 writeln!(output, "{}// Decode field: {}", ind, inner_field.name)?;
1762 generate_nested_inline_field_decode(
1763 output,
1764 &inner_field.ty,
1765 &nested_var,
1766 &ind,
1767 )?;
1768 }
1769 writeln!(output)?;
1770 }
1771
1772 writeln!(output, "{}synta_decoder_free(nested_decoder);", ind)?;
1773 }
1774 Type::SequenceOf(inner_ty, _) | Type::SetOf(inner_ty, _) => {
1775 let is_sequence = matches!(ty, Type::SequenceOf(_, _));
1776 let container_type = if is_sequence { "sequence" } else { "set" };
1777
1778 writeln!(output, "{}// Decode SEQUENCE OF / SET OF", ind)?;
1779 writeln!(output, "{}SyntaDecoder* array_decoder = NULL;", ind)?;
1780 writeln!(
1781 output,
1782 "{}err = synta_decoder_enter_{}(seq_decoder, &array_decoder);",
1783 ind, container_type
1784 )?;
1785 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
1786 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1787 writeln!(output, "{} return err;", ind)?;
1788 writeln!(output, "{}}}", ind)?;
1789 writeln!(output)?;
1790
1791 writeln!(output, "{}// Allocate dynamic array for elements", ind)?;
1792 writeln!(output, "{}size_t capacity = 4; // Initial capacity", ind)?;
1793 writeln!(output, "{}size_t count = 0;", ind)?;
1794 let elem_c_type = get_c_type(inner_ty);
1795 let array_type = format!("{}*", elem_c_type); writeln!(
1797 output,
1798 "{}{} array = ({})calloc(capacity, sizeof({}));",
1799 ind, array_type, array_type, elem_c_type
1800 )?;
1801 writeln!(output, "{}if (array == NULL) {{", ind)?;
1802 writeln!(output, "{} synta_decoder_free(array_decoder);", ind)?;
1803 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1804 writeln!(output, "{} return SyntaErrorCode_OutOfMemory;", ind)?;
1805 writeln!(output, "{}}}", ind)?;
1806 writeln!(output)?;
1807
1808 writeln!(
1809 output,
1810 "{}while (!synta_decoder_at_end(array_decoder)) {{",
1811 ind
1812 )?;
1813 writeln!(output, "{} // Grow array if needed", ind)?;
1814 writeln!(output, "{} if (count >= capacity) {{", ind)?;
1815 writeln!(output, "{} capacity *= 2;", ind)?;
1816 writeln!(
1817 output,
1818 "{} {} new_array = ({})realloc(array, capacity * sizeof({}));",
1819 ind, array_type, array_type, elem_c_type
1820 )?;
1821 writeln!(output, "{} if (new_array == NULL) {{", ind)?;
1822 writeln!(output, "{} free(array);", ind)?;
1823 writeln!(
1824 output,
1825 "{} synta_decoder_free(array_decoder);",
1826 ind
1827 )?;
1828 writeln!(
1829 output,
1830 "{} synta_decoder_free(seq_decoder);",
1831 ind
1832 )?;
1833 writeln!(
1834 output,
1835 "{} return SyntaErrorCode_OutOfMemory;",
1836 ind
1837 )?;
1838 writeln!(output, "{} }}", ind)?;
1839 writeln!(output, "{} array = new_array;", ind)?;
1840 writeln!(output, "{} }}", ind)?;
1841 writeln!(output)?;
1842
1843 writeln!(output, "{} // Decode element", ind)?;
1845 generate_decode_element(output, inner_ty, "array_decoder", "array[count]", " ")?;
1846 writeln!(output, "{} count++;", ind)?;
1847 writeln!(output, "{}}}", ind)?;
1848 writeln!(output)?;
1849
1850 writeln!(output, "{}{} = array;", ind, var_name)?;
1851 writeln!(output, "{}{}_count = count;", ind, var_name)?;
1852 writeln!(output, "{}synta_decoder_free(array_decoder);", ind)?;
1853 }
1854 Type::Tagged {
1857 tag: tag_info,
1858 inner,
1859 } => match tag_info.tagging {
1860 Tagging::Explicit => {
1861 let class = tag_class_c_str(&tag_info.class);
1862 writeln!(
1863 output,
1864 "{}// Enter EXPLICIT [{cls} {num}] tag wrapper",
1865 ind,
1866 cls = class,
1867 num = tag_info.number
1868 )?;
1869 writeln!(output, "{}{{", ind)?;
1870 writeln!(output, "{} SyntaDecoder* tagged_decoder = NULL;", ind)?;
1871 writeln!(output, "{} SyntaTag explicit_tag;", ind)?;
1872 writeln!(output, "{} explicit_tag.class_ = {};", ind, class)?;
1873 writeln!(output, "{} explicit_tag.constructed = true;", ind)?;
1874 writeln!(
1875 output,
1876 "{} explicit_tag.number = {};",
1877 ind, tag_info.number
1878 )?;
1879 writeln!(
1880 output,
1881 "{} err = synta_decoder_enter_constructed(seq_decoder, explicit_tag, &tagged_decoder);",
1882 ind
1883 )?;
1884 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
1885 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1886 writeln!(output, "{} return err;", ind)?;
1887 writeln!(output, "{} }}", ind)?;
1888 if let Some(call) = make_decode_call(inner, "tagged_decoder", var_name) {
1889 writeln!(output, "{} err = {};", ind, call)?;
1890 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
1891 writeln!(output, "{} synta_decoder_free(tagged_decoder);", ind)?;
1892 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1893 writeln!(output, "{} return err;", ind)?;
1894 writeln!(output, "{} }}", ind)?;
1895 } else {
1896 writeln!(output, "{} /* structural inner type inside EXPLICIT tag: not yet supported */", ind)?;
1899 writeln!(output, "{} err = SyntaErrorCode_InvalidEncoding;", ind)?;
1900 writeln!(output, "{} synta_decoder_free(tagged_decoder);", ind)?;
1901 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1902 writeln!(output, "{} return err;", ind)?;
1903 }
1904 writeln!(output, "{} synta_decoder_free(tagged_decoder);", ind)?;
1905 writeln!(output, "{}}}", ind)?;
1906 }
1907 Tagging::Implicit => {
1908 let concrete = resolve_to_base(inner, defs);
1915 match concrete {
1916 Type::Sequence(seq_fields) | Type::Set(seq_fields) => {
1917 let class = tag_class_c_str(&tag_info.class);
1918 let is_set = matches!(concrete, Type::Set(_));
1919 let ct_label = if is_set { "SET" } else { "SEQUENCE" };
1920 writeln!(
1921 output,
1922 "{}// IMPLICIT [{}]: enter as CONSTRUCTED, decode {} fields inline",
1923 ind, tag_info.number, ct_label
1924 )?;
1925 writeln!(output, "{}SyntaDecoder* nested_decoder = NULL;", ind)?;
1926 writeln!(output, "{}{{", ind)?;
1927 writeln!(output, "{} SyntaTag impl_tag;", ind)?;
1928 writeln!(output, "{} impl_tag.class_ = {};", ind, class)?;
1929 writeln!(output, "{} impl_tag.constructed = true;", ind)?;
1930 writeln!(output, "{} impl_tag.number = {};", ind, tag_info.number)?;
1931 writeln!(
1932 output,
1933 "{} err = synta_decoder_enter_constructed(seq_decoder, impl_tag, &nested_decoder);",
1934 ind
1935 )?;
1936 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
1937 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
1938 writeln!(output, "{} return err;", ind)?;
1939 writeln!(output, "{} }}", ind)?;
1940 writeln!(output, "{}}}", ind)?;
1941 writeln!(output)?;
1942 for seq_field in seq_fields {
1943 if matches!(seq_field.ty, Type::Null) {
1944 continue;
1945 }
1946 let inner_name = to_snake_case(&seq_field.name);
1947 let nested_var = format!("{}.{}", var_name, inner_name);
1948 if seq_field.optional {
1949 let tag_check = get_tag_check_condition(&seq_field.ty, defs);
1950 writeln!(
1951 output,
1952 "{}// Decode optional nested field: {}",
1953 ind, seq_field.name
1954 )?;
1955 writeln!(output, "{}{{", ind)?;
1956 writeln!(output, "{} SyntaTag tag;", ind)?;
1957 writeln!(
1958 output,
1959 "{} if (synta_decoder_peek_tag(nested_decoder, &tag) == SyntaErrorCode_Success &&",
1960 ind
1961 )?;
1962 writeln!(output, "{} ({})) {{", ind, tag_check)?;
1963 let deeper_ind = format!("{} ", ind);
1964 generate_nested_inline_field_decode(
1965 output,
1966 &seq_field.ty,
1967 &nested_var,
1968 &deeper_ind,
1969 )?;
1970 writeln!(
1971 output,
1972 "{} {}.has_{} = true;",
1973 ind, var_name, inner_name
1974 )?;
1975 writeln!(output, "{} }} else {{", ind)?;
1976 writeln!(
1977 output,
1978 "{} {}.has_{} = false;",
1979 ind, var_name, inner_name
1980 )?;
1981 writeln!(output, "{} }}", ind)?;
1982 writeln!(output, "{}}}", ind)?;
1983 } else {
1984 writeln!(output, "{}// Decode field: {}", ind, seq_field.name)?;
1985 generate_nested_inline_field_decode(
1986 output,
1987 &seq_field.ty,
1988 &nested_var,
1989 &ind,
1990 )?;
1991 }
1992 writeln!(output)?;
1993 }
1994 writeln!(output, "{}synta_decoder_free(nested_decoder);", ind)?;
1995 }
1996 Type::SequenceOf(elem_ty, _) | Type::SetOf(elem_ty, _) => {
1997 let class = tag_class_c_str(&tag_info.class);
1998 let is_seq = matches!(concrete, Type::SequenceOf(_, _));
1999 let ct_label = if is_seq { "SEQUENCE OF" } else { "SET OF" };
2000 writeln!(
2001 output,
2002 "{}// IMPLICIT [{}]: enter as CONSTRUCTED, decode {} elements inline",
2003 ind, tag_info.number, ct_label
2004 )?;
2005 writeln!(output, "{}SyntaDecoder* array_decoder = NULL;", ind)?;
2006 writeln!(output, "{}{{", ind)?;
2007 writeln!(output, "{} SyntaTag impl_tag;", ind)?;
2008 writeln!(output, "{} impl_tag.class_ = {};", ind, class)?;
2009 writeln!(output, "{} impl_tag.constructed = true;", ind)?;
2010 writeln!(output, "{} impl_tag.number = {};", ind, tag_info.number)?;
2011 writeln!(
2012 output,
2013 "{} err = synta_decoder_enter_constructed(seq_decoder, impl_tag, &array_decoder);",
2014 ind
2015 )?;
2016 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
2017 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
2018 writeln!(output, "{} return err;", ind)?;
2019 writeln!(output, "{} }}", ind)?;
2020 writeln!(output, "{}}}", ind)?;
2021 writeln!(output)?;
2022 let elem_c_type = get_c_type(elem_ty);
2023 let array_type = format!("{}*", elem_c_type);
2024 writeln!(output, "{}size_t capacity = 4;", ind)?;
2025 writeln!(output, "{}size_t count = 0;", ind)?;
2026 writeln!(
2027 output,
2028 "{}{} array = ({})calloc(capacity, sizeof({}));",
2029 ind, array_type, array_type, elem_c_type
2030 )?;
2031 writeln!(output, "{}if (array == NULL) {{", ind)?;
2032 writeln!(output, "{} synta_decoder_free(array_decoder);", ind)?;
2033 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
2034 writeln!(output, "{} return SyntaErrorCode_OutOfMemory;", ind)?;
2035 writeln!(output, "{}}}", ind)?;
2036 writeln!(output)?;
2037 writeln!(
2038 output,
2039 "{}while (!synta_decoder_at_end(array_decoder)) {{",
2040 ind
2041 )?;
2042 writeln!(output, "{} if (count >= capacity) {{", ind)?;
2043 writeln!(output, "{} capacity *= 2;", ind)?;
2044 writeln!(
2045 output,
2046 "{} {} new_array = ({})realloc(array, capacity * sizeof({}));",
2047 ind, array_type, array_type, elem_c_type
2048 )?;
2049 writeln!(output, "{} if (new_array == NULL) {{", ind)?;
2050 writeln!(output, "{} free(array);", ind)?;
2051 writeln!(
2052 output,
2053 "{} synta_decoder_free(array_decoder);",
2054 ind
2055 )?;
2056 writeln!(
2057 output,
2058 "{} synta_decoder_free(seq_decoder);",
2059 ind
2060 )?;
2061 writeln!(
2062 output,
2063 "{} return SyntaErrorCode_OutOfMemory;",
2064 ind
2065 )?;
2066 writeln!(output, "{} }}", ind)?;
2067 writeln!(output, "{} array = new_array;", ind)?;
2068 writeln!(output, "{} }}", ind)?;
2069 writeln!(output)?;
2070 generate_decode_element(
2071 output,
2072 elem_ty,
2073 "array_decoder",
2074 "array[count]",
2075 " ",
2076 )?;
2077 writeln!(output, "{} count++;", ind)?;
2078 writeln!(output, "{}}}", ind)?;
2079 writeln!(output)?;
2080 writeln!(output, "{}{}.items = array;", ind, var_name)?;
2081 writeln!(output, "{}{}.count = count;", ind, var_name)?;
2082 writeln!(output, "{}synta_decoder_free(array_decoder);", ind)?;
2083 }
2084 _ => {
2085 generate_field_decode(output, inner, var_name, indent, defs)?;
2087 }
2088 }
2089 }
2090 },
2091 Type::Constrained {
2092 base_type: inner, ..
2093 } => {
2094 generate_field_decode(output, inner, var_name, indent, defs)?;
2095 }
2096 _ => {
2097 writeln!(
2098 output,
2099 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported field type */",
2100 ind
2101 )?;
2102 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
2103 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
2104 writeln!(output, "{} return err;", ind)?;
2105 writeln!(output, "{}}}", ind)?;
2106 }
2107 }
2108 } Ok(())
2111}
2112
2113fn generate_field_encode(
2122 output: &mut String,
2123 ty: &Type,
2124 var_name: &str,
2125 encoder_name: &str,
2126 indent: usize,
2127 ctx: &EncodeCtx<'_>,
2128) -> Result<(), Box<dyn std::error::Error>> {
2129 let ind = " ".repeat(indent);
2130
2131 if let Type::Constrained {
2133 base_type: inner,
2134 constraint,
2135 } = ty
2136 {
2137 emit_constraint_validation(
2138 output,
2139 constraint,
2140 inner,
2141 var_name,
2142 &ind,
2143 ctx.mode,
2144 ctx.with_containing,
2145 )?;
2146 return generate_field_encode(output, inner, var_name, encoder_name, indent, ctx);
2147 }
2148
2149 if let Type::Tagged {
2154 tag: tag_info,
2155 inner,
2156 } = ty
2157 {
2158 if matches!(tag_info.tagging, Tagging::Implicit) {
2159 let concrete = resolve_to_base(inner, ctx.defs);
2160 match concrete {
2161 Type::Sequence(seq_fields) | Type::Set(seq_fields) => {
2162 let class = tag_class_c_str(&tag_info.class);
2163 let is_set = matches!(concrete, Type::Set(_));
2164 let ct_label = if is_set { "SET" } else { "SEQUENCE" };
2165 writeln!(
2166 output,
2167 "{}// IMPLICIT [{}]: start CONSTRUCTED, encode {} fields inline",
2168 ind, tag_info.number, ct_label
2169 )?;
2170 writeln!(output, "{}SyntaEncoder* nested_encoder = NULL;", ind)?;
2171 writeln!(output, "{}{{", ind)?;
2172 writeln!(output, "{} SyntaTag impl_tag;", ind)?;
2173 writeln!(output, "{} impl_tag.class_ = {};", ind, class)?;
2174 writeln!(output, "{} impl_tag.constructed = true;", ind)?;
2175 writeln!(output, "{} impl_tag.number = {};", ind, tag_info.number)?;
2176 writeln!(
2177 output,
2178 "{} err = synta_encoder_start_constructed({}, impl_tag, &nested_encoder);",
2179 ind, encoder_name
2180 )?;
2181 writeln!(
2182 output,
2183 "{} if (err != SyntaErrorCode_Success) return err;",
2184 ind
2185 )?;
2186 writeln!(output, "{}}}", ind)?;
2187 for seq_field in seq_fields {
2188 if matches!(seq_field.ty, Type::Null) {
2189 continue;
2190 }
2191 let inner_name = to_snake_case(&seq_field.name);
2192 let nested_var = format!("{}.{}", var_name, inner_name);
2193 let field_ind = if seq_field.optional {
2194 writeln!(output, "{}if ({}.has_{}) {{", ind, var_name, inner_name)?;
2195 format!("{} ", ind)
2196 } else {
2197 ind.clone()
2198 };
2199 generate_nested_inline_field_encode(
2200 output,
2201 &seq_field.ty,
2202 &nested_var,
2203 &field_ind,
2204 )?;
2205 if seq_field.optional {
2206 writeln!(output, "{}}}", ind)?;
2207 }
2208 }
2209 writeln!(output)?;
2210 writeln!(
2211 output,
2212 "{}err = synta_encoder_end_constructed(nested_encoder);",
2213 ind
2214 )?;
2215 writeln!(
2216 output,
2217 "{}if (err != SyntaErrorCode_Success) return err;",
2218 ind
2219 )?;
2220 return Ok(());
2221 }
2222 Type::SequenceOf(elem_ty, _) | Type::SetOf(elem_ty, _) => {
2223 let class = tag_class_c_str(&tag_info.class);
2224 let is_seq = matches!(concrete, Type::SequenceOf(_, _));
2225 let ct_label = if is_seq { "SEQUENCE OF" } else { "SET OF" };
2226 writeln!(
2227 output,
2228 "{}// IMPLICIT [{}]: start CONSTRUCTED, encode {} elements inline",
2229 ind, tag_info.number, ct_label
2230 )?;
2231 writeln!(output, "{}SyntaEncoder* array_encoder = NULL;", ind)?;
2232 writeln!(output, "{}{{", ind)?;
2233 writeln!(output, "{} SyntaTag impl_tag;", ind)?;
2234 writeln!(output, "{} impl_tag.class_ = {};", ind, class)?;
2235 writeln!(output, "{} impl_tag.constructed = true;", ind)?;
2236 writeln!(output, "{} impl_tag.number = {};", ind, tag_info.number)?;
2237 writeln!(
2238 output,
2239 "{} err = synta_encoder_start_constructed({}, impl_tag, &array_encoder);",
2240 ind, encoder_name
2241 )?;
2242 writeln!(
2243 output,
2244 "{} if (err != SyntaErrorCode_Success) return err;",
2245 ind
2246 )?;
2247 writeln!(output, "{}}}", ind)?;
2248 writeln!(output)?;
2249 writeln!(
2250 output,
2251 "{}for (size_t i = 0; i < {}.count; i++) {{",
2252 ind, var_name
2253 )?;
2254 generate_encode_element_field(
2255 output,
2256 elem_ty,
2257 "array_encoder",
2258 &format!("{}.items[i]", var_name),
2259 " ",
2260 )?;
2261 writeln!(output, "{}}}", ind)?;
2262 writeln!(output)?;
2263 writeln!(
2264 output,
2265 "{}err = synta_encoder_end_constructed(array_encoder);",
2266 ind
2267 )?;
2268 writeln!(
2269 output,
2270 "{}if (err != SyntaErrorCode_Success) return err;",
2271 ind
2272 )?;
2273 return Ok(());
2274 }
2275 _ => {
2276 let cls = match tag_info.class {
2278 TagClass::ContextSpecific => tag_info.number.to_string(),
2279 TagClass::Application => format!("APPLICATION {}", tag_info.number),
2280 TagClass::Universal => format!("UNIVERSAL {}", tag_info.number),
2281 TagClass::Private => format!("PRIVATE {}", tag_info.number),
2282 };
2283 writeln!(
2284 output,
2285 "{}/* IMPLICIT [{}]: primitive inner type encoded directly */",
2286 ind, cls
2287 )?;
2288 }
2289 }
2290 }
2291 }
2292
2293 if let Some(call) = make_encode_call(ty, encoder_name, var_name) {
2294 writeln!(output, "{}err = {};", ind, call)?;
2295 writeln!(
2296 output,
2297 "{}if (err != SyntaErrorCode_Success) return err;",
2298 ind
2299 )?;
2300 } else {
2301 match ty {
2302 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
2303 let is_sequence = matches!(ty, Type::Sequence(_));
2304 let container_type = if is_sequence { "sequence" } else { "set" };
2305
2306 writeln!(
2307 output,
2308 "{}// Encode nested {}",
2309 ind,
2310 container_type.to_uppercase()
2311 )?;
2312 writeln!(output, "{}SyntaEncoder* nested_encoder = NULL;", ind)?;
2313 writeln!(
2314 output,
2315 "{}err = synta_encoder_start_{}({}, &nested_encoder);",
2316 ind, container_type, encoder_name
2317 )?;
2318 writeln!(
2319 output,
2320 "{}if (err != SyntaErrorCode_Success) return err;",
2321 ind
2322 )?;
2323 writeln!(output)?;
2324
2325 for inner_field in inner_fields {
2327 if matches!(inner_field.ty, Type::Null) {
2328 continue;
2329 }
2330
2331 let inner_name = to_snake_case(&inner_field.name);
2332 let nested_var = format!("{}.{}", var_name, inner_name);
2333 let field_ind = if inner_field.optional {
2334 writeln!(output, "{}if ({}.has_{}) {{", ind, var_name, inner_name)?;
2335 format!("{} ", ind)
2336 } else {
2337 ind.clone()
2338 };
2339 generate_nested_inline_field_encode(
2340 output,
2341 &inner_field.ty,
2342 &nested_var,
2343 &field_ind,
2344 )?;
2345 if inner_field.optional {
2346 writeln!(output, "{}}}", ind)?;
2347 }
2348 }
2349 writeln!(output)?;
2350
2351 writeln!(
2352 output,
2353 "{}err = synta_encoder_end_constructed(nested_encoder);",
2354 ind
2355 )?;
2356 writeln!(
2357 output,
2358 "{}if (err != SyntaErrorCode_Success) return err;",
2359 ind
2360 )?;
2361 }
2362 Type::SequenceOf(inner_ty, _) | Type::SetOf(inner_ty, _) => {
2363 let is_sequence = matches!(ty, Type::SequenceOf(_, _));
2364 let container_type = if is_sequence { "sequence" } else { "set" };
2365
2366 writeln!(output, "{}// Encode SEQUENCE OF / SET OF", ind)?;
2367 writeln!(output, "{}SyntaEncoder* array_encoder = NULL;", ind)?;
2368 writeln!(
2369 output,
2370 "{}err = synta_encoder_start_{}({}, &array_encoder);",
2371 ind, container_type, encoder_name
2372 )?;
2373 writeln!(
2374 output,
2375 "{}if (err != SyntaErrorCode_Success) return err;",
2376 ind
2377 )?;
2378 writeln!(output)?;
2379
2380 writeln!(output, "{}// Encode each element", ind)?;
2381 writeln!(
2382 output,
2383 "{}for (size_t i = 0; i < {}_count; i++) {{",
2384 ind, var_name
2385 )?;
2386 generate_encode_element_field(
2387 output,
2388 inner_ty,
2389 "array_encoder",
2390 &format!("{}[i]", var_name),
2391 " ",
2392 )?;
2393 writeln!(output, "{}}}", ind)?;
2394 writeln!(output)?;
2395
2396 writeln!(
2397 output,
2398 "{}err = synta_encoder_end_constructed(array_encoder);",
2399 ind
2400 )?;
2401 writeln!(
2402 output,
2403 "{}if (err != SyntaErrorCode_Success) return err;",
2404 ind
2405 )?;
2406 }
2407 Type::Tagged {
2410 tag: tag_info,
2411 inner,
2412 } => match tag_info.tagging {
2413 Tagging::Explicit => {
2414 let class = tag_class_c_str(&tag_info.class);
2415 writeln!(
2416 output,
2417 "{}// Wrap in EXPLICIT [{cls} {num}] tag",
2418 ind,
2419 cls = class,
2420 num = tag_info.number
2421 )?;
2422 writeln!(output, "{}{{", ind)?;
2423 writeln!(output, "{} SyntaEncoder* tagged_encoder = NULL;", ind)?;
2424 writeln!(output, "{} SyntaTag explicit_tag;", ind)?;
2425 writeln!(output, "{} explicit_tag.class_ = {};", ind, class)?;
2426 writeln!(output, "{} explicit_tag.constructed = true;", ind)?;
2427 writeln!(
2428 output,
2429 "{} explicit_tag.number = {};",
2430 ind, tag_info.number
2431 )?;
2432 writeln!(
2433 output,
2434 "{} err = synta_encoder_start_constructed({}, explicit_tag, &tagged_encoder);",
2435 ind, encoder_name
2436 )?;
2437 writeln!(
2438 output,
2439 "{} if (err != SyntaErrorCode_Success) return err;",
2440 ind
2441 )?;
2442 if let Some(call) = make_encode_call(inner, "tagged_encoder", var_name) {
2443 writeln!(output, "{} err = {};", ind, call)?;
2444 writeln!(
2445 output,
2446 "{} if (err != SyntaErrorCode_Success) return err;",
2447 ind
2448 )?;
2449 } else {
2450 writeln!(output, "{} /* structural inner type inside EXPLICIT tag: not yet supported */", ind)?;
2451 writeln!(output, "{} return SyntaErrorCode_InvalidEncoding;", ind)?;
2452 }
2453 writeln!(
2454 output,
2455 "{} err = synta_encoder_end_constructed(tagged_encoder);",
2456 ind
2457 )?;
2458 writeln!(
2459 output,
2460 "{} if (err != SyntaErrorCode_Success) return err;",
2461 ind
2462 )?;
2463 writeln!(output, "{}}}", ind)?;
2464 }
2465 Tagging::Implicit => {
2466 generate_field_encode(output, inner, var_name, encoder_name, indent, ctx)?;
2469 }
2470 },
2471 _ => {
2472 writeln!(
2473 output,
2474 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported field type */",
2475 ind
2476 )?;
2477 writeln!(
2478 output,
2479 "{}if (err != SyntaErrorCode_Success) return err;",
2480 ind
2481 )?;
2482 }
2483 }
2484 } Ok(())
2487}
2488
2489fn emit_array_size_check(
2496 output: &mut String,
2497 bounds: ArraySizeBounds,
2498 count_var: &str,
2499) -> Result<(), Box<dyn std::error::Error>> {
2500 let (min, max) = bounds;
2501 let mut conditions: Vec<String> = Vec::new();
2502 if let Some(n) = min {
2503 if n > 0 {
2504 conditions.push(format!("{} < (size_t){}ULL", count_var, n));
2505 }
2506 }
2508 if let Some(n) = max {
2509 conditions.push(format!("{} > (size_t){}ULL", count_var, n));
2510 }
2511 if !conditions.is_empty() {
2512 writeln!(output, " // Validate SIZE constraint on collection")?;
2513 writeln!(output, " if ({}) {{", conditions.join(" || "))?;
2514 writeln!(output, " free(array);")?;
2515 writeln!(output, " synta_decoder_free(array_decoder);")?;
2516 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
2517 writeln!(output, " }}")?;
2518 }
2519 Ok(())
2520}
2521
2522fn emit_array_size_check_encode(
2528 output: &mut String,
2529 bounds: ArraySizeBounds,
2530 count_var: &str,
2531) -> Result<(), Box<dyn std::error::Error>> {
2532 let (min, max) = bounds;
2533 let mut conditions: Vec<String> = Vec::new();
2534 if let Some(n) = min {
2535 if n > 0 {
2536 conditions.push(format!("{} < (size_t){}ULL", count_var, n));
2537 }
2538 }
2539 if let Some(n) = max {
2540 conditions.push(format!("{} > (size_t){}ULL", count_var, n));
2541 }
2542 if !conditions.is_empty() {
2543 writeln!(output, " // Validate SIZE constraint before encoding")?;
2544 writeln!(output, " if ({}) {{", conditions.join(" || "))?;
2545 writeln!(output, " return SyntaErrorCode_InvalidArgument;")?;
2546 writeln!(output, " }}")?;
2547 }
2548 Ok(())
2549}
2550
2551fn emit_permitted_alphabet_validation(
2562 output: &mut String,
2563 ranges: &[CharRange],
2564 var_name: &str,
2565 ind: &str,
2566) -> Result<(), Box<dyn std::error::Error>> {
2567 let alpha_expr = generate_c_alphabet_expr(ranges);
2568 writeln!(
2569 output,
2570 "{}// Validate FROM (permitted alphabet) constraint",
2571 ind
2572 )?;
2573 writeln!(output, "{}{{", ind)?;
2574 writeln!(
2575 output,
2576 "{} size_t _alen = synta_octet_string_len({});",
2577 ind, var_name
2578 )?;
2579 writeln!(
2580 output,
2581 "{} const unsigned char* _ap = (const unsigned char*)synta_octet_string_data({});",
2582 ind, var_name
2583 )?;
2584 writeln!(output, "{} size_t _ai;", ind)?;
2585 writeln!(output, "{} for (_ai = 0; _ai < _alen; _ai++) {{", ind)?;
2586 writeln!(output, "{} unsigned char _c = _ap[_ai];", ind)?;
2587 writeln!(
2588 output,
2589 "{} if (!({alpha})) return SyntaErrorCode_InvalidArgument;",
2590 ind,
2591 alpha = alpha_expr
2592 )?;
2593 writeln!(output, "{} }}", ind)?;
2594 writeln!(output, "{}}}", ind)?;
2595 Ok(())
2596}
2597
2598fn emit_constraint_validation(
2609 output: &mut String,
2610 constraint: &Constraint,
2611 base_type: &Type,
2612 var_name: &str,
2613 ind: &str,
2614 mode: &PatternMode,
2615 with_containing: bool,
2616) -> Result<(), Box<dyn std::error::Error>> {
2617 if let ConstraintSpec::Subtype(ref spec) = constraint.spec {
2618 emit_subtype_constraint_validation(
2619 output,
2620 spec,
2621 base_type,
2622 var_name,
2623 ind,
2624 mode,
2625 with_containing,
2626 )?;
2627 }
2628 Ok(())
2630}
2631
2632fn emit_subtype_constraint_validation(
2634 output: &mut String,
2635 spec: &SubtypeConstraint,
2636 base_type: &Type,
2637 var_name: &str,
2638 ind: &str,
2639 mode: &PatternMode,
2640 with_containing: bool,
2641) -> Result<(), Box<dyn std::error::Error>> {
2642 let actual_base = unwrap_type(base_type);
2643 match spec {
2644 SubtypeConstraint::ValueRange { min, max } => {
2645 if matches!(actual_base, Type::Integer(_, _)) {
2646 writeln!(output, "{}// Validate INTEGER range constraint", ind)?;
2647 writeln!(output, "{}{{", ind)?;
2648 writeln!(output, "{} int64_t _constraint_val;", ind)?;
2649 writeln!(
2650 output,
2651 "{} err = synta_integer_to_i64({}, &_constraint_val);",
2652 ind, var_name
2653 )?;
2654 writeln!(
2655 output,
2656 "{} if (err != SyntaErrorCode_Success) return err;",
2657 ind
2658 )?;
2659 if let ConstraintValue::Integer(n) = min {
2660 writeln!(
2661 output,
2662 "{} if (_constraint_val < {}LL) return SyntaErrorCode_InvalidArgument;",
2663 ind, n
2664 )?;
2665 }
2666 if let ConstraintValue::Integer(n) = max {
2667 writeln!(
2668 output,
2669 "{} if (_constraint_val > {}LL) return SyntaErrorCode_InvalidArgument;",
2670 ind, n
2671 )?;
2672 }
2673 writeln!(output, "{}}}", ind)?;
2674 }
2675 }
2676 SubtypeConstraint::SingleValue(val) => {
2677 if matches!(actual_base, Type::Integer(_, _)) {
2678 if let ConstraintValue::Integer(n) = val {
2679 writeln!(output, "{}// Validate INTEGER single-value constraint", ind)?;
2680 writeln!(output, "{}{{", ind)?;
2681 writeln!(output, "{} int64_t _constraint_val;", ind)?;
2682 writeln!(
2683 output,
2684 "{} err = synta_integer_to_i64({}, &_constraint_val);",
2685 ind, var_name
2686 )?;
2687 writeln!(
2688 output,
2689 "{} if (err != SyntaErrorCode_Success) return err;",
2690 ind
2691 )?;
2692 writeln!(
2693 output,
2694 "{} if (_constraint_val != {}LL) return SyntaErrorCode_InvalidArgument;",
2695 ind, n
2696 )?;
2697 writeln!(output, "{}}}", ind)?;
2698 }
2699 }
2700 }
2701 SubtypeConstraint::SizeConstraint(inner_spec) => match actual_base {
2702 Type::OctetString(_)
2703 | Type::Utf8String(_)
2704 | Type::PrintableString(_)
2705 | Type::IA5String(_)
2706 | Type::Any
2707 | Type::AnyDefinedBy(_) => {
2708 emit_size_constraint_validation(output, inner_spec, var_name, ind)?;
2709 }
2710 _ => {}
2711 },
2712 SubtypeConstraint::PermittedAlphabet(ranges) => {
2713 if matches!(
2714 actual_base,
2715 Type::OctetString(_)
2716 | Type::Utf8String(_)
2717 | Type::PrintableString(_)
2718 | Type::IA5String(_)
2719 ) {
2720 emit_permitted_alphabet_validation(output, ranges, var_name, ind)?;
2721 }
2722 }
2723 SubtypeConstraint::Intersection(parts) => {
2724 for part in parts {
2727 emit_subtype_constraint_validation(
2728 output,
2729 part,
2730 base_type,
2731 var_name,
2732 ind,
2733 mode,
2734 with_containing,
2735 )?;
2736 }
2737 }
2738 SubtypeConstraint::Union(_) => {
2739 writeln!(
2740 output,
2741 "{}/* UNION constraint: validation not generated */",
2742 ind
2743 )?;
2744 }
2745 SubtypeConstraint::ContainedSubtype(inner_ty) => {
2746 let is_byte_string = matches!(
2747 actual_base,
2748 Type::OctetString(_) | Type::Any | Type::AnyDefinedBy(_)
2749 );
2750 if is_byte_string {
2751 if with_containing {
2752 emit_containing_validation(output, inner_ty, var_name, ind)?;
2753 } else {
2754 writeln!(
2755 output,
2756 "{}/* CONTAINING constraint skipped; use --with-containing to enable validation */",
2757 ind
2758 )?;
2759 }
2760 }
2761 }
2762 SubtypeConstraint::Pattern(p) => {
2763 let is_string = matches!(
2764 unwrap_type(base_type),
2765 Type::OctetString(_)
2766 | Type::Utf8String(_)
2767 | Type::PrintableString(_)
2768 | Type::IA5String(_)
2769 );
2770 if is_string {
2771 match mode {
2772 PatternMode::Skip => {
2773 writeln!(
2774 output,
2775 "{}/* PATTERN constraint \"{}\" skipped; compile with --with-regex for validation */",
2776 ind, p
2777 )?;
2778 }
2779 PatternMode::Posix => {
2780 emit_posix_pattern_validation(output, p, var_name, ind)?;
2781 }
2782 PatternMode::Pcre2 => {
2783 emit_pcre2_pattern_validation(output, p, var_name, ind)?;
2784 }
2785 }
2786 }
2787 }
2788 _ => {}
2790 }
2791 Ok(())
2792}
2793
2794fn emit_posix_pattern_validation(
2802 output: &mut String,
2803 pattern: &str,
2804 var_name: &str,
2805 ind: &str,
2806) -> Result<(), Box<dyn std::error::Error>> {
2807 let escaped = pattern.replace('\\', "\\\\").replace('"', "\\\"");
2809 writeln!(
2810 output,
2811 "{}// Validate PATTERN constraint \"{}\" (POSIX ERE)",
2812 ind, pattern
2813 )?;
2814 writeln!(output, "{}{{", ind)?;
2815 writeln!(
2816 output,
2817 "{} size_t _plen = synta_octet_string_len({});",
2818 ind, var_name
2819 )?;
2820 writeln!(output, "{} char* _pstr = (char*)malloc(_plen + 1);", ind)?;
2821 writeln!(
2822 output,
2823 "{} if (_pstr == NULL) return SyntaErrorCode_OutOfMemory;",
2824 ind
2825 )?;
2826 writeln!(
2827 output,
2828 "{} memcpy(_pstr, synta_octet_string_data({}), _plen);",
2829 ind, var_name
2830 )?;
2831 writeln!(output, "{} _pstr[_plen] = '\\0';", ind)?;
2832 writeln!(output, "{} regex_t _pre;", ind)?;
2833 writeln!(
2834 output,
2835 "{} int _prc = regcomp(&_pre, \"{}\", REG_EXTENDED | REG_NOSUB);",
2836 ind, escaped
2837 )?;
2838 writeln!(output, "{} if (_prc == 0) {{", ind)?;
2839 writeln!(
2840 output,
2841 "{} _prc = regexec(&_pre, _pstr, 0, NULL, 0);",
2842 ind
2843 )?;
2844 writeln!(output, "{} regfree(&_pre);", ind)?;
2845 writeln!(output, "{} }}", ind)?;
2846 writeln!(output, "{} free(_pstr);", ind)?;
2847 writeln!(
2848 output,
2849 "{} if (_prc != 0) return SyntaErrorCode_InvalidArgument;",
2850 ind
2851 )?;
2852 writeln!(output, "{}}}", ind)?;
2853 Ok(())
2854}
2855
2856fn emit_pcre2_pattern_validation(
2863 output: &mut String,
2864 pattern: &str,
2865 var_name: &str,
2866 ind: &str,
2867) -> Result<(), Box<dyn std::error::Error>> {
2868 let escaped = pattern.replace('\\', "\\\\").replace('"', "\\\"");
2869 writeln!(
2870 output,
2871 "{}// Validate PATTERN constraint \"{}\" (PCRE2)",
2872 ind, pattern
2873 )?;
2874 writeln!(output, "{}{{", ind)?;
2875 writeln!(output, "{} int _perr;", ind)?;
2876 writeln!(output, "{} PCRE2_SIZE _perr_ofs;", ind)?;
2877 writeln!(
2878 output,
2879 "{} size_t _plen = synta_octet_string_len({});",
2880 ind, var_name
2881 )?;
2882 writeln!(
2883 output,
2884 "{} const PCRE2_UCHAR8* _pdata = (const PCRE2_UCHAR8*)synta_octet_string_data({});",
2885 ind, var_name
2886 )?;
2887 writeln!(
2888 output,
2889 "{} pcre2_code* _pcode = pcre2_compile((PCRE2_SPTR8)\"{}\", PCRE2_ZERO_TERMINATED, 0, &_perr, &_perr_ofs, NULL);",
2890 ind, escaped
2891 )?;
2892 writeln!(output, "{} if (_pcode != NULL) {{", ind)?;
2893 writeln!(
2894 output,
2895 "{} pcre2_match_data* _pmatch = pcre2_match_data_create_from_pattern(_pcode, NULL);",
2896 ind
2897 )?;
2898 writeln!(
2899 output,
2900 "{} int _prc = (int)pcre2_match(_pcode, _pdata, _plen, 0, 0, _pmatch, NULL);",
2901 ind
2902 )?;
2903 writeln!(output, "{} pcre2_match_data_free(_pmatch);", ind)?;
2904 writeln!(output, "{} pcre2_code_free(_pcode);", ind)?;
2905 writeln!(
2906 output,
2907 "{} if (_prc < 0) return SyntaErrorCode_InvalidArgument;",
2908 ind
2909 )?;
2910 writeln!(output, "{} }}", ind)?;
2911 writeln!(output, "{}}}", ind)?;
2912 Ok(())
2913}
2914
2915fn emit_containing_validation(
2924 output: &mut String,
2925 inner_type: &Type,
2926 var_name: &str,
2927 ind: &str,
2928) -> Result<(), Box<dyn std::error::Error>> {
2929 let (inner_c_type, inner_fn) = match inner_type {
2931 Type::TypeRef(name) => (to_pascal_case(name), to_snake_case(name)),
2932 _ => {
2933 writeln!(
2934 output,
2935 "{}/* CONTAINING (built-in type): validation not generated */",
2936 ind
2937 )?;
2938 return Ok(());
2939 }
2940 };
2941 writeln!(
2942 output,
2943 "{}// Validate CONTAINING constraint ({})",
2944 ind, inner_c_type
2945 )?;
2946 writeln!(output, "{}{{", ind)?;
2947 writeln!(
2948 output,
2949 "{} SyntaDecoder* _inner_dec = synta_decoder_new(",
2950 ind
2951 )?;
2952 writeln!(
2953 output,
2954 "{} synta_octet_string_data({}),",
2955 ind, var_name
2956 )?;
2957 writeln!(
2958 output,
2959 "{} (uint32_t)synta_octet_string_len({}),",
2960 ind, var_name
2961 )?;
2962 writeln!(output, "{} SyntaEncoding_Der);", ind)?;
2963 writeln!(
2964 output,
2965 "{} if (_inner_dec == NULL) return SyntaErrorCode_OutOfMemory;",
2966 ind
2967 )?;
2968 writeln!(output, "{} {} _inner_val;", ind, inner_c_type)?;
2969 writeln!(
2970 output,
2971 "{} SyntaErrorCode _inner_err = {}_decode(_inner_dec, &_inner_val);",
2972 ind, inner_fn
2973 )?;
2974 writeln!(output, "{} synta_decoder_free(_inner_dec);", ind)?;
2975 writeln!(
2976 output,
2977 "{} if (_inner_err != SyntaErrorCode_Success) return SyntaErrorCode_InvalidArgument;",
2978 ind
2979 )?;
2980 writeln!(output, "{} {}_free(&_inner_val);", ind, inner_fn)?;
2981 writeln!(output, "{}}}", ind)?;
2982 Ok(())
2983}
2984
2985fn emit_size_constraint_validation(
2990 output: &mut String,
2991 spec: &SubtypeConstraint,
2992 var_name: &str,
2993 ind: &str,
2994) -> Result<(), Box<dyn std::error::Error>> {
2995 match spec {
2996 SubtypeConstraint::ValueRange { min, max } => {
2997 writeln!(output, "{}// Validate SIZE range constraint", ind)?;
2998 writeln!(output, "{}{{", ind)?;
2999 writeln!(
3000 output,
3001 "{} size_t _len = synta_octet_string_len({});",
3002 ind, var_name
3003 )?;
3004 if let ConstraintValue::Integer(n) = min {
3005 writeln!(
3006 output,
3007 "{} if (_len < (size_t){}UL) return SyntaErrorCode_InvalidArgument;",
3008 ind, n
3009 )?;
3010 }
3011 if let ConstraintValue::Integer(n) = max {
3012 writeln!(
3013 output,
3014 "{} if (_len > (size_t){}UL) return SyntaErrorCode_MaxLengthExceeded;",
3015 ind, n
3016 )?;
3017 }
3018 writeln!(output, "{}}}", ind)?;
3019 }
3020 SubtypeConstraint::SingleValue(val) => {
3021 if let ConstraintValue::Integer(n) = val {
3022 writeln!(output, "{}// Validate fixed SIZE constraint", ind)?;
3023 writeln!(output, "{}{{", ind)?;
3024 writeln!(
3025 output,
3026 "{} size_t _len = synta_octet_string_len({});",
3027 ind, var_name
3028 )?;
3029 writeln!(
3030 output,
3031 "{} if (_len != (size_t){}UL) return SyntaErrorCode_InvalidArgument;",
3032 ind, n
3033 )?;
3034 writeln!(output, "{}}}", ind)?;
3035 }
3036 }
3037 _ => {
3038 writeln!(
3039 output,
3040 "{}/* complex SIZE constraint: validation not generated */",
3041 ind
3042 )?;
3043 }
3044 }
3045 Ok(())
3046}
3047
3048fn tag_class_c_str(class: &TagClass) -> &'static str {
3050 match class {
3051 TagClass::Universal => "SyntaTagClass_Universal",
3052 TagClass::Application => "SyntaTagClass_Application",
3053 TagClass::ContextSpecific => "SyntaTagClass_ContextSpecific",
3054 TagClass::Private => "SyntaTagClass_Private",
3055 }
3056}
3057
3058fn resolve_typeref_once<'a>(name: &str, defs: &'a [Definition]) -> Option<&'a Type> {
3060 defs.iter()
3061 .find(|d| d.name.eq_ignore_ascii_case(name))
3062 .map(|d| &d.ty)
3063}
3064
3065fn resolve_to_base<'a>(ty: &'a Type, defs: &'a [Definition]) -> &'a Type {
3068 match ty {
3069 Type::TypeRef(name) => {
3070 if let Some(resolved) = resolve_typeref_once(name, defs) {
3071 resolve_to_base(resolved, defs)
3072 } else {
3073 ty
3074 }
3075 }
3076 Type::Tagged { inner, .. }
3077 | Type::Constrained {
3078 base_type: inner, ..
3079 } => resolve_to_base(inner, defs),
3080 other => other,
3081 }
3082}
3083
3084fn get_tag_check_condition(ty: &Type, defs: &[Definition]) -> String {
3086 match ty {
3087 Type::Boolean => {
3088 "tag.class_ == SyntaTagClass_Universal && tag.number == 1 && !tag.constructed"
3089 .to_string()
3090 }
3091 Type::Integer(_, _) => {
3092 "tag.class_ == SyntaTagClass_Universal && tag.number == 2 && !tag.constructed"
3093 .to_string()
3094 }
3095 Type::BitString(_) => {
3096 "tag.class_ == SyntaTagClass_Universal && tag.number == 3 && !tag.constructed"
3097 .to_string()
3098 }
3099 Type::OctetString(_) => {
3100 "tag.class_ == SyntaTagClass_Universal && tag.number == 4 && !tag.constructed"
3101 .to_string()
3102 }
3103 Type::Null => {
3104 "tag.class_ == SyntaTagClass_Universal && tag.number == 5 && !tag.constructed"
3105 .to_string()
3106 }
3107 Type::ObjectIdentifier => {
3108 "tag.class_ == SyntaTagClass_Universal && tag.number == 6 && !tag.constructed"
3109 .to_string()
3110 }
3111 Type::Real => {
3112 "tag.class_ == SyntaTagClass_Universal && tag.number == 9 && !tag.constructed"
3113 .to_string()
3114 }
3115 Type::Enumerated(_) => {
3116 "tag.class_ == SyntaTagClass_Universal && tag.number == 10 && !tag.constructed"
3117 .to_string()
3118 }
3119 Type::Utf8String(_) => {
3120 "tag.class_ == SyntaTagClass_Universal && tag.number == 12 && !tag.constructed"
3121 .to_string()
3122 }
3123 Type::PrintableString(_) => {
3124 "tag.class_ == SyntaTagClass_Universal && tag.number == 19 && !tag.constructed"
3125 .to_string()
3126 }
3127 Type::IA5String(_) => {
3128 "tag.class_ == SyntaTagClass_Universal && tag.number == 22 && !tag.constructed"
3129 .to_string()
3130 }
3131 Type::Sequence(_) => {
3132 "tag.class_ == SyntaTagClass_Universal && tag.number == 16 && tag.constructed"
3133 .to_string()
3134 }
3135 Type::SequenceOf(_, _) => {
3136 "tag.class_ == SyntaTagClass_Universal && tag.number == 16 && tag.constructed"
3137 .to_string()
3138 }
3139 Type::Set(_) => {
3140 "tag.class_ == SyntaTagClass_Universal && tag.number == 17 && tag.constructed"
3141 .to_string()
3142 }
3143 Type::SetOf(_, _) => {
3144 "tag.class_ == SyntaTagClass_Universal && tag.number == 17 && tag.constructed"
3145 .to_string()
3146 }
3147 Type::UtcTime => {
3148 "tag.class_ == SyntaTagClass_Universal && tag.number == 23 && !tag.constructed"
3149 .to_string()
3150 }
3151 Type::GeneralizedTime => {
3152 "tag.class_ == SyntaTagClass_Universal && tag.number == 24 && !tag.constructed"
3153 .to_string()
3154 }
3155 Type::Tagged {
3156 tag: tag_info,
3157 inner,
3158 } => {
3159 let class = tag_class_c_str(&tag_info.class);
3160 let constructed = match tag_info.tagging {
3165 crate::ast::Tagging::Explicit => "tag.constructed",
3166 crate::ast::Tagging::Implicit => {
3167 let concrete = resolve_to_base(inner, defs);
3168 if matches!(
3169 concrete,
3170 Type::Sequence(_)
3171 | Type::Set(_)
3172 | Type::SequenceOf(_, _)
3173 | Type::SetOf(_, _)
3174 | Type::Choice(_)
3175 ) {
3176 "tag.constructed"
3177 } else {
3178 "!tag.constructed"
3179 }
3180 }
3181 };
3182 format!(
3183 "tag.class_ == {} && tag.number == {} && {}",
3184 class, tag_info.number, constructed
3185 )
3186 }
3187 Type::TypeRef(name) => {
3188 if let Some(underlying) = resolve_typeref_once(name, defs) {
3191 if let Type::TypeRef(_) = underlying {
3192 get_tag_check_condition(underlying, defs)
3193 } else {
3194 get_tag_check_condition(underlying, defs)
3195 }
3196 } else {
3197 "true /* TypeRef - unresolved, match any tag */".to_string()
3198 }
3199 }
3200 Type::Any | Type::AnyDefinedBy(_) => {
3201 "true /* ANY - match any tag */".to_string()
3203 }
3204 _ => {
3205 "false /* Unknown type tag */".to_string()
3207 }
3208 }
3209}
3210
3211fn generate_choice_variant_decode(
3213 output: &mut String,
3214 ty: &Type,
3215 var_name: &str,
3216) -> Result<(), Box<dyn std::error::Error>> {
3217 if let Some(call) = make_decode_call(ty, "decoder", var_name) {
3218 writeln!(output, " err = {};", call)?;
3219 writeln!(
3220 output,
3221 " if (err != SyntaErrorCode_Success) return err;"
3222 )?;
3223 } else {
3224 match ty {
3225 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
3226 let is_sequence = matches!(ty, Type::Sequence(_));
3227 let container_type = if is_sequence { "sequence" } else { "set" };
3228 writeln!(
3229 output,
3230 " /* Decode nested {} choice variant */",
3231 container_type.to_uppercase()
3232 )?;
3233 writeln!(output, " SyntaDecoder* nested_decoder = NULL;")?;
3234 writeln!(
3235 output,
3236 " err = synta_decoder_enter_{}(decoder, &nested_decoder);",
3237 container_type
3238 )?;
3239 writeln!(
3240 output,
3241 " if (err != SyntaErrorCode_Success) return err;"
3242 )?;
3243 writeln!(output)?;
3244 for inner_field in inner_fields {
3245 if matches!(inner_field.ty, Type::Null) {
3246 continue;
3247 }
3248 let inner_name = to_snake_case(&inner_field.name);
3249 let nested_var = format!("{}.{}", var_name, inner_name);
3250 generate_choice_seq_field_decode(
3251 output,
3252 &inner_field.ty,
3253 &nested_var,
3254 " ",
3255 )?;
3256 writeln!(output)?;
3257 }
3258 writeln!(output, " synta_decoder_free(nested_decoder);")?;
3259 }
3260 _ => {
3261 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
3262 }
3263 }
3264 } Ok(())
3266}
3267
3268fn generate_choice_variant_encode(
3270 output: &mut String,
3271 ty: &Type,
3272 var_name: &str,
3273) -> Result<(), Box<dyn std::error::Error>> {
3274 if let Some(call) = make_encode_call(ty, "encoder", var_name) {
3275 writeln!(output, " err = {};", call)?;
3276 writeln!(
3277 output,
3278 " if (err != SyntaErrorCode_Success) return err;"
3279 )?;
3280 } else {
3281 match ty {
3282 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
3283 let is_sequence = matches!(ty, Type::Sequence(_));
3284 let container_type = if is_sequence { "sequence" } else { "set" };
3285 writeln!(
3286 output,
3287 " /* Encode nested {} choice variant */",
3288 container_type.to_uppercase()
3289 )?;
3290 writeln!(output, " SyntaEncoder* nested_encoder = NULL;")?;
3291 writeln!(
3292 output,
3293 " err = synta_encoder_start_{}(encoder, &nested_encoder);",
3294 container_type
3295 )?;
3296 writeln!(
3297 output,
3298 " if (err != SyntaErrorCode_Success) return err;"
3299 )?;
3300 writeln!(output)?;
3301 for inner_field in inner_fields {
3302 if matches!(inner_field.ty, Type::Null) {
3303 continue;
3304 }
3305 let inner_name = to_snake_case(&inner_field.name);
3306 let nested_var = format!("{}.{}", var_name, inner_name);
3307 generate_nested_inline_field_encode(
3308 output,
3309 &inner_field.ty,
3310 &nested_var,
3311 " ",
3312 )?;
3313 }
3314 writeln!(output)?;
3315 writeln!(
3316 output,
3317 " err = synta_encoder_end_constructed(nested_encoder);"
3318 )?;
3319 writeln!(
3320 output,
3321 " if (err != SyntaErrorCode_Success) return err;"
3322 )?;
3323 }
3324 _ => {
3325 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
3326 }
3327 }
3328 } Ok(())
3330}
3331
3332fn generate_choice_variant_free(
3334 output: &mut String,
3335 ty: &Type,
3336 var_name: &str,
3337 defs: &[Definition],
3338) -> Result<(), Box<dyn std::error::Error>> {
3339 match ty {
3340 Type::Integer(_, _) => {
3341 writeln!(output, " synta_integer_free({});", var_name)?;
3342 }
3343 Type::Enumerated(_) => {
3344 }
3346 Type::ObjectIdentifier => {
3347 writeln!(output, " synta_oid_free({});", var_name)?;
3348 }
3349 Type::OctetString(_)
3350 | Type::Utf8String(_)
3351 | Type::PrintableString(_)
3352 | Type::IA5String(_)
3353 | Type::UtcTime
3354 | Type::GeneralizedTime
3355 | Type::Any
3356 | Type::AnyDefinedBy(_) => {
3357 writeln!(output, " synta_octet_string_free({});", var_name)?;
3358 }
3359 Type::BitString(_) => {
3360 writeln!(
3361 output,
3362 " synta_byte_array_free(&{}.data);",
3363 var_name
3364 )?;
3365 }
3366 Type::TypeRef(type_name) => {
3367 let name = type_name.clone();
3368 emit_typeref_free(output, &name, var_name, " ", defs)?;
3369 }
3370 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
3371 for inner_field in inner_fields {
3372 if !needs_freeing(&inner_field.ty, defs) {
3373 continue;
3374 }
3375 let inner_name = to_snake_case(&inner_field.name);
3376 let nested_var = format!("{}.{}", var_name, inner_name);
3377 if inner_field.optional {
3378 writeln!(
3379 output,
3380 " if ({}.has_{}) {{",
3381 var_name, inner_name
3382 )?;
3383 generate_free_stmt(output, &inner_field.ty, &nested_var, " ")?;
3384 writeln!(output, " }}")?;
3385 } else {
3386 generate_free_stmt(output, &inner_field.ty, &nested_var, " ")?;
3387 }
3388 }
3389 }
3390 _ => {
3391 }
3393 }
3394 Ok(())
3395}
3396
3397fn emit_typeref_free(
3403 output: &mut String,
3404 type_name: &str,
3405 field_access: &str,
3406 ind: &str,
3407 defs: &[Definition],
3408) -> Result<(), Box<dyn std::error::Error>> {
3409 if let Some(def) = defs.iter().find(|d| d.name == type_name) {
3410 match &def.ty {
3411 Type::Sequence(_)
3413 | Type::Set(_)
3414 | Type::Choice(_)
3415 | Type::SequenceOf(_, _)
3416 | Type::SetOf(_, _) => {
3417 let type_fn = to_snake_case(type_name);
3418 writeln!(output, "{}{}_free(&{});", ind, type_fn, field_access)?;
3419 }
3420 Type::Constrained { base_type, .. }
3422 if matches!(
3423 base_type.as_ref(),
3424 Type::IA5String(_)
3425 | Type::PrintableString(_)
3426 | Type::Utf8String(_)
3427 | Type::OctetString(_)
3428 | Type::BitString(_)
3429 ) =>
3430 {
3431 let type_fn = to_snake_case(type_name);
3432 writeln!(output, "{}{}_free(&{});", ind, type_fn, field_access)?;
3433 }
3434 Type::Integer(_, named) if !named.is_empty() => {}
3436 Type::Integer(_, _) => {
3438 writeln!(output, "{}synta_integer_free({});", ind, field_access)?;
3439 }
3440 Type::Enumerated(_) => {}
3442 Type::ObjectIdentifier => {
3444 writeln!(output, "{}synta_oid_free({});", ind, field_access)?;
3445 }
3446 Type::OctetString(_)
3448 | Type::Utf8String(_)
3449 | Type::PrintableString(_)
3450 | Type::IA5String(_)
3451 | Type::UtcTime
3452 | Type::GeneralizedTime
3453 | Type::Any
3454 | Type::AnyDefinedBy(_) => {
3455 writeln!(output, "{}synta_octet_string_free({});", ind, field_access)?;
3456 }
3457 Type::BitString(_) => {
3459 writeln!(
3460 output,
3461 "{}synta_byte_array_free(&{}.data);",
3462 ind, field_access
3463 )?;
3464 }
3465 Type::TypeRef(inner_name) => {
3467 let inner = inner_name.clone();
3468 emit_typeref_free(output, &inner, field_access, ind, defs)?;
3469 }
3470 Type::Tagged { inner, .. } => {
3472 let base = unwrap_type(inner);
3473 generate_free_stmt(output, base, field_access, ind)?;
3474 }
3475 _ => {}
3477 }
3478 } else {
3479 let type_fn = to_snake_case(type_name);
3481 writeln!(output, "{}{}_free(&{});", ind, type_fn, field_access)?;
3482 }
3483 Ok(())
3484}
3485
3486fn needs_freeing(ty: &Type, defs: &[Definition]) -> bool {
3488 match ty {
3489 Type::Integer(_, named) if !named.is_empty() => false,
3491 Type::Integer(_, _)
3493 | Type::ObjectIdentifier
3494 | Type::OctetString(_)
3495 | Type::Utf8String(_)
3496 | Type::PrintableString(_)
3497 | Type::IA5String(_)
3498 | Type::UtcTime
3499 | Type::GeneralizedTime
3500 | Type::Any
3501 | Type::AnyDefinedBy(_)
3502 | Type::BitString(_)
3503 | Type::Sequence(_)
3504 | Type::Set(_)
3505 | Type::Choice(_)
3506 | Type::SequenceOf(_, _)
3507 | Type::SetOf(_, _) => true,
3508 Type::Enumerated(_) => false,
3510 Type::TypeRef(name) => {
3511 if let Some(def) = defs.iter().find(|d| &d.name == name) {
3513 needs_freeing(&def.ty, defs)
3514 } else {
3515 true }
3517 }
3518 Type::Boolean | Type::Real | Type::Null => false,
3519 _ => false,
3520 }
3521}
3522
3523fn generate_decode_element_toplevel(
3525 output: &mut String,
3526 ty: &Type,
3527 decoder_name: &str,
3528 var_name: &str,
3529) -> Result<(), Box<dyn std::error::Error>> {
3530 if let Some(call) = make_decode_call(ty, decoder_name, var_name) {
3531 writeln!(output, " err = {};", call)?;
3532 } else {
3533 writeln!(output, " err = SyntaErrorCode_InvalidEncoding;")?;
3534 }
3535 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
3536 writeln!(output, " free(array);")?;
3537 writeln!(output, " synta_decoder_free(array_decoder);")?;
3538 writeln!(output, " return err;")?;
3539 writeln!(output, " }}")?;
3540 Ok(())
3541}
3542
3543fn generate_encode_element_toplevel(
3545 output: &mut String,
3546 ty: &Type,
3547 encoder_name: &str,
3548 var_name: &str,
3549) -> Result<(), Box<dyn std::error::Error>> {
3550 if let Some(call) = make_encode_call(ty, encoder_name, var_name) {
3551 writeln!(output, " err = {};", call)?;
3552 } else {
3553 writeln!(output, " err = SyntaErrorCode_InvalidEncoding;")?;
3554 }
3555 writeln!(
3556 output,
3557 " if (err != SyntaErrorCode_Success) return err;"
3558 )?;
3559 Ok(())
3560}
3561
3562fn generate_free_element(
3564 output: &mut String,
3565 ty: &Type,
3566 var_name: &str,
3567 defs: &[Definition],
3568) -> Result<(), Box<dyn std::error::Error>> {
3569 match ty {
3570 Type::Integer(_, _) => {
3571 writeln!(output, " synta_integer_free({});", var_name)?;
3572 }
3573 Type::ObjectIdentifier => {
3574 writeln!(
3575 output,
3576 " synta_object_identifier_free({});",
3577 var_name
3578 )?;
3579 }
3580 Type::OctetString(_) => {
3581 writeln!(output, " synta_octet_string_free({});", var_name)?;
3582 }
3583 Type::BitString(_) => {
3584 writeln!(output, " synta_byte_array_free(&{}.data);", var_name)?;
3585 }
3586 Type::TypeRef(type_name) => {
3587 let name = type_name.clone();
3588 emit_typeref_free(output, &name, var_name, " ", defs)?;
3589 }
3590 _ => {}
3591 }
3592 Ok(())
3593}
3594
3595fn generate_encode_element_field(
3597 output: &mut String,
3598 ty: &Type,
3599 encoder_name: &str,
3600 var_name: &str,
3601 ind: &str,
3602) -> Result<(), Box<dyn std::error::Error>> {
3603 if let Some(call) = make_encode_call(ty, encoder_name, var_name) {
3604 writeln!(output, "{}err = {};", ind, call)?;
3605 } else {
3606 writeln!(output, "{}err = SyntaErrorCode_InvalidEncoding;", ind)?;
3607 }
3608 writeln!(
3609 output,
3610 "{}if (err != SyntaErrorCode_Success) return err;",
3611 ind
3612 )?;
3613 Ok(())
3614}
3615
3616fn generate_decode_element(
3618 output: &mut String,
3619 ty: &Type,
3620 decoder_name: &str,
3621 var_name: &str,
3622 ind: &str,
3623) -> Result<(), Box<dyn std::error::Error>> {
3624 if let Some(call) = make_decode_call(ty, decoder_name, var_name) {
3625 writeln!(output, "{}err = {};", ind, call)?;
3626 } else {
3627 writeln!(output, "{}return SyntaErrorCode_InvalidEncoding;", ind)?;
3628 return Ok(());
3629 }
3630 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
3631 writeln!(output, "{} free(array);", ind)?;
3632 writeln!(output, "{} synta_decoder_free(array_decoder);", ind)?;
3633 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
3634 writeln!(output, "{} return err;", ind)?;
3635 writeln!(output, "{}}}", ind)?;
3636 Ok(())
3637}
3638
3639fn generate_nested_inline_field_decode(
3642 output: &mut String,
3643 ty: &Type,
3644 var_name: &str,
3645 ind: &str,
3646) -> Result<(), Box<dyn std::error::Error>> {
3647 if let Some(call) = make_decode_call(ty, "nested_decoder", var_name) {
3648 writeln!(output, "{}err = {};", ind, call)?;
3649 } else {
3650 writeln!(
3651 output,
3652 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported nested field type */",
3653 ind
3654 )?;
3655 }
3656 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
3657 writeln!(output, "{} synta_decoder_free(nested_decoder);", ind)?;
3658 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
3659 writeln!(output, "{} return err;", ind)?;
3660 writeln!(output, "{}}}", ind)?;
3661 Ok(())
3662}
3663
3664fn generate_choice_seq_field_decode(
3669 output: &mut String,
3670 ty: &Type,
3671 var_name: &str,
3672 ind: &str,
3673) -> Result<(), Box<dyn std::error::Error>> {
3674 if let Some(call) = make_decode_call(ty, "nested_decoder", var_name) {
3675 writeln!(output, "{}err = {};", ind, call)?;
3676 } else {
3677 writeln!(
3678 output,
3679 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported nested field type */",
3680 ind
3681 )?;
3682 }
3683 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
3684 writeln!(output, "{} synta_decoder_free(nested_decoder);", ind)?;
3685 writeln!(output, "{} return err;", ind)?;
3686 writeln!(output, "{}}}", ind)?;
3687 Ok(())
3688}
3689
3690fn generate_free_stmt(
3694 output: &mut String,
3695 ty: &Type,
3696 var_name: &str,
3697 ind: &str,
3698) -> Result<(), Box<dyn std::error::Error>> {
3699 match ty {
3700 Type::Integer(_, _) | Type::Enumerated(_) => {
3701 writeln!(output, "{}synta_integer_free({});", ind, var_name)?;
3702 }
3703 Type::ObjectIdentifier => {
3704 writeln!(output, "{}synta_oid_free({});", ind, var_name)?;
3705 }
3706 Type::OctetString(_)
3707 | Type::Utf8String(_)
3708 | Type::PrintableString(_)
3709 | Type::IA5String(_)
3710 | Type::UtcTime
3711 | Type::GeneralizedTime
3712 | Type::Any
3713 | Type::AnyDefinedBy(_) => {
3714 writeln!(output, "{}synta_octet_string_free({});", ind, var_name)?;
3715 }
3716 Type::BitString(_) => {
3717 writeln!(output, "{}synta_byte_array_free(&{}.data);", ind, var_name)?;
3718 }
3719 Type::TypeRef(type_name) => {
3720 let fn_name = to_snake_case(type_name);
3721 writeln!(output, "{}{}_free(&{});", ind, fn_name, var_name)?;
3722 }
3723 Type::Tagged { inner, .. }
3724 | Type::Constrained {
3725 base_type: inner, ..
3726 } => {
3727 generate_free_stmt(output, inner, var_name, ind)?;
3728 }
3729 _ => {} }
3731 Ok(())
3732}
3733
3734fn generate_nested_inline_field_encode(
3737 output: &mut String,
3738 ty: &Type,
3739 var_name: &str,
3740 ind: &str,
3741) -> Result<(), Box<dyn std::error::Error>> {
3742 if let Some(call) = make_encode_call(ty, "nested_encoder", var_name) {
3743 writeln!(output, "{}err = {};", ind, call)?;
3744 } else {
3745 writeln!(
3746 output,
3747 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported nested field type */",
3748 ind
3749 )?;
3750 }
3751 writeln!(
3752 output,
3753 "{}if (err != SyntaErrorCode_Success) return err;",
3754 ind
3755 )?;
3756 Ok(())
3757}
3758
3759fn generate_type_arena_impl(
3763 output: &mut String,
3764 def: &Definition,
3765 defs: &[Definition],
3766) -> Result<(), Box<dyn std::error::Error>> {
3767 match &def.ty {
3768 Type::Sequence(fields) => {
3769 generate_sequence_arena_impl(output, &def.name, fields, defs, false)?;
3770 }
3771 Type::Set(fields) => {
3772 generate_sequence_arena_impl(output, &def.name, fields, defs, true)?;
3773 }
3774 Type::Choice(variants) => {
3775 generate_choice_arena_impl(output, &def.name, variants, defs)?;
3776 }
3777 Type::Integer(_, named_numbers) if !named_numbers.is_empty() => {
3778 generate_enum_arena_impl(output, &def.name)?;
3779 }
3780 Type::Enumerated(_) => {
3781 generate_enum_arena_impl(output, &def.name)?;
3782 }
3783 Type::SequenceOf(inner, opt_constraint) => {
3784 let size_c = opt_constraint.as_ref().map(legacy_size_to_bounds);
3785 generate_array_arena_impl(output, &def.name, inner, true, size_c)?;
3786 }
3787 Type::SetOf(inner, opt_constraint) => {
3788 let size_c = opt_constraint.as_ref().map(legacy_size_to_bounds);
3789 generate_array_arena_impl(output, &def.name, inner, false, size_c)?;
3790 }
3791 Type::Constrained {
3793 base_type,
3794 constraint,
3795 } => {
3796 let size_c = modern_size_to_bounds(&constraint.spec);
3797 match base_type.as_ref() {
3798 Type::SequenceOf(inner, _) => {
3799 generate_array_arena_impl(output, &def.name, inner, true, size_c)?;
3800 }
3801 Type::SetOf(inner, _) => {
3802 generate_array_arena_impl(output, &def.name, inner, false, size_c)?;
3803 }
3804 _ => {
3805 generate_simple_arena_impl(output, &def.name, &def.ty)?;
3806 }
3807 }
3808 }
3809 _ => {
3810 generate_simple_arena_impl(output, &def.name, &def.ty)?;
3811 }
3812 }
3813 Ok(())
3814}
3815
3816fn make_decode_call_arena(ty: &Type, decoder: &str, arena: &str, var: &str) -> Option<String> {
3820 match ty {
3821 Type::Boolean => Some(format!("synta_decode_boolean({}, &{})", decoder, var)),
3822 Type::Integer(_, _) | Type::Enumerated(_) => {
3823 Some(format!("synta_decode_integer({}, &{})", decoder, var))
3824 }
3825 Type::Real => Some(format!("synta_decode_real({}, &{})", decoder, var)),
3826 Type::Null => Some(format!("synta_decode_null({})", decoder)),
3827 Type::ObjectIdentifier => Some(format!(
3828 "synta_decode_object_identifier({}, &{})",
3829 decoder, var
3830 )),
3831 Type::BitString(_) => Some(format!(
3832 "synta_decode_bit_string({}, &{}.data, &{}.unused_bits)",
3833 decoder, var, var
3834 )),
3835 Type::OctetString(_) | Type::Any | Type::AnyDefinedBy(_) => {
3836 Some(format!("synta_decode_octet_string({}, &{})", decoder, var))
3837 }
3838 Type::Utf8String(_) => Some(format!(
3839 "synta_decode_utf8_string_os({}, &{})",
3840 decoder, var
3841 )),
3842 Type::PrintableString(_) => Some(format!(
3843 "synta_decode_printable_string_os({}, &{})",
3844 decoder, var
3845 )),
3846 Type::IA5String(_) => Some(format!("synta_decode_ia5_string_os({}, &{})", decoder, var)),
3847 Type::UtcTime => Some(format!("synta_decode_utctime_os({}, &{})", decoder, var)),
3848 Type::GeneralizedTime => Some(format!(
3849 "synta_decode_generalized_time_os({}, &{})",
3850 decoder, var
3851 )),
3852 Type::TypeRef(name) => Some(format!(
3854 "{}_decode_arena({}, {}, &{})",
3855 to_snake_case(name),
3856 decoder,
3857 arena,
3858 var
3859 )),
3860 Type::Tagged { tag, inner } => match tag.tagging {
3861 Tagging::Explicit => None,
3862 Tagging::Implicit => make_decode_call_arena(inner, decoder, arena, var),
3863 },
3864 Type::Constrained {
3865 base_type: inner, ..
3866 } => make_decode_call_arena(inner, decoder, arena, var),
3867 _ => None,
3868 }
3869}
3870
3871fn emit_arena_track_field(
3877 output: &mut String,
3878 ty: &Type,
3879 var_name: &str,
3880 arena: &str,
3881 ind: &str,
3882) -> Result<(), Box<dyn std::error::Error>> {
3883 match unwrap_type(ty) {
3884 Type::Integer(_, _) | Type::Enumerated(_) => {
3885 writeln!(
3886 output,
3887 "{}_synta_arena_track({}, {}, (void(*)(void*))synta_integer_free);",
3888 ind, arena, var_name
3889 )?;
3890 }
3891 Type::OctetString(_)
3892 | Type::Utf8String(_)
3893 | Type::PrintableString(_)
3894 | Type::IA5String(_)
3895 | Type::UtcTime
3896 | Type::GeneralizedTime
3897 | Type::Any
3898 | Type::AnyDefinedBy(_) => {
3899 writeln!(
3900 output,
3901 "{}_synta_arena_track({}, {}, (void(*)(void*))synta_octet_string_free);",
3902 ind, arena, var_name
3903 )?;
3904 }
3905 Type::ObjectIdentifier => {
3906 writeln!(
3907 output,
3908 "{}_synta_arena_track({}, {}, (void(*)(void*))synta_oid_free);",
3909 ind, arena, var_name
3910 )?;
3911 }
3912 Type::BitString(_) => {
3913 writeln!(
3914 output,
3915 "{}if ({}.data.owned) _synta_arena_track({}, (void*){}.data.data, free);",
3916 ind, var_name, arena, var_name
3917 )?;
3918 }
3919 _ => {}
3921 }
3922 Ok(())
3923}
3924
3925fn generate_nested_inline_field_decode_arena(
3928 output: &mut String,
3929 ty: &Type,
3930 var_name: &str,
3931 ind: &str,
3932 arena: &str,
3933) -> Result<(), Box<dyn std::error::Error>> {
3934 if let Some(call) = make_decode_call_arena(ty, "nested_decoder", arena, var_name) {
3935 writeln!(output, "{}err = {};", ind, call)?;
3936 } else {
3937 writeln!(
3938 output,
3939 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported nested field type */",
3940 ind
3941 )?;
3942 }
3943 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
3944 writeln!(output, "{} synta_decoder_free(nested_decoder);", ind)?;
3945 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
3946 writeln!(output, "{} return err;", ind)?;
3947 writeln!(output, "{}}}", ind)?;
3948 emit_arena_track_field(output, ty, var_name, arena, ind)?;
3949 Ok(())
3950}
3951
3952fn generate_choice_seq_field_decode_arena(
3955 output: &mut String,
3956 ty: &Type,
3957 var_name: &str,
3958 ind: &str,
3959 arena: &str,
3960) -> Result<(), Box<dyn std::error::Error>> {
3961 if let Some(call) = make_decode_call_arena(ty, "nested_decoder", arena, var_name) {
3962 writeln!(output, "{}err = {};", ind, call)?;
3963 } else {
3964 writeln!(
3965 output,
3966 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported nested field type */",
3967 ind
3968 )?;
3969 }
3970 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
3971 writeln!(output, "{} synta_decoder_free(nested_decoder);", ind)?;
3972 writeln!(output, "{} return err;", ind)?;
3973 writeln!(output, "{}}}", ind)?;
3974 emit_arena_track_field(output, ty, var_name, arena, ind)?;
3975 Ok(())
3976}
3977
3978fn generate_decode_element_arena(
3981 output: &mut String,
3982 ty: &Type,
3983 decoder_name: &str,
3984 var_name: &str,
3985 ind: &str,
3986 arena: &str,
3987) -> Result<(), Box<dyn std::error::Error>> {
3988 if let Some(call) = make_decode_call_arena(ty, decoder_name, arena, var_name) {
3989 writeln!(output, "{}err = {};", ind, call)?;
3990 } else {
3991 writeln!(output, "{}return SyntaErrorCode_InvalidEncoding;", ind)?;
3992 return Ok(());
3993 }
3994 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
3995 writeln!(output, "{} free(array);", ind)?;
3996 writeln!(output, "{} synta_decoder_free(array_decoder);", ind)?;
3997 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
3998 writeln!(output, "{} return err;", ind)?;
3999 writeln!(output, "{}}}", ind)?;
4000 emit_arena_track_field(output, ty, var_name, arena, ind)?;
4001 Ok(())
4002}
4003
4004fn generate_decode_element_toplevel_arena(
4007 output: &mut String,
4008 ty: &Type,
4009 decoder_name: &str,
4010 var_name: &str,
4011 arena: &str,
4012) -> Result<(), Box<dyn std::error::Error>> {
4013 if let Some(call) = make_decode_call_arena(ty, decoder_name, arena, var_name) {
4014 writeln!(output, " err = {};", call)?;
4015 } else {
4016 writeln!(output, " err = SyntaErrorCode_InvalidEncoding;")?;
4017 }
4018 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
4019 writeln!(output, " free(array);")?;
4020 writeln!(output, " synta_decoder_free(array_decoder);")?;
4021 writeln!(output, " return err;")?;
4022 writeln!(output, " }}")?;
4023 emit_arena_track_field(output, ty, var_name, arena, " ")?;
4024 Ok(())
4025}
4026
4027fn generate_field_decode_arena(
4035 output: &mut String,
4036 ty: &Type,
4037 var_name: &str,
4038 indent: usize,
4039 arena: &str,
4040 defs: &[Definition],
4041) -> Result<(), Box<dyn std::error::Error>> {
4042 let ind = " ".repeat(indent);
4043
4044 if let Some(call) = make_decode_call_arena(ty, "seq_decoder", arena, var_name) {
4045 writeln!(output, "{}err = {};", ind, call)?;
4046 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
4047 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4048 writeln!(output, "{} return err;", ind)?;
4049 writeln!(output, "{}}}", ind)?;
4050 emit_arena_track_field(output, ty, var_name, arena, &ind)?;
4051 } else {
4052 match ty {
4053 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
4054 let is_sequence = matches!(ty, Type::Sequence(_));
4055 let container_type = if is_sequence { "sequence" } else { "set" };
4056
4057 writeln!(
4058 output,
4059 "{}// Decode nested {}",
4060 ind,
4061 container_type.to_uppercase()
4062 )?;
4063 writeln!(output, "{}SyntaDecoder* nested_decoder = NULL;", ind)?;
4064 writeln!(
4065 output,
4066 "{}err = synta_decoder_enter_{}(seq_decoder, &nested_decoder);",
4067 ind, container_type
4068 )?;
4069 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
4070 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4071 writeln!(output, "{} return err;", ind)?;
4072 writeln!(output, "{}}}", ind)?;
4073 writeln!(output)?;
4074
4075 for inner_field in inner_fields {
4076 if matches!(inner_field.ty, Type::Null) {
4077 continue;
4078 }
4079
4080 let inner_name = to_snake_case(&inner_field.name);
4081 let nested_var = format!("{}.{}", var_name, inner_name);
4082 if inner_field.optional {
4083 writeln!(
4084 output,
4085 "{}// Decode optional nested field: {}",
4086 ind, inner_field.name
4087 )?;
4088 let tag_check = get_tag_check_condition(&inner_field.ty, defs);
4089 writeln!(output, "{}{{", ind)?;
4090 writeln!(output, "{} SyntaTag tag;", ind)?;
4091 writeln!(
4092 output,
4093 "{} if (synta_decoder_peek_tag(nested_decoder, &tag) == SyntaErrorCode_Success &&",
4094 ind
4095 )?;
4096 writeln!(output, "{} ({})) {{", ind, tag_check)?;
4097 let deeper_ind = format!("{} ", ind);
4098 generate_nested_inline_field_decode_arena(
4099 output,
4100 &inner_field.ty,
4101 &nested_var,
4102 &deeper_ind,
4103 arena,
4104 )?;
4105 writeln!(
4106 output,
4107 "{} {}.has_{} = true;",
4108 ind, var_name, inner_name
4109 )?;
4110 writeln!(output, "{} }} else {{", ind)?;
4111 writeln!(
4112 output,
4113 "{} {}.has_{} = false;",
4114 ind, var_name, inner_name
4115 )?;
4116 writeln!(output, "{} }}", ind)?;
4117 writeln!(output, "{}}}", ind)?;
4118 } else {
4119 writeln!(output, "{}// Decode field: {}", ind, inner_field.name)?;
4120 generate_nested_inline_field_decode_arena(
4121 output,
4122 &inner_field.ty,
4123 &nested_var,
4124 &ind,
4125 arena,
4126 )?;
4127 }
4128 writeln!(output)?;
4129 }
4130
4131 writeln!(output, "{}synta_decoder_free(nested_decoder);", ind)?;
4132 }
4133 Type::SequenceOf(inner_ty, _) | Type::SetOf(inner_ty, _) => {
4134 let is_sequence = matches!(ty, Type::SequenceOf(_, _));
4135 let container_type = if is_sequence { "sequence" } else { "set" };
4136
4137 writeln!(output, "{}// Decode SEQUENCE OF / SET OF", ind)?;
4138 writeln!(output, "{}SyntaDecoder* array_decoder = NULL;", ind)?;
4139 writeln!(
4140 output,
4141 "{}err = synta_decoder_enter_{}(seq_decoder, &array_decoder);",
4142 ind, container_type
4143 )?;
4144 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
4145 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4146 writeln!(output, "{} return err;", ind)?;
4147 writeln!(output, "{}}}", ind)?;
4148 writeln!(output)?;
4149
4150 writeln!(output, "{}// Allocate dynamic array for elements", ind)?;
4151 writeln!(output, "{}size_t capacity = 4; // Initial capacity", ind)?;
4152 writeln!(output, "{}size_t count = 0;", ind)?;
4153 let elem_c_type = get_c_type(inner_ty);
4154 let array_type = format!("{}*", elem_c_type);
4155 writeln!(
4156 output,
4157 "{}{} array = ({})calloc(capacity, sizeof({}));",
4158 ind, array_type, array_type, elem_c_type
4159 )?;
4160 writeln!(output, "{}if (array == NULL) {{", ind)?;
4161 writeln!(output, "{} synta_decoder_free(array_decoder);", ind)?;
4162 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4163 writeln!(output, "{} return SyntaErrorCode_OutOfMemory;", ind)?;
4164 writeln!(output, "{}}}", ind)?;
4165 writeln!(output)?;
4166
4167 writeln!(
4168 output,
4169 "{}while (!synta_decoder_at_end(array_decoder)) {{",
4170 ind
4171 )?;
4172 writeln!(output, "{} // Grow array if needed", ind)?;
4173 writeln!(output, "{} if (count >= capacity) {{", ind)?;
4174 writeln!(output, "{} capacity *= 2;", ind)?;
4175 writeln!(
4176 output,
4177 "{} {} new_array = ({})realloc(array, capacity * sizeof({}));",
4178 ind, array_type, array_type, elem_c_type
4179 )?;
4180 writeln!(output, "{} if (new_array == NULL) {{", ind)?;
4181 writeln!(output, "{} free(array);", ind)?;
4182 writeln!(
4183 output,
4184 "{} synta_decoder_free(array_decoder);",
4185 ind
4186 )?;
4187 writeln!(
4188 output,
4189 "{} synta_decoder_free(seq_decoder);",
4190 ind
4191 )?;
4192 writeln!(
4193 output,
4194 "{} return SyntaErrorCode_OutOfMemory;",
4195 ind
4196 )?;
4197 writeln!(output, "{} }}", ind)?;
4198 writeln!(output, "{} array = new_array;", ind)?;
4199 writeln!(output, "{} }}", ind)?;
4200 writeln!(output)?;
4201
4202 writeln!(output, "{} // Decode element", ind)?;
4203 generate_decode_element_arena(
4204 output,
4205 inner_ty,
4206 "array_decoder",
4207 "array[count]",
4208 " ",
4209 arena,
4210 )?;
4211 writeln!(output, "{} count++;", ind)?;
4212 writeln!(output, "{}}}", ind)?;
4213 writeln!(output)?;
4214
4215 writeln!(output, "{}{} = array;", ind, var_name)?;
4216 writeln!(output, "{}{}_count = count;", ind, var_name)?;
4217 writeln!(output, "{}synta_decoder_free(array_decoder);", ind)?;
4218 writeln!(
4220 output,
4221 "{}_synta_arena_track({}, {}, free);",
4222 ind, arena, var_name
4223 )?;
4224 }
4225 Type::Tagged {
4226 tag: tag_info,
4227 inner,
4228 } => match tag_info.tagging {
4229 Tagging::Explicit => {
4230 let class = tag_class_c_str(&tag_info.class);
4231 writeln!(
4232 output,
4233 "{}// Enter EXPLICIT [{cls} {num}] tag wrapper",
4234 ind,
4235 cls = class,
4236 num = tag_info.number
4237 )?;
4238 writeln!(output, "{}{{", ind)?;
4239 writeln!(output, "{} SyntaDecoder* tagged_decoder = NULL;", ind)?;
4240 writeln!(output, "{} SyntaTag explicit_tag;", ind)?;
4241 writeln!(output, "{} explicit_tag.class_ = {};", ind, class)?;
4242 writeln!(output, "{} explicit_tag.constructed = true;", ind)?;
4243 writeln!(
4244 output,
4245 "{} explicit_tag.number = {};",
4246 ind, tag_info.number
4247 )?;
4248 writeln!(
4249 output,
4250 "{} err = synta_decoder_enter_constructed(seq_decoder, explicit_tag, &tagged_decoder);",
4251 ind
4252 )?;
4253 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
4254 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4255 writeln!(output, "{} return err;", ind)?;
4256 writeln!(output, "{} }}", ind)?;
4257 if let Some(call) =
4258 make_decode_call_arena(inner, "tagged_decoder", arena, var_name)
4259 {
4260 writeln!(output, "{} err = {};", ind, call)?;
4261 writeln!(output, "{} if (err != SyntaErrorCode_Success) {{", ind)?;
4262 writeln!(output, "{} synta_decoder_free(tagged_decoder);", ind)?;
4263 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4264 writeln!(output, "{} return err;", ind)?;
4265 writeln!(output, "{} }}", ind)?;
4266 emit_arena_track_field(
4267 output,
4268 inner,
4269 var_name,
4270 arena,
4271 &format!("{} ", ind),
4272 )?;
4273 } else {
4274 writeln!(output, "{} /* structural inner type inside EXPLICIT tag: not yet supported */", ind)?;
4275 writeln!(output, "{} err = SyntaErrorCode_InvalidEncoding;", ind)?;
4276 writeln!(output, "{} synta_decoder_free(tagged_decoder);", ind)?;
4277 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4278 writeln!(output, "{} return err;", ind)?;
4279 }
4280 writeln!(output, "{} synta_decoder_free(tagged_decoder);", ind)?;
4281 writeln!(output, "{}}}", ind)?;
4282 }
4283 Tagging::Implicit => {
4284 let class = tag_class_c_str(&tag_info.class);
4285 writeln!(
4286 output,
4287 "{}/* IMPLICIT [{cls} {num}]: decoded transparently (tag check relaxed) */",
4288 ind,
4289 cls = class,
4290 num = tag_info.number
4291 )?;
4292 generate_field_decode_arena(output, inner, var_name, indent, arena, defs)?;
4293 }
4294 },
4295 Type::Constrained {
4296 base_type: inner, ..
4297 } => {
4298 generate_field_decode_arena(output, inner, var_name, indent, arena, defs)?;
4299 }
4300 _ => {
4301 writeln!(
4302 output,
4303 "{}err = SyntaErrorCode_InvalidEncoding; /* unsupported field type */",
4304 ind
4305 )?;
4306 writeln!(output, "{}if (err != SyntaErrorCode_Success) {{", ind)?;
4307 writeln!(output, "{} synta_decoder_free(seq_decoder);", ind)?;
4308 writeln!(output, "{} return err;", ind)?;
4309 writeln!(output, "{}}}", ind)?;
4310 }
4311 }
4312 }
4313
4314 Ok(())
4315}
4316
4317fn generate_sequence_arena_impl(
4324 output: &mut String,
4325 name: &str,
4326 fields: &[SequenceField],
4327 defs: &[Definition],
4328 is_set: bool,
4329) -> Result<(), Box<dyn std::error::Error>> {
4330 let struct_name = to_pascal_case(name);
4331 let fn_prefix = to_snake_case(name);
4332 let container_kind = if is_set { "set" } else { "sequence" };
4333 let enter_fn = if is_set {
4334 "synta_decoder_enter_set"
4335 } else {
4336 "synta_decoder_enter_sequence"
4337 };
4338
4339 writeln!(
4340 output,
4341 "SyntaErrorCode {}_decode_arena(SyntaDecoder* decoder, SyntaArena* arena, {}* out) {{",
4342 fn_prefix, struct_name
4343 )?;
4344 writeln!(
4345 output,
4346 " if (decoder == NULL || arena == NULL || out == NULL) {{"
4347 )?;
4348 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
4349 writeln!(output, " }}")?;
4350 writeln!(output)?;
4351 writeln!(output, " // Enter {}", container_kind.to_uppercase())?;
4352 writeln!(output, " SyntaDecoder* seq_decoder = NULL;")?;
4353 writeln!(
4354 output,
4355 " SyntaErrorCode err = {}(decoder, &seq_decoder);",
4356 enter_fn
4357 )?;
4358 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
4359 writeln!(output, " return err;")?;
4360 writeln!(output, " }}")?;
4361 writeln!(output)?;
4362
4363 for field in fields {
4364 let field_name = to_snake_case(&field.name);
4365
4366 if field.optional {
4367 writeln!(output, " // Decode optional field: {}", field_name)?;
4368 let tag_check = get_tag_check_condition(&field.ty, defs);
4369 writeln!(output, " {{")?;
4370 writeln!(output, " SyntaTag tag;")?;
4371 writeln!(
4372 output,
4373 " if (synta_decoder_peek_tag(seq_decoder, &tag) == SyntaErrorCode_Success &&"
4374 )?;
4375 writeln!(output, " ({})) {{", tag_check)?;
4376 generate_field_decode_arena(
4377 output,
4378 &field.ty,
4379 &format!("out->{}", field_name),
4380 3,
4381 "arena",
4382 defs,
4383 )?;
4384 writeln!(output, " out->has_{} = true;", field_name)?;
4385 writeln!(output, " }} else {{")?;
4386 writeln!(output, " out->has_{} = false;", field_name)?;
4387 writeln!(output, " }}")?;
4388 writeln!(output, " }}")?;
4389 } else {
4390 writeln!(output, " // Decode field: {}", field_name)?;
4391 generate_field_decode_arena(
4392 output,
4393 &field.ty,
4394 &format!("out->{}", field_name),
4395 1,
4396 "arena",
4397 defs,
4398 )?;
4399 }
4400 writeln!(output)?;
4401 }
4402
4403 writeln!(output, " synta_decoder_free(seq_decoder);")?;
4404 writeln!(output, " return SyntaErrorCode_Success;")?;
4405 writeln!(output, "}}")?;
4406
4407 Ok(())
4408}
4409
4410fn generate_choice_arena_impl(
4412 output: &mut String,
4413 name: &str,
4414 variants: &[ChoiceVariant],
4415 defs: &[Definition],
4416) -> Result<(), Box<dyn std::error::Error>> {
4417 let struct_name = to_pascal_case(name);
4418 let fn_prefix = to_snake_case(name);
4419 let tag_enum_name = format!("{}Tag", struct_name);
4420
4421 writeln!(
4422 output,
4423 "SyntaErrorCode {}_decode_arena(SyntaDecoder* decoder, SyntaArena* arena, {}* out) {{",
4424 fn_prefix, struct_name
4425 )?;
4426 writeln!(
4427 output,
4428 " if (decoder == NULL || arena == NULL || out == NULL) {{"
4429 )?;
4430 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
4431 writeln!(output, " }}")?;
4432 writeln!(output)?;
4433 writeln!(
4434 output,
4435 " // Peek at the next tag to determine which variant"
4436 )?;
4437 writeln!(output, " SyntaTag tag;")?;
4438 writeln!(
4439 output,
4440 " SyntaErrorCode err = synta_decoder_peek_tag(decoder, &tag);"
4441 )?;
4442 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
4443 writeln!(output, " return err;")?;
4444 writeln!(output, " }}")?;
4445 writeln!(output)?;
4446
4447 for (i, variant) in variants.iter().enumerate() {
4448 let variant_name = to_snake_case(&variant.name);
4449 let variant_pascal = to_pascal_case(&variant.name);
4450 let tag_check = get_tag_check_condition(&variant.ty, defs);
4451
4452 let else_if = if i == 0 { "if" } else { "} else if" };
4453
4454 writeln!(output, " {} ({}) {{", else_if, tag_check)?;
4455 writeln!(output, " // Decode {} variant", variant_name)?;
4456 writeln!(
4457 output,
4458 " out->tag = {}_{};",
4459 tag_enum_name, variant_pascal
4460 )?;
4461 generate_choice_variant_decode_arena(
4462 output,
4463 &variant.ty,
4464 &format!("out->value.{}", variant_name),
4465 "arena",
4466 )?;
4467 writeln!(output, " return SyntaErrorCode_Success;")?;
4468 }
4469
4470 writeln!(output, " }} else {{")?;
4471 writeln!(
4472 output,
4473 " /* no matching variant found for the observed tag */"
4474 )?;
4475 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
4476 writeln!(output, " }}")?;
4477 writeln!(output, "}}")?;
4478
4479 Ok(())
4480}
4481
4482fn generate_choice_variant_decode_arena(
4484 output: &mut String,
4485 ty: &Type,
4486 var_name: &str,
4487 arena: &str,
4488) -> Result<(), Box<dyn std::error::Error>> {
4489 if let Some(call) = make_decode_call_arena(ty, "decoder", arena, var_name) {
4490 writeln!(output, " err = {};", call)?;
4491 writeln!(
4492 output,
4493 " if (err != SyntaErrorCode_Success) return err;"
4494 )?;
4495 emit_arena_track_field(output, ty, var_name, arena, " ")?;
4496 } else {
4497 match ty {
4498 Type::Sequence(inner_fields) | Type::Set(inner_fields) => {
4499 let is_sequence = matches!(ty, Type::Sequence(_));
4500 let container_type = if is_sequence { "sequence" } else { "set" };
4501 writeln!(
4502 output,
4503 " /* Decode nested {} choice variant */",
4504 container_type.to_uppercase()
4505 )?;
4506 writeln!(output, " SyntaDecoder* nested_decoder = NULL;")?;
4507 writeln!(
4508 output,
4509 " err = synta_decoder_enter_{}(decoder, &nested_decoder);",
4510 container_type
4511 )?;
4512 writeln!(
4513 output,
4514 " if (err != SyntaErrorCode_Success) return err;"
4515 )?;
4516 writeln!(output)?;
4517 for inner_field in inner_fields {
4518 if matches!(inner_field.ty, Type::Null) {
4519 continue;
4520 }
4521 let inner_name = to_snake_case(&inner_field.name);
4522 let nested_var = format!("{}.{}", var_name, inner_name);
4523 generate_choice_seq_field_decode_arena(
4524 output,
4525 &inner_field.ty,
4526 &nested_var,
4527 " ",
4528 arena,
4529 )?;
4530 writeln!(output)?;
4531 }
4532 writeln!(output, " synta_decoder_free(nested_decoder);")?;
4533 }
4534 _ => {
4535 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
4536 }
4537 }
4538 }
4539 Ok(())
4540}
4541
4542fn generate_array_arena_impl(
4544 output: &mut String,
4545 name: &str,
4546 inner_ty: &Type,
4547 is_sequence: bool,
4548 size_constraint: Option<ArraySizeBounds>,
4549) -> Result<(), Box<dyn std::error::Error>> {
4550 let struct_name = to_pascal_case(name);
4551 let fn_prefix = to_snake_case(name);
4552 let container_type = if is_sequence { "sequence" } else { "set" };
4553 let elem_c_type = get_c_type(inner_ty);
4554 let array_type = format!("{}*", elem_c_type);
4555
4556 writeln!(
4557 output,
4558 "SyntaErrorCode {}_decode_arena(SyntaDecoder* decoder, SyntaArena* arena, struct {}* out) {{",
4559 fn_prefix, struct_name
4560 )?;
4561 writeln!(
4562 output,
4563 " if (decoder == NULL || arena == NULL || out == NULL) {{"
4564 )?;
4565 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
4566 writeln!(output, " }}")?;
4567 writeln!(output)?;
4568
4569 writeln!(output, " // Enter SEQUENCE/SET")?;
4570 writeln!(output, " SyntaDecoder* array_decoder = NULL;")?;
4571 writeln!(
4572 output,
4573 " SyntaErrorCode err = synta_decoder_enter_{}(decoder, &array_decoder);",
4574 container_type
4575 )?;
4576 writeln!(output, " if (err != SyntaErrorCode_Success) {{")?;
4577 writeln!(output, " return err;")?;
4578 writeln!(output, " }}")?;
4579 writeln!(output)?;
4580
4581 writeln!(output, " // Allocate dynamic array for elements")?;
4582 writeln!(output, " size_t capacity = 4; // Initial capacity")?;
4583 writeln!(output, " size_t count = 0;")?;
4584 writeln!(
4585 output,
4586 " {} array = ({})calloc(capacity, sizeof({}));",
4587 array_type, array_type, elem_c_type
4588 )?;
4589 writeln!(output, " if (array == NULL) {{")?;
4590 writeln!(output, " synta_decoder_free(array_decoder);")?;
4591 writeln!(output, " return SyntaErrorCode_OutOfMemory;")?;
4592 writeln!(output, " }}")?;
4593 writeln!(output)?;
4594
4595 writeln!(
4596 output,
4597 " while (!synta_decoder_at_end(array_decoder)) {{"
4598 )?;
4599 writeln!(output, " // Grow array if needed")?;
4600 writeln!(output, " if (count >= capacity) {{")?;
4601 writeln!(output, " capacity *= 2;")?;
4602 writeln!(
4603 output,
4604 " {} new_array = ({})realloc(array, capacity * sizeof({}));",
4605 array_type, array_type, elem_c_type
4606 )?;
4607 writeln!(output, " if (new_array == NULL) {{")?;
4608 writeln!(output, " free(array);")?;
4609 writeln!(output, " synta_decoder_free(array_decoder);")?;
4610 writeln!(output, " return SyntaErrorCode_OutOfMemory;")?;
4611 writeln!(output, " }}")?;
4612 writeln!(output, " array = new_array;")?;
4613 writeln!(output, " }}")?;
4614 writeln!(output)?;
4615
4616 writeln!(output, " // Decode element")?;
4617 generate_decode_element_toplevel_arena(
4618 output,
4619 inner_ty,
4620 "array_decoder",
4621 "array[count]",
4622 "arena",
4623 )?;
4624 writeln!(output, " count++;")?;
4625 writeln!(output, " }}")?;
4626 writeln!(output)?;
4627
4628 if let Some(size_spec) = size_constraint {
4630 emit_array_size_check(output, size_spec, "count")?;
4631 }
4632
4633 writeln!(output, " out->count = count;")?;
4634 writeln!(output, " out->items = array;")?;
4635 writeln!(output, " _synta_arena_track(arena, out->items, free);")?;
4636 writeln!(output, " synta_decoder_free(array_decoder);")?;
4637 writeln!(output, " return SyntaErrorCode_Success;")?;
4638 writeln!(output, "}}")?;
4639
4640 Ok(())
4641}
4642
4643fn generate_enum_arena_impl(
4649 output: &mut String,
4650 name: &str,
4651) -> Result<(), Box<dyn std::error::Error>> {
4652 let fn_prefix = to_snake_case(name);
4653
4654 writeln!(
4655 output,
4656 "SyntaErrorCode {}_decode_arena(SyntaDecoder* decoder, SyntaArena* arena, enum {}* out) {{",
4657 fn_prefix,
4658 to_pascal_case(name)
4659 )?;
4660 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
4661 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
4662 writeln!(output, " }}")?;
4663 writeln!(
4664 output,
4665 " (void)arena; /* enum decode does not leave heap allocations */"
4666 )?;
4667 writeln!(output)?;
4668 writeln!(output, " SyntaInteger* int_val = NULL;")?;
4669 writeln!(
4670 output,
4671 " SyntaErrorCode err = synta_decode_integer(decoder, &int_val);"
4672 )?;
4673 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
4674 writeln!(output)?;
4675 writeln!(output, " int64_t val;")?;
4676 writeln!(output, " err = synta_integer_to_i64(int_val, &val);")?;
4677 writeln!(output, " synta_integer_free(int_val);")?;
4678 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
4679 writeln!(output)?;
4680 writeln!(output, " *out = (enum {})val;", to_pascal_case(name))?;
4681 writeln!(output, " return SyntaErrorCode_Success;")?;
4682 writeln!(output, "}}")?;
4683
4684 Ok(())
4685}
4686
4687fn generate_simple_arena_impl(
4694 output: &mut String,
4695 name: &str,
4696 ty: &Type,
4697) -> Result<(), Box<dyn std::error::Error>> {
4698 let fn_prefix = to_snake_case(name);
4699 let type_name = to_pascal_case(name);
4700 let base = unwrap_type(ty);
4701
4702 writeln!(
4703 output,
4704 "SyntaErrorCode {}_decode_arena(SyntaDecoder* decoder, SyntaArena* arena, {}* out) {{",
4705 fn_prefix, type_name
4706 )?;
4707 writeln!(output, " if (decoder == NULL || out == NULL) {{")?;
4708 writeln!(output, " return SyntaErrorCode_NullPointer;")?;
4709 writeln!(output, " }}")?;
4710
4711 match base {
4712 Type::Boolean => {
4713 writeln!(output, " (void)arena;")?;
4714 writeln!(output, " return synta_decode_boolean(decoder, out);")?;
4715 }
4716 Type::Integer(_, _) | Type::Enumerated(_) => {
4717 writeln!(
4718 output,
4719 " SyntaErrorCode err = synta_decode_integer(decoder, out);"
4720 )?;
4721 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
4722 writeln!(
4723 output,
4724 " _synta_arena_track(arena, *out, (void(*)(void*))synta_integer_free);"
4725 )?;
4726 writeln!(output, " return SyntaErrorCode_Success;")?;
4727 }
4728 Type::Real => {
4729 writeln!(output, " (void)arena;")?;
4730 writeln!(output, " return synta_decode_real(decoder, out);")?;
4731 }
4732 Type::Null => {
4733 writeln!(output, " (void)arena; (void)out;")?;
4734 writeln!(output, " return synta_decode_null(decoder);")?;
4735 }
4736 Type::ObjectIdentifier => {
4737 writeln!(
4738 output,
4739 " SyntaErrorCode err = synta_decode_object_identifier(decoder, out);"
4740 )?;
4741 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
4742 writeln!(
4743 output,
4744 " _synta_arena_track(arena, *out, (void(*)(void*))synta_oid_free);"
4745 )?;
4746 writeln!(output, " return SyntaErrorCode_Success;")?;
4747 }
4748 Type::BitString(_) => {
4749 writeln!(
4750 output,
4751 " SyntaErrorCode err = synta_decode_bit_string(decoder, &out->data, &out->unused_bits);"
4752 )?;
4753 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
4754 writeln!(
4755 output,
4756 " if (out->data.owned) _synta_arena_track(arena, (void*)out->data.data, free);"
4757 )?;
4758 writeln!(output, " return SyntaErrorCode_Success;")?;
4759 }
4760 Type::OctetString(_)
4761 | Type::Utf8String(_)
4762 | Type::PrintableString(_)
4763 | Type::IA5String(_)
4764 | Type::UtcTime
4765 | Type::GeneralizedTime
4766 | Type::Any
4767 | Type::AnyDefinedBy(_) => {
4768 writeln!(
4769 output,
4770 " SyntaErrorCode err = synta_decode_octet_string(decoder, out);"
4771 )?;
4772 writeln!(output, " if (err != SyntaErrorCode_Success) return err;")?;
4773 writeln!(
4774 output,
4775 " _synta_arena_track(arena, *out, (void(*)(void*))synta_octet_string_free);"
4776 )?;
4777 writeln!(output, " return SyntaErrorCode_Success;")?;
4778 }
4779 Type::TypeRef(ref_name) => {
4780 let ref_fn = to_snake_case(ref_name);
4781 writeln!(
4782 output,
4783 " return {}_decode_arena(decoder, arena, out);",
4784 ref_fn
4785 )?;
4786 }
4787 _ => {
4788 writeln!(output, " /* unsupported simple type alias */")?;
4789 writeln!(output, " return SyntaErrorCode_InvalidEncoding;")?;
4790 }
4791 }
4792 writeln!(output, "}}")?;
4793 writeln!(output)?;
4794
4795 Ok(())
4796}
4797
4798#[cfg(test)]
4799mod tests {
4800 use super::*;
4801
4802 fn make_module(name: &str, ty: Type) -> Module {
4803 Module {
4804 name: "TestModule".to_string(),
4805 oid: None,
4806 values: vec![],
4807 tagging_mode: None,
4808 imports: vec![],
4809 exports: vec![],
4810 definitions: vec![Definition {
4811 name: name.to_string(),
4812 ty,
4813 }],
4814 }
4815 }
4816
4817 fn impl_config() -> CImplConfig {
4818 CImplConfig {
4819 header_file: "test.h".to_string(),
4820 arena_mode: false,
4821 pattern_mode: PatternMode::Skip,
4822 with_containing: false,
4823 }
4824 }
4825
4826 #[test]
4831 fn sequence_of_no_size_constraint_no_check() {
4832 let module = make_module(
4833 "Items",
4834 Type::SequenceOf(Box::new(Type::Integer(None, vec![])), None),
4835 );
4836 let result = generate_c_impl(&module, impl_config()).unwrap();
4837 assert!(result.contains("items_decode"), "decode function generated");
4839 assert!(result.contains("items_encode"), "encode function generated");
4840 assert!(
4842 !result.contains("Validate SIZE constraint"),
4843 "no SIZE check without constraint"
4844 );
4845 }
4846
4847 #[test]
4852 fn sequence_of_fixed_size_generates_check() {
4853 let module = make_module(
4854 "Triple",
4855 Type::SequenceOf(
4856 Box::new(Type::Integer(None, vec![])),
4857 Some(SizeConstraint::Fixed(3)),
4858 ),
4859 );
4860 let result = generate_c_impl(&module, impl_config()).unwrap();
4861 assert!(
4863 result.contains("< (size_t)3ULL") || result.contains("> (size_t)3ULL"),
4864 "fixed SIZE check on decode"
4865 );
4866 assert!(result.contains("value->count"), "encode-side count checked");
4868 assert!(result.contains("< (size_t)3ULL"), "lower bound (count < 3)");
4870 assert!(result.contains("> (size_t)3ULL"), "upper bound (count > 3)");
4871 }
4872
4873 #[test]
4878 fn sequence_of_range_lower_only() {
4879 let module = make_module(
4880 "NonEmpty",
4881 Type::SequenceOf(
4882 Box::new(Type::Integer(None, vec![])),
4883 Some(SizeConstraint::Range(Some(1), None)),
4884 ),
4885 );
4886 let result = generate_c_impl(&module, impl_config()).unwrap();
4887 assert!(result.contains("< (size_t)1ULL"), "lower bound emitted");
4889 assert!(!result.contains("> (size_t)"), "no upper bound emitted");
4891 }
4892
4893 #[test]
4898 fn sequence_of_range_zero_lower_bound_skipped() {
4899 let module = make_module(
4900 "Items",
4901 Type::SequenceOf(
4902 Box::new(Type::Integer(None, vec![])),
4903 Some(SizeConstraint::Range(Some(0), Some(10))),
4904 ),
4905 );
4906 let result = generate_c_impl(&module, impl_config()).unwrap();
4907 assert!(result.contains("> (size_t)10ULL"), "upper bound emitted");
4909 assert!(
4911 !result.contains("< (size_t)0ULL"),
4912 "zero lower bound is not emitted"
4913 );
4914 }
4915
4916 #[test]
4921 fn sequence_of_range_both_bounds() {
4922 let module = make_module(
4923 "Items",
4924 Type::SequenceOf(
4925 Box::new(Type::Integer(None, vec![])),
4926 Some(SizeConstraint::Range(Some(2), Some(5))),
4927 ),
4928 );
4929 let result = generate_c_impl(&module, impl_config()).unwrap();
4930 assert!(result.contains("< (size_t)2ULL"), "lower bound emitted");
4931 assert!(result.contains("> (size_t)5ULL"), "upper bound emitted");
4932 assert!(result.contains("||"), "conditions joined with ||");
4934 }
4935
4936 #[test]
4941 fn sequence_of_encode_side_check_uses_value_count() {
4942 let module = make_module(
4943 "Items",
4944 Type::SequenceOf(
4945 Box::new(Type::Integer(None, vec![])),
4946 Some(SizeConstraint::Range(Some(1), Some(4))),
4947 ),
4948 );
4949 let result = generate_c_impl(&module, impl_config()).unwrap();
4950 assert!(
4951 result.contains("value->count < (size_t)1ULL"),
4952 "encode-side lower bound uses value->count"
4953 );
4954 assert!(
4955 result.contains("value->count > (size_t)4ULL"),
4956 "encode-side upper bound uses value->count"
4957 );
4958 }
4959
4960 #[test]
4965 fn sequence_of_decode_check_before_assignment() {
4966 let module = make_module(
4967 "Items",
4968 Type::SequenceOf(
4969 Box::new(Type::Integer(None, vec![])),
4970 Some(SizeConstraint::Range(Some(1), None)),
4971 ),
4972 );
4973 let result = generate_c_impl(&module, impl_config()).unwrap();
4974 let check_pos = result
4976 .find("Validate SIZE constraint on collection")
4977 .expect("SIZE check present");
4978 let assign_pos = result
4979 .find("out->count = count;")
4980 .expect("assignment present");
4981 assert!(
4982 check_pos < assign_pos,
4983 "SIZE check comes before out->count assignment"
4984 );
4985 }
4986
4987 #[test]
4992 fn sequence_of_encode_check_before_loop() {
4993 let module = make_module(
4994 "Items",
4995 Type::SequenceOf(
4996 Box::new(Type::Integer(None, vec![])),
4997 Some(SizeConstraint::Range(Some(1), None)),
4998 ),
4999 );
5000 let result = generate_c_impl(&module, impl_config()).unwrap();
5001 let check_pos = result
5003 .find("Validate SIZE constraint before encoding")
5004 .expect("encode-side SIZE check present");
5005 let loop_pos = result
5006 .find("for (size_t i = 0;")
5007 .expect("encode loop present");
5008 assert!(
5009 check_pos < loop_pos,
5010 "encode SIZE check comes before the encode for-loop"
5011 );
5012 }
5013
5014 #[test]
5019 fn set_of_size_constraint_generates_check() {
5020 let module = make_module(
5021 "Items",
5022 Type::SetOf(
5023 Box::new(Type::Integer(None, vec![])),
5024 Some(SizeConstraint::Range(Some(1), Some(8))),
5025 ),
5026 );
5027 let result = generate_c_impl(&module, impl_config()).unwrap();
5028 assert!(result.contains("< (size_t)1ULL"), "lower bound for SET OF");
5029 assert!(result.contains("> (size_t)8ULL"), "upper bound for SET OF");
5030 }
5031
5032 #[test]
5037 fn constrained_sequence_of_modern_size() {
5038 let module = make_module(
5039 "Items",
5040 Type::Constrained {
5041 base_type: Box::new(Type::SequenceOf(
5042 Box::new(Type::Integer(None, vec![])),
5043 None,
5044 )),
5045 constraint: Constraint {
5046 spec: ConstraintSpec::Subtype(SubtypeConstraint::SizeConstraint(Box::new(
5047 SubtypeConstraint::ValueRange {
5048 min: ConstraintValue::Integer(2),
5049 max: ConstraintValue::Integer(6),
5050 },
5051 ))),
5052 exception: None,
5053 },
5054 },
5055 );
5056 let result = generate_c_impl(&module, impl_config()).unwrap();
5057 assert!(
5058 result.contains("< (size_t)2ULL"),
5059 "modern SIZE lower bound extracted"
5060 );
5061 assert!(
5062 result.contains("> (size_t)6ULL"),
5063 "modern SIZE upper bound extracted"
5064 );
5065 }
5066
5067 #[test]
5072 fn legacy_size_fixed_maps_to_equal_bounds() {
5073 let bounds = legacy_size_to_bounds(&SizeConstraint::Fixed(7));
5074 assert_eq!(bounds, (Some(7), Some(7)));
5075 }
5076
5077 #[test]
5078 fn legacy_size_range_maps_correctly() {
5079 let bounds = legacy_size_to_bounds(&SizeConstraint::Range(Some(1), Some(10)));
5080 assert_eq!(bounds, (Some(1), Some(10)));
5081 }
5082
5083 #[test]
5084 fn legacy_size_range_unbounded_max() {
5085 let bounds = legacy_size_to_bounds(&SizeConstraint::Range(Some(1), None));
5086 assert_eq!(bounds, (Some(1), None));
5087 }
5088
5089 #[test]
5090 fn modern_size_extracts_value_range() {
5091 let spec = ConstraintSpec::Subtype(SubtypeConstraint::SizeConstraint(Box::new(
5092 SubtypeConstraint::ValueRange {
5093 min: ConstraintValue::Integer(3),
5094 max: ConstraintValue::Integer(9),
5095 },
5096 )));
5097 let bounds = modern_size_to_bounds(&spec);
5098 assert_eq!(bounds, Some((Some(3), Some(9))));
5099 }
5100
5101 #[test]
5102 fn modern_size_non_size_constraint_returns_none() {
5103 let spec = ConstraintSpec::Subtype(SubtypeConstraint::ValueRange {
5104 min: ConstraintValue::Integer(0),
5105 max: ConstraintValue::Integer(100),
5106 });
5107 let bounds = modern_size_to_bounds(&spec);
5108 assert_eq!(bounds, None);
5109 }
5110
5111 fn make_constrained_sequence(field_base_ty: Type, constraint: SubtypeConstraint) -> Module {
5116 Module {
5117 name: "TestModule".to_string(),
5118 oid: None,
5119 values: vec![],
5120 tagging_mode: None,
5121 imports: vec![],
5122 exports: vec![],
5123 definitions: vec![Definition {
5124 name: "Msg".to_string(),
5125 ty: Type::Sequence(vec![SequenceField {
5126 name: "field".to_string(),
5127 ty: Type::Constrained {
5128 base_type: Box::new(field_base_ty),
5129 constraint: Constraint {
5130 spec: ConstraintSpec::Subtype(constraint),
5131 exception: None,
5132 },
5133 },
5134 optional: false,
5135 default: None,
5136 }]),
5137 }],
5138 }
5139 }
5140
5141 #[test]
5142 fn permitted_alphabet_ia5string_generates_loop() {
5143 let module = make_constrained_sequence(
5144 Type::IA5String(None),
5145 SubtypeConstraint::PermittedAlphabet(vec![CharRange { min: 'A', max: 'Z' }]),
5146 );
5147 let result = generate_c_impl(&module, impl_config()).unwrap();
5148 assert!(
5149 result.contains("for (_ai = 0; _ai < _alen; _ai++)"),
5150 "alphabet loop emitted"
5151 );
5152 assert!(result.contains("unsigned char _c = _ap[_ai]"), "byte fetch");
5153 assert!(result.contains("_c >= 'A' && _c <= 'Z'"), "range A-Z");
5154 assert!(
5155 result.contains("SyntaErrorCode_InvalidArgument"),
5156 "returns InvalidArgument on bad char"
5157 );
5158 }
5159
5160 #[test]
5161 fn permitted_alphabet_single_char_uses_equality() {
5162 let module = make_constrained_sequence(
5163 Type::IA5String(None),
5164 SubtypeConstraint::PermittedAlphabet(vec![CharRange { min: 'x', max: 'x' }]),
5165 );
5166 let result = generate_c_impl(&module, impl_config()).unwrap();
5167 assert!(result.contains("_c == 'x'"), "single char uses ==");
5168 assert!(!result.contains("_c >= 'x'"), "no range for single char");
5169 }
5170
5171 #[test]
5172 fn permitted_alphabet_multiple_ranges_joined_with_or() {
5173 let module = make_constrained_sequence(
5174 Type::IA5String(None),
5175 SubtypeConstraint::PermittedAlphabet(vec![
5176 CharRange { min: 'A', max: 'Z' },
5177 CharRange { min: '0', max: '9' },
5178 ]),
5179 );
5180 let result = generate_c_impl(&module, impl_config()).unwrap();
5181 assert!(result.contains("_c >= 'A' && _c <= 'Z'"), "first range");
5182 assert!(result.contains("_c >= '0' && _c <= '9'"), "second range");
5183 assert!(result.contains(" || "), "ranges joined with ||");
5184 }
5185
5186 #[test]
5187 fn permitted_alphabet_not_emitted_for_integer_field() {
5188 let module = make_constrained_sequence(
5190 Type::Integer(None, vec![]),
5191 SubtypeConstraint::PermittedAlphabet(vec![CharRange { min: 'A', max: 'Z' }]),
5192 );
5193 let result = generate_c_impl(&module, impl_config()).unwrap();
5194 assert!(
5195 !result.contains("for (_ai = 0"),
5196 "no alphabet loop for INTEGER"
5197 );
5198 }
5199
5200 #[test]
5201 fn permitted_alphabet_uses_synta_octet_string_helpers() {
5202 let module = make_constrained_sequence(
5203 Type::PrintableString(None),
5204 SubtypeConstraint::PermittedAlphabet(vec![CharRange { min: 'a', max: 'z' }]),
5205 );
5206 let result = generate_c_impl(&module, impl_config()).unwrap();
5207 assert!(
5208 result.contains("synta_octet_string_len("),
5209 "uses synta_octet_string_len"
5210 );
5211 assert!(
5212 result.contains("synta_octet_string_data("),
5213 "uses synta_octet_string_data"
5214 );
5215 }
5216
5217 #[test]
5218 fn intersection_emits_both_size_and_alphabet_checks() {
5219 let module = make_constrained_sequence(
5221 Type::IA5String(None),
5222 SubtypeConstraint::Intersection(vec![
5223 SubtypeConstraint::SizeConstraint(Box::new(SubtypeConstraint::ValueRange {
5224 min: ConstraintValue::Integer(1),
5225 max: ConstraintValue::Integer(64),
5226 })),
5227 SubtypeConstraint::PermittedAlphabet(vec![CharRange { min: 'A', max: 'Z' }]),
5228 ]),
5229 );
5230 let result = generate_c_impl(&module, impl_config()).unwrap();
5231 assert!(
5232 result.contains("Validate SIZE range constraint"),
5233 "SIZE check present"
5234 );
5235 assert!(
5236 result.contains("Validate FROM (permitted alphabet) constraint"),
5237 "alphabet check present"
5238 );
5239 }
5240
5241 #[test]
5242 fn intersection_size_check_before_alphabet_check() {
5243 let module = make_constrained_sequence(
5244 Type::IA5String(None),
5245 SubtypeConstraint::Intersection(vec![
5246 SubtypeConstraint::SizeConstraint(Box::new(SubtypeConstraint::ValueRange {
5247 min: ConstraintValue::Integer(1),
5248 max: ConstraintValue::Integer(64),
5249 })),
5250 SubtypeConstraint::PermittedAlphabet(vec![CharRange { min: 'A', max: 'Z' }]),
5251 ]),
5252 );
5253 let result = generate_c_impl(&module, impl_config()).unwrap();
5254 let size_pos = result
5255 .find("Validate SIZE range constraint")
5256 .expect("SIZE check present");
5257 let alpha_pos = result
5258 .find("Validate FROM (permitted alphabet) constraint")
5259 .expect("alphabet check present");
5260 assert!(size_pos < alpha_pos, "SIZE check precedes alphabet check");
5261 }
5262
5263 #[test]
5268 fn pattern_skip_emits_comment_not_regex() {
5269 let module = make_constrained_sequence(
5271 Type::IA5String(None),
5272 SubtypeConstraint::Pattern("[0-9]+".to_string()),
5273 );
5274 let result = generate_c_impl(&module, impl_config()).unwrap();
5275 assert!(
5276 result.contains("PATTERN constraint \"[0-9]+\" skipped"),
5277 "skip comment present"
5278 );
5279 assert!(
5280 !result.contains("regcomp") && !result.contains("pcre2_compile"),
5281 "no regex call in Skip mode"
5282 );
5283 }
5284
5285 #[test]
5286 fn pattern_posix_emits_regex_include_and_regcomp() {
5287 let module = make_constrained_sequence(
5288 Type::IA5String(None),
5289 SubtypeConstraint::Pattern("[A-Z]+".to_string()),
5290 );
5291 let config = CImplConfig {
5292 header_file: "test.h".to_string(),
5293 arena_mode: false,
5294 pattern_mode: PatternMode::Posix,
5295 with_containing: false,
5296 };
5297 let result = generate_c_impl(&module, config).unwrap();
5298 assert!(result.contains("#include <regex.h>"), "regex.h included");
5300 assert!(
5302 result.contains("Validate PATTERN constraint \"[A-Z]+\" (POSIX ERE)"),
5303 "posix comment present"
5304 );
5305 assert!(result.contains("regcomp("), "regcomp call present");
5307 assert!(result.contains("regexec("), "regexec call present");
5308 assert!(result.contains("regfree("), "regfree call present");
5309 assert!(
5311 !result.contains("pcre2_compile"),
5312 "no pcre2 call in Posix mode"
5313 );
5314 }
5315
5316 #[test]
5317 fn pattern_pcre2_emits_pcre2_include_and_compile() {
5318 let module = make_constrained_sequence(
5319 Type::IA5String(None),
5320 SubtypeConstraint::Pattern("[0-9]{3}".to_string()),
5321 );
5322 let config = CImplConfig {
5323 header_file: "test.h".to_string(),
5324 arena_mode: false,
5325 pattern_mode: PatternMode::Pcre2,
5326 with_containing: false,
5327 };
5328 let result = generate_c_impl(&module, config).unwrap();
5329 assert!(
5331 result.contains("#define PCRE2_CODE_UNIT_WIDTH 8"),
5332 "PCRE2 width define present"
5333 );
5334 assert!(result.contains("#include <pcre2.h>"), "pcre2.h included");
5335 assert!(
5337 result.contains("Validate PATTERN constraint \"[0-9]{3}\" (PCRE2)"),
5338 "pcre2 comment present"
5339 );
5340 assert!(result.contains("pcre2_compile("), "pcre2_compile call");
5342 assert!(result.contains("pcre2_match("), "pcre2_match call");
5343 assert!(result.contains("pcre2_code_free("), "pcre2_code_free call");
5344 assert!(!result.contains("regcomp"), "no regcomp in Pcre2 mode");
5346 }
5347
5348 #[test]
5349 fn pattern_non_string_type_no_validation() {
5350 let module = make_constrained_sequence(
5352 Type::Integer(None, vec![]),
5353 SubtypeConstraint::Pattern("[0-9]+".to_string()),
5354 );
5355 let config = CImplConfig {
5356 header_file: "test.h".to_string(),
5357 arena_mode: false,
5358 pattern_mode: PatternMode::Posix,
5359 with_containing: false,
5360 };
5361 let result = generate_c_impl(&module, config).unwrap();
5362 assert!(
5363 !result.contains("regcomp") && !result.contains("pcre2_compile"),
5364 "no regex for non-string type"
5365 );
5366 }
5367
5368 #[test]
5369 fn pattern_posix_escapes_special_chars() {
5370 let module = make_constrained_sequence(
5372 Type::IA5String(None),
5373 SubtypeConstraint::Pattern("\\d+".to_string()),
5374 );
5375 let config = CImplConfig {
5376 header_file: "test.h".to_string(),
5377 arena_mode: false,
5378 pattern_mode: PatternMode::Posix,
5379 with_containing: false,
5380 };
5381 let result = generate_c_impl(&module, config).unwrap();
5382 assert!(
5384 result.contains("\"\\\\d+\""),
5385 "backslash escaped in C string literal"
5386 );
5387 }
5388
5389 #[test]
5394 fn containing_skip_emits_comment_not_decoder() {
5395 let module = make_constrained_sequence(
5397 Type::OctetString(None),
5398 SubtypeConstraint::ContainedSubtype(Box::new(Type::TypeRef("Certificate".to_string()))),
5399 );
5400 let result = generate_c_impl(&module, impl_config()).unwrap();
5401 assert!(
5402 result.contains("CONTAINING constraint skipped"),
5403 "skip comment present"
5404 );
5405 assert!(
5406 !result.contains("synta_decoder_new"),
5407 "no decoder call in skip mode"
5408 );
5409 }
5410
5411 #[test]
5412 fn containing_enabled_emits_scratch_decoder_block() {
5413 let module = make_constrained_sequence(
5415 Type::OctetString(None),
5416 SubtypeConstraint::ContainedSubtype(Box::new(Type::TypeRef("Certificate".to_string()))),
5417 );
5418 let config = CImplConfig {
5419 header_file: "test.h".to_string(),
5420 arena_mode: false,
5421 pattern_mode: PatternMode::Skip,
5422 with_containing: true,
5423 };
5424 let result = generate_c_impl(&module, config).unwrap();
5425 assert!(
5427 result.contains("Validate CONTAINING constraint (Certificate)"),
5428 "containing comment present"
5429 );
5430 assert!(
5432 result.contains("synta_decoder_new("),
5433 "synta_decoder_new called"
5434 );
5435 assert!(
5436 result.contains("certificate_decode(_inner_dec, &_inner_val)"),
5437 "inner decode called"
5438 );
5439 assert!(
5440 result.contains("synta_decoder_free(_inner_dec)"),
5441 "decoder freed"
5442 );
5443 assert!(
5444 result.contains("certificate_free(&_inner_val)"),
5445 "inner value freed"
5446 );
5447 assert!(
5449 result.contains("SyntaErrorCode_InvalidArgument"),
5450 "returns InvalidArgument on decode failure"
5451 );
5452 }
5453
5454 #[test]
5455 fn containing_builtin_inner_type_emits_comment() {
5456 let module = make_constrained_sequence(
5458 Type::OctetString(None),
5459 SubtypeConstraint::ContainedSubtype(Box::new(Type::Integer(None, vec![]))),
5460 );
5461 let config = CImplConfig {
5462 header_file: "test.h".to_string(),
5463 arena_mode: false,
5464 pattern_mode: PatternMode::Skip,
5465 with_containing: true,
5466 };
5467 let result = generate_c_impl(&module, config).unwrap();
5468 assert!(
5469 result.contains("CONTAINING (built-in type): validation not generated"),
5470 "built-in comment present"
5471 );
5472 assert!(
5473 !result.contains("synta_decoder_new"),
5474 "no decoder for built-in type"
5475 );
5476 }
5477
5478 #[test]
5479 fn containing_non_byte_string_no_validation() {
5480 let module = make_constrained_sequence(
5482 Type::Integer(None, vec![]),
5483 SubtypeConstraint::ContainedSubtype(Box::new(Type::TypeRef("Inner".to_string()))),
5484 );
5485 let config = CImplConfig {
5486 header_file: "test.h".to_string(),
5487 arena_mode: false,
5488 pattern_mode: PatternMode::Skip,
5489 with_containing: true,
5490 };
5491 let result = generate_c_impl(&module, config).unwrap();
5492 assert!(
5493 !result.contains("synta_decoder_new"),
5494 "no containing check for non-byte-string base type"
5495 );
5496 }
5497
5498 fn make_default_seq(fields: Vec<SequenceField>) -> Module {
5503 Module {
5504 name: "TestModule".to_string(),
5505 oid: None,
5506 values: vec![],
5507 tagging_mode: None,
5508 imports: vec![],
5509 exports: vec![],
5510 definitions: vec![Definition {
5511 name: "Config".to_string(),
5512 ty: Type::Sequence(fields),
5513 }],
5514 }
5515 }
5516
5517 fn make_tagged_seq(
5522 field_name: &str,
5523 class: TagClass,
5524 number: u32,
5525 tagging: Tagging,
5526 inner: Type,
5527 optional: bool,
5528 ) -> Module {
5529 Module {
5530 name: "TestModule".to_string(),
5531 oid: None,
5532 values: vec![],
5533 tagging_mode: None,
5534 imports: vec![],
5535 exports: vec![],
5536 definitions: vec![Definition {
5537 name: "Msg".to_string(),
5538 ty: Type::Sequence(vec![SequenceField {
5539 name: field_name.to_string(),
5540 ty: Type::Tagged {
5541 tag: TagInfo {
5542 class,
5543 number,
5544 tagging,
5545 },
5546 inner: Box::new(inner),
5547 },
5548 optional,
5549 default: None,
5550 }]),
5551 }],
5552 }
5553 }
5554
5555 #[test]
5556 fn explicit_tag_decode_enters_constructed() {
5557 let module = make_tagged_seq(
5559 "id",
5560 TagClass::ContextSpecific,
5561 0,
5562 Tagging::Explicit,
5563 Type::Integer(None, vec![]),
5564 false,
5565 );
5566 let result = generate_c_impl(&module, impl_config()).unwrap();
5567 assert!(
5568 result.contains("synta_decoder_enter_constructed"),
5569 "explicit tag decode must use synta_decoder_enter_constructed; got:\n{}",
5570 result
5571 );
5572 assert!(
5573 result.contains("SyntaTagClass_ContextSpecific"),
5574 "explicit tag decode must set ContextSpecific class; got:\n{}",
5575 result
5576 );
5577 assert!(
5578 result.contains("explicit_tag.number = 0"),
5579 "explicit tag decode must set tag number 0; got:\n{}",
5580 result
5581 );
5582 assert!(
5583 result.contains("explicit_tag.constructed = true"),
5584 "explicit tag must be constructed; got:\n{}",
5585 result
5586 );
5587 assert!(
5588 result.contains("synta_decode_integer"),
5589 "inner type still decoded with synta_decode_integer; got:\n{}",
5590 result
5591 );
5592 }
5593
5594 #[test]
5595 fn explicit_tag_encode_starts_constructed() {
5596 let module = make_tagged_seq(
5598 "id",
5599 TagClass::ContextSpecific,
5600 0,
5601 Tagging::Explicit,
5602 Type::Integer(None, vec![]),
5603 false,
5604 );
5605 let result = generate_c_impl(&module, impl_config()).unwrap();
5606 assert!(
5607 result.contains("synta_encoder_start_constructed"),
5608 "explicit tag encode must use synta_encoder_start_constructed; got:\n{}",
5609 result
5610 );
5611 assert!(
5612 result.contains("synta_encoder_end_constructed"),
5613 "explicit tag encode must call synta_encoder_end_constructed; got:\n{}",
5614 result
5615 );
5616 assert!(
5617 result.contains("synta_encode_integer"),
5618 "inner type still encoded with synta_encode_integer; got:\n{}",
5619 result
5620 );
5621 }
5622
5623 #[test]
5624 fn explicit_optional_tag_peek_uses_tag_class_and_number() {
5625 let module = make_tagged_seq(
5627 "flag",
5628 TagClass::ContextSpecific,
5629 1,
5630 Tagging::Explicit,
5631 Type::Boolean,
5632 true,
5633 );
5634 let result = generate_c_impl(&module, impl_config()).unwrap();
5635 assert!(
5636 result.contains("synta_decoder_peek_tag"),
5637 "optional field must peek at tag; got:\n{}",
5638 result
5639 );
5640 assert!(
5641 result.contains("SyntaTagClass_ContextSpecific"),
5642 "peek must check ContextSpecific class; got:\n{}",
5643 result
5644 );
5645 assert!(
5646 result.contains("tag.number == 1"),
5647 "peek must check tag number 1; got:\n{}",
5648 result
5649 );
5650 }
5651
5652 #[test]
5653 fn implicit_tag_decode_emits_transparency_comment() {
5654 let module = make_tagged_seq(
5656 "data",
5657 TagClass::ContextSpecific,
5658 2,
5659 Tagging::Implicit,
5660 Type::OctetString(None),
5661 false,
5662 );
5663 let result = generate_c_impl(&module, impl_config()).unwrap();
5664 assert!(
5665 result.contains("IMPLICIT"),
5666 "implicit tag decode should emit IMPLICIT comment; got:\n{}",
5667 result
5668 );
5669 assert!(
5671 result.contains("synta_decode_octet_string"),
5672 "implicit tag falls back to inner type decode; got:\n{}",
5673 result
5674 );
5675 }
5676
5677 #[test]
5678 fn implicit_tag_encode_emits_transparency_comment() {
5679 let module = make_tagged_seq(
5681 "data",
5682 TagClass::ContextSpecific,
5683 2,
5684 Tagging::Implicit,
5685 Type::OctetString(None),
5686 false,
5687 );
5688 let result = generate_c_impl(&module, impl_config()).unwrap();
5689 assert!(
5690 result.contains("IMPLICIT"),
5691 "implicit tag encode should emit IMPLICIT comment; got:\n{}",
5692 result
5693 );
5694 assert!(
5696 result.contains("synta_encode_octet_string"),
5697 "implicit tag falls back to inner type encode; got:\n{}",
5698 result
5699 );
5700 }
5701
5702 #[test]
5703 fn explicit_tag_decode_frees_tagged_decoder_on_error() {
5704 let module = make_tagged_seq(
5706 "id",
5707 TagClass::ContextSpecific,
5708 0,
5709 Tagging::Explicit,
5710 Type::Integer(None, vec![]),
5711 false,
5712 );
5713 let result = generate_c_impl(&module, impl_config()).unwrap();
5714 assert!(
5716 result.contains("synta_decoder_free(tagged_decoder)"),
5717 "tagged_decoder must be freed; got:\n{}",
5718 result
5719 );
5720 }
5721
5722 #[test]
5723 fn default_bool_true_assigns_directly() {
5724 let module = make_default_seq(vec![SequenceField {
5726 name: "enabled".to_string(),
5727 ty: Type::Boolean,
5728 optional: false,
5729 default: Some("TRUE".to_string()),
5730 }]);
5731 let result = generate_c_impl(&module, impl_config()).unwrap();
5732 assert!(
5733 result.contains("Config config_default(void)"),
5734 "_default function present"
5735 );
5736 assert!(
5737 result.contains("out.enabled = true;"),
5738 "TRUE default assigned"
5739 );
5740 }
5741
5742 #[test]
5743 fn default_bool_false_no_assignment() {
5744 let module = make_default_seq(vec![SequenceField {
5746 name: "disabled".to_string(),
5747 ty: Type::Boolean,
5748 optional: false,
5749 default: Some("FALSE".to_string()),
5750 }]);
5751 let result = generate_c_impl(&module, impl_config()).unwrap();
5752 assert!(
5753 result.contains("Config config_default(void)"),
5754 "_default function present"
5755 );
5756 assert!(
5757 !result.contains("out.disabled = false;"),
5758 "no redundant false assignment"
5759 );
5760 }
5761
5762 #[test]
5763 fn default_integer_emits_comment() {
5764 let module = make_default_seq(vec![SequenceField {
5766 name: "port".to_string(),
5767 ty: Type::Integer(None, vec![]),
5768 optional: false,
5769 default: Some("8080".to_string()),
5770 }]);
5771 let result = generate_c_impl(&module, impl_config()).unwrap();
5772 assert!(
5773 result.contains("/* out.port: DEFAULT 8080"),
5774 "integer default comment emitted"
5775 );
5776 assert!(
5777 !result.contains("out.port = 8080"),
5778 "no direct assignment for pointer integer"
5779 );
5780 }
5781
5782 #[test]
5783 fn default_function_not_generated_for_required_field() {
5784 let module = make_default_seq(vec![SequenceField {
5786 name: "name".to_string(),
5787 ty: Type::Integer(None, vec![]),
5788 optional: false,
5789 default: None,
5790 }]);
5791 let result = generate_c_impl(&module, impl_config()).unwrap();
5792 assert!(
5793 !result.contains("_default(void)"),
5794 "no _default for required-field sequence"
5795 );
5796 }
5797
5798 #[test]
5799 fn default_function_for_all_optional_sequence() {
5800 let module = make_default_seq(vec![
5802 SequenceField {
5803 name: "host".to_string(),
5804 ty: Type::OctetString(None),
5805 optional: true,
5806 default: None,
5807 },
5808 SequenceField {
5809 name: "port".to_string(),
5810 ty: Type::Integer(None, vec![]),
5811 optional: true,
5812 default: None,
5813 },
5814 ]);
5815 let result = generate_c_impl(&module, impl_config()).unwrap();
5816 assert!(
5817 result.contains("Config config_default(void)"),
5818 "_default function present"
5819 );
5820 assert!(result.contains("Config out = {0};"), "zero-init present");
5821 assert!(result.contains("return out;"), "returns out");
5822 }
5823}