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