1#![allow(clippy::module_name_repetitions)]
84
85use core::fmt::Write as _;
86use std::collections::{BTreeMap, BTreeSet};
87
88use zerodds_idl::ast::{
89 Annotation, AnnotationParams, BitmaskDecl, BitsetDecl, Case, CaseLabel, ConstExpr,
90 ConstrTypeDecl, Declarator, Definition, EnumDef, FloatingType, IntegerType, LiteralKind,
91 ModuleDef, PrimitiveType, ScopedName, Specification, StructDcl, StructDef, SwitchTypeSpec,
92 TypeDecl, TypeSpec, UnionDcl, UnionDef,
93};
94use zerodds_idl::semantics::const_eval::{Symbol, SymbolTable, evaluate, evaluate_positive_int};
95
96use crate::error::CppGenError;
97
98#[derive(Default)]
102struct TypeReg {
103 enums: BTreeMap<String, String>,
105 enum_bytes: BTreeMap<String, u32>,
109 typedefs: BTreeMap<String, TypeSpec>,
111 typedef_arrays: BTreeMap<String, Vec<u64>>,
115 bitmasks: BTreeMap<String, (String, &'static str)>,
119 bitsets: BTreeMap<String, (String, &'static str)>,
123 structs: BTreeMap<String, (String, StructDef)>,
125 unions: BTreeMap<String, (String, UnionDef)>,
127 recursive: BTreeSet<String>,
133 consts: SymbolTable,
139}
140
141impl TypeReg {
142 fn build(defs: &[Definition]) -> Self {
143 let mut r = TypeReg::default();
144 collect_types(defs, &[], &mut r);
145 r.compute_recursive();
146 r
147 }
148
149 fn compute_recursive(&mut self) {
156 let names: Vec<String> = self
157 .structs
158 .keys()
159 .chain(self.unions.keys())
160 .cloned()
161 .collect();
162 let mut recursive = BTreeSet::new();
163 for start in &names {
164 let mut seen = BTreeSet::new();
165 if self.reaches(start, start, &mut seen) {
166 recursive.insert(start.clone());
167 }
168 }
169 self.recursive = recursive;
170 }
171
172 fn reaches(&self, from: &str, target: &str, seen: &mut BTreeSet<String>) -> bool {
176 if !seen.insert(from.to_string()) {
177 return false;
178 }
179 let mut refs: Vec<String> = Vec::new();
180 if let Some((_, sdef)) = self.structs.get(from) {
181 for m in &sdef.members {
182 self.collect_aggregate_refs(&m.type_spec, &mut refs);
183 }
184 }
185 if let Some((_, udef)) = self.unions.get(from) {
186 self.collect_aggregate_refs(&switch_type_spec(&udef.switch_type), &mut refs);
187 for c in &udef.cases {
188 self.collect_aggregate_refs(&c.element.type_spec, &mut refs);
189 }
190 }
191 for r in refs {
192 if r == target {
193 return true;
194 }
195 if self.reaches(&r, target, seen) {
196 return true;
197 }
198 }
199 false
200 }
201
202 fn collect_aggregate_refs(&self, ts: &TypeSpec, out: &mut Vec<String>) {
207 let resolved = resolve_alias(self, ts);
208 match &resolved {
209 TypeSpec::Scoped(sc) => {
210 if let Some(last) = scoped_last(sc) {
211 if self.structs.contains_key(&last) || self.unions.contains_key(&last) {
212 out.push(last);
213 }
214 }
215 }
216 TypeSpec::Sequence(seq) => self.collect_aggregate_refs(&seq.elem, out),
217 TypeSpec::Map(m) => {
218 self.collect_aggregate_refs(&m.key, out);
219 self.collect_aggregate_refs(&m.value, out);
220 }
221 _ => {}
222 }
223 }
224
225 fn is_recursive(&self, name: &str) -> bool {
226 self.recursive.contains(name)
227 }
228}
229
230fn collect_types(defs: &[Definition], scope: &[String], r: &mut TypeReg) {
232 for d in defs {
233 match d {
234 Definition::Module(m) => {
235 let mut s = scope.to_vec();
236 s.push(m.name.text.clone());
237 collect_types(&m.definitions, &s, r);
238 }
239 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Enum(e))) => {
240 r.enums
241 .insert(e.name.text.clone(), c_identifier(scope, &e.name.text));
242 let ebound = extract_int_annotation_c(&e.annotations, "bit_bound")
243 .filter(|&v| (1..=32).contains(&v))
244 .unwrap_or(32);
245 let ebytes = if ebound <= 8 {
246 1
247 } else if ebound <= 16 {
248 2
249 } else {
250 4
251 };
252 r.enum_bytes.insert(e.name.text.clone(), ebytes);
253 let type_name = scope_join(scope, &e.name.text, "::");
257 for (i, en) in e.enumerators.iter().enumerate() {
258 let sym = Symbol::EnumValue {
259 type_name: type_name.clone(),
260 value: i32::try_from(i).unwrap_or(0),
261 };
262 r.consts.insert(en.name.text.clone(), sym.clone());
263 r.consts.insert(scope_join(scope, &en.name.text, "::"), sym);
264 }
265 }
266 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Struct(StructDcl::Def(s)))) => {
267 r.structs.insert(
268 s.name.text.clone(),
269 (c_identifier(scope, &s.name.text), s.clone()),
270 );
271 }
272 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Union(UnionDcl::Def(u)))) => {
273 r.unions.insert(
274 u.name.text.clone(),
275 (c_identifier(scope, &u.name.text), u.clone()),
276 );
277 }
278 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Bitmask(b))) => {
279 let holder = bitmask_holder_c_type(b);
280 r.bitmasks.insert(
281 b.name.text.clone(),
282 (c_identifier(scope, &b.name.text), holder),
283 );
284 }
285 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Bitset(b))) => {
286 let holder = bitset_holder_c_type(b);
287 r.bitsets.insert(
288 b.name.text.clone(),
289 (c_identifier(scope, &b.name.text), holder),
290 );
291 }
292 Definition::Type(TypeDecl::Typedef(td)) => {
293 for decl in &td.declarators {
294 match decl {
295 Declarator::Simple(n) => {
296 r.typedefs.insert(n.text.clone(), td.type_spec.clone());
297 }
298 Declarator::Array(arr) => {
299 r.typedefs
303 .insert(arr.name.text.clone(), td.type_spec.clone());
304 let dims: Vec<u64> = arr
305 .sizes
306 .iter()
307 .map(|sz| const_expr_to_u64_pre(&r.consts, sz).unwrap_or(0))
308 .collect();
309 r.typedef_arrays.insert(arr.name.text.clone(), dims);
310 }
311 }
312 }
313 }
314 Definition::Const(c) => {
315 if let Ok(v) = evaluate(&c.value, &r.consts) {
319 r.consts
320 .insert(c.name.text.clone(), Symbol::Const(v.clone()));
321 r.consts
322 .insert(scope_join(scope, &c.name.text, "::"), Symbol::Const(v));
323 }
324 }
325 _ => {}
326 }
327 }
328}
329
330fn resolve_alias(reg: &TypeReg, ts: &TypeSpec) -> TypeSpec {
333 let mut cur = ts.clone();
334 for _ in 0..16 {
335 let TypeSpec::Scoped(s) = &cur else { break };
336 let Some(last) = s.parts.last() else { break };
337 let Some(aliased) = reg.typedefs.get(&last.text).cloned() else {
338 break;
339 };
340 cur = aliased;
341 }
342 cur
343}
344
345fn scoped_last(s: &ScopedName) -> Option<String> {
346 s.parts.last().map(|p| p.text.clone())
347}
348
349fn unsupported(kind: &'static str) -> CppGenError {
350 CppGenError::UnsupportedConstruct {
351 construct: kind.to_string(),
352 context: None,
353 }
354}
355
356#[derive(Debug, Clone, Default)]
358pub struct CGenOptions {
359 pub include_guard: Option<String>,
361 pub file_header: Option<String>,
363}
364
365pub fn generate_c_header(ast: &Specification, opts: &CGenOptions) -> Result<String, CppGenError> {
376 let reg = TypeReg::build(&ast.definitions);
377 let mut ctx = Ctx::new(opts, ®);
378 ctx.emit_preamble();
379 ctx.emit_enums(&ast.definitions, &[]);
381 ctx.emit_bits(&ast.definitions, &[]);
383 ctx.emit_all_aggregate_typedefs(&ast.definitions)?;
389 ctx.emit_recursive_helpers()?;
393 ctx.walk_definitions(&ast.definitions, &[])?;
394 ctx.emit_postamble();
395 Ok(ctx.out)
396}
397
398struct Ctx<'a> {
403 out: String,
404 opts: &'a CGenOptions,
405 reg: &'a TypeReg,
406 coll_depth: u32,
411}
412
413#[derive(Debug, Clone, Copy, PartialEq, Eq)]
414enum Extensibility {
415 Final,
416 Appendable,
417 Mutable,
418}
419
420impl<'a> Ctx<'a> {
421 fn new(opts: &'a CGenOptions, reg: &'a TypeReg) -> Self {
422 Self {
423 out: String::new(),
424 opts,
425 reg,
426 coll_depth: 0,
427 }
428 }
429
430 fn emit_enums(&mut self, defs: &[Definition], scope: &[String]) {
434 for d in defs {
435 match d {
436 Definition::Module(m) => {
437 let mut s = scope.to_vec();
438 s.push(m.name.text.clone());
439 self.emit_enums(&m.definitions, &s);
440 }
441 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Enum(e))) => {
442 self.emit_enum(e, scope);
443 }
444 _ => {}
445 }
446 }
447 }
448
449 fn emit_enum(&mut self, e: &EnumDef, scope: &[String]) {
450 let c_name = c_identifier(scope, &e.name.text);
451 let _ = writeln!(self.out, "typedef int32_t {c_name}_t;");
452 for (i, en) in e.enumerators.iter().enumerate() {
453 let _ = writeln!(
456 self.out,
457 "enum {{ {c_name}_{label} = {i} }};",
458 label = en.name.text
459 );
460 }
461 let _ = writeln!(self.out);
462 }
463
464 fn emit_bits(&mut self, defs: &[Definition], scope: &[String]) {
470 for d in defs {
471 match d {
472 Definition::Module(m) => {
473 let mut s = scope.to_vec();
474 s.push(m.name.text.clone());
475 self.emit_bits(&m.definitions, &s);
476 }
477 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Bitmask(b))) => {
478 self.emit_bitmask(b, scope);
479 }
480 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Bitset(b))) => {
481 self.emit_bitset(b, scope);
482 }
483 _ => {}
484 }
485 }
486 }
487
488 fn emit_bitmask(&mut self, b: &BitmaskDecl, scope: &[String]) {
489 let c_name = c_identifier(scope, &b.name.text);
490 let holder = bitmask_holder_c_type(b);
491 let _ = writeln!(self.out, "typedef {holder} {c_name}_t;");
492 let mut next_pos: u32 = 0;
493 for v in &b.values {
494 let pos = extract_int_annotation_c(&v.annotations, "position").unwrap_or(next_pos);
495 next_pos = pos.saturating_add(1);
496 let _ = writeln!(
499 self.out,
500 "enum {{ {c_name}_{label} = (1u << {pos}) }};",
501 label = v.name.text
502 );
503 }
504 let _ = writeln!(self.out);
505 }
506
507 fn emit_bitset(&mut self, b: &BitsetDecl, scope: &[String]) {
508 let c_name = c_identifier(scope, &b.name.text);
509 let holder = bitset_holder_c_type(b);
510 let _ = writeln!(self.out, "typedef {holder} {c_name}_t;");
511 let mut offset: u32 = 0;
514 for f in &b.bitfields {
515 let width = match &f.spec.width {
516 ConstExpr::Literal(l) if l.kind == LiteralKind::Integer => {
517 l.raw.trim().parse::<u32>().unwrap_or(0)
518 }
519 _ => 0,
520 };
521 if let Some(name) = &f.name {
522 let mask: u64 = if width >= 64 {
523 u64::MAX
524 } else {
525 (1u64 << width) - 1
526 };
527 let _ = writeln!(
528 self.out,
529 "enum {{ {c_name}_{field}_SHIFT = {offset} }};",
530 field = name.text
531 );
532 let _ = writeln!(
533 self.out,
534 "#define {c_name}_{field}_MASK 0x{mask:X}u",
535 field = name.text
536 );
537 }
538 offset = offset.saturating_add(width);
539 }
540 let _ = writeln!(self.out);
541 }
542
543 fn emit_union_typedef(&mut self, u: &UnionDef, scope: &[String]) -> Result<(), CppGenError> {
547 let c_name = c_identifier(scope, &u.name.text);
548 let disc_ts = switch_type_spec(&u.switch_type);
549 let disc_c = c_type_for(self.reg, &disc_ts)?;
550 let _ = writeln!(self.out, "typedef struct {c_name}_s {{");
551 let _ = writeln!(self.out, " {disc_c} _d;");
552 let _ = writeln!(self.out, " union {{");
553 for case in &u.cases {
554 let field = union_case_field(case);
555 let c_type = c_type_for(self.reg, &case.element.type_spec)?;
556 let dims =
557 effective_array_dims(self.reg, &case.element.type_spec, &case.element.declarator)?;
558 if dims.is_empty() {
559 let _ = writeln!(self.out, " {c_type} {field};");
560 } else {
561 let suffix: String = dims.iter().map(|n| format!("[{n}]")).collect();
562 let _ = writeln!(self.out, " {c_type} {field}{suffix};");
563 }
564 }
565 let _ = writeln!(self.out, " }} _u;");
566 let _ = writeln!(self.out, "}} {c_name}_t;");
567 let _ = writeln!(self.out);
568 Ok(())
569 }
570
571 fn emit_union_typesupport(
574 &mut self,
575 u: &UnionDef,
576 scope: &[String],
577 ) -> Result<(), CppGenError> {
578 let c_name = c_identifier(scope, &u.name.text);
579 let dds_name = dds_type_name(scope, &u.name.text);
580 let ext = extensibility_of(&u.annotations);
581
582 let _ = writeln!(
583 self.out,
584 "static int {c_name}_encode(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len);"
585 );
586 let _ = writeln!(
587 self.out,
588 "static int {c_name}_decode(const uint8_t* buf, size_t len, void* out_sample);\nstatic int {c_name}_decode_e(const uint8_t* buf, size_t len, void* out_sample, int zd_be);"
589 );
590 let _ = writeln!(
591 self.out,
592 "static int {c_name}_decode_repr(const uint8_t* buf, size_t len, uint8_t representation, void* out_sample);"
593 );
594 let _ = writeln!(self.out, "static void {c_name}_sample_free(void* sample);");
595 let _ = writeln!(self.out);
596 let _ = writeln!(
597 self.out,
598 "static const char {c_name}_type_name[] = \"{dds_name}\";"
599 );
600 let _ = writeln!(
601 self.out,
602 "static const zerodds_typesupport_t {c_name}_typesupport = {{"
603 );
604 let _ = writeln!(self.out, " .type_hash = {{0}},");
605 let _ = writeln!(self.out, " .type_name = {c_name}_type_name,");
606 let _ = writeln!(self.out, " .is_keyed = 0,");
607 let _ = writeln!(self.out, " .extensibility = {},", ext.as_u8());
608 let _ = writeln!(self.out, " ._reserved = {{0}},");
609 let _ = writeln!(self.out, " .encode = {c_name}_encode,");
610 let _ = writeln!(self.out, " .decode = {c_name}_decode,");
611 let _ = writeln!(self.out, " .key_hash = NULL,");
612 let _ = writeln!(self.out, " .sample_free = {c_name}_sample_free,");
613 let _ = writeln!(self.out, " .decode_repr = {c_name}_decode_repr,");
614 let _ = writeln!(self.out, "}};");
615 let _ = writeln!(self.out);
616
617 let _ = writeln!(
619 self.out,
620 "static int {c_name}_encode_repr(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len, int representation);"
621 );
622 let _ = writeln!(
623 self.out,
624 "static int {c_name}_encode(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len) {{ return {c_name}_encode_repr(sample, out_buf, out_cap, out_len, 1); }}"
625 );
626 let _ = writeln!(
627 self.out,
628 "static int {c_name}_encode_repr(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len, int representation) {{"
629 );
630 let _ = writeln!(
631 self.out,
632 " const {c_name}_t* s = (const {c_name}_t*)sample;"
633 );
634 let _ = writeln!(self.out, " (void)s;");
635 let _ = writeln!(
636 self.out,
637 " size_t zd_ma = representation ? 4 : 8; (void)zd_ma;"
638 );
639 let _ = writeln!(self.out, " uint8_t* w_buf = NULL;");
640 let _ = writeln!(self.out, " size_t w_len = 0;");
641 let _ = writeln!(self.out, " size_t w_cap = 0;");
642 let _ = writeln!(
643 self.out,
644 " if (out_buf == NULL && out_cap > 0) goto fail;"
645 );
646 let _ = ext;
649 self.emit_union_write("(*s)", u)?;
650 let _ = writeln!(self.out, " if (out_len) *out_len = w_len;");
651 let _ = writeln!(
652 self.out,
653 " if (out_buf == NULL || out_cap < w_len) {{ free(w_buf); return -13; }}"
654 );
655 let _ = writeln!(
656 self.out,
657 " if (w_len > 0) memcpy(out_buf, w_buf, w_len);"
658 );
659 let _ = writeln!(self.out, " free(w_buf);");
660 let _ = writeln!(self.out, " return 0;");
661 let _ = writeln!(self.out, "fail:");
662 let _ = writeln!(self.out, " free(w_buf);");
663 let _ = writeln!(self.out, " return -1;");
664 let _ = writeln!(self.out, "}}");
665 let _ = writeln!(self.out);
666
667 let _ = writeln!(
669 self.out,
670 "static int {c_name}_decode_core(const uint8_t* buf, size_t len, void* out_sample, int zd_be, int representation);"
671 );
672 let _ = writeln!(
673 self.out,
674 "static int {c_name}_decode(const uint8_t* buf, size_t len, void* out_sample) {{ return {c_name}_decode_core(buf, len, out_sample, 0, 1); }}"
675 );
676 let _ = writeln!(
677 self.out,
678 "static int {c_name}_decode_e(const uint8_t* buf, size_t len, void* out_sample, int zd_be) {{ return {c_name}_decode_core(buf, len, out_sample, zd_be, 1); }}"
679 );
680 let _ = writeln!(
681 self.out,
682 "static int {c_name}_decode_repr(const uint8_t* buf, size_t len, uint8_t representation, void* out_sample) {{ return {c_name}_decode_core(buf, len, out_sample, 0, representation ? 1 : 0); }}"
683 );
684 let _ = writeln!(
685 self.out,
686 "static int {c_name}_decode_core(const uint8_t* buf, size_t len, void* out_sample, int zd_be, int representation) {{"
687 );
688 let _ = writeln!(self.out, " {c_name}_t* s = ({c_name}_t*)out_sample;");
689 let _ = writeln!(self.out, " size_t pos = 0;");
690 let _ = writeln!(
691 self.out,
692 " size_t zd_ma = representation ? 4 : 8; (void)zd_ma;"
693 );
694 self.emit_union_read("(*s)", u)?;
696 let _ = writeln!(self.out, " (void)s;");
697 let _ = writeln!(self.out, " return 0;");
698 let _ = writeln!(self.out, "}}");
699 let _ = writeln!(self.out);
700
701 let _ = writeln!(
703 self.out,
704 "static void {c_name}_sample_free(void* sample) {{"
705 );
706 let _ = writeln!(self.out, " if (sample == NULL) return;");
707 let _ = writeln!(self.out, " {c_name}_t* s = ({c_name}_t*)sample;");
708 let _ = writeln!(self.out, " (void)s;");
709 let _ = writeln!(self.out, "}}");
710 let _ = writeln!(self.out);
711 Ok(())
712 }
713
714 fn emit_preamble(&mut self) {
715 let guard = self
716 .opts
717 .include_guard
718 .clone()
719 .unwrap_or_else(|| "ZERODDS_GENERATED_H".to_string());
720 if let Some(h) = &self.opts.file_header {
721 for line in h.lines() {
722 let _ = writeln!(self.out, "/* {line} */");
723 }
724 } else {
725 let _ = writeln!(
726 self.out,
727 "/* Generated by zerodds idl-cpp c_mode. Do not edit. */"
728 );
729 }
730 let _ = writeln!(self.out, "#ifndef {guard}");
731 let _ = writeln!(self.out, "#define {guard}");
732 let _ = writeln!(self.out, "#include <stddef.h>");
733 let _ = writeln!(self.out, "#include <stdint.h>");
734 let _ = writeln!(self.out, "#include <string.h>");
735 let _ = writeln!(self.out, "#include <stdlib.h>");
736 let _ = writeln!(self.out, "#include \"zerodds_xcdr2.h\"");
746 let _ = writeln!(self.out, "#ifdef __cplusplus");
747 let _ = writeln!(self.out, "extern \"C\" {{");
748 let _ = writeln!(self.out, "#endif");
749 let _ = writeln!(self.out);
750 let _ = writeln!(self.out, "#ifndef ZERODDS_X2_ALIGN4_8BYTE");
757 let _ = writeln!(self.out, "#define ZERODDS_X2_ALIGN4_8BYTE");
758 let _ = writeln!(
759 self.out,
760 "static inline int zd_x2_write_u64(uint8_t** buf, size_t* len, size_t* cap, uint64_t v) {{"
761 );
762 let _ = writeln!(
763 self.out,
764 " if (zerodds_xcdr2_c_pad_to(buf, len, cap, 4) != 0) return -1;"
765 );
766 let _ = writeln!(
767 self.out,
768 " if (zerodds_xcdr2_c_grow(buf, cap, *len + 8) != 0) return -1;"
769 );
770 let _ = writeln!(
771 self.out,
772 " for (int i = 0; i < 8; ++i) {{ (*buf)[(*len)++] = (uint8_t)((v >> (8 * i)) & 0xFFu); }}"
773 );
774 let _ = writeln!(self.out, " return 0;");
775 let _ = writeln!(self.out, "}}");
776 let _ = writeln!(
777 self.out,
778 "static inline int zd_x2_write_i64(uint8_t** buf, size_t* len, size_t* cap, int64_t v) {{ return zd_x2_write_u64(buf, len, cap, (uint64_t)v); }}"
779 );
780 let _ = writeln!(
781 self.out,
782 "static inline int zd_x2_write_f64(uint8_t** buf, size_t* len, size_t* cap, double v) {{ uint64_t u; memcpy(&u, &v, sizeof(u)); return zd_x2_write_u64(buf, len, cap, u); }}"
783 );
784 let _ = writeln!(
785 self.out,
786 "static inline int zd_x2_read_u64(const uint8_t* buf, size_t len, size_t* pos, uint64_t* out, int big_endian) {{"
787 );
788 let _ = writeln!(
789 self.out,
790 " if (zerodds_xcdr2_c_pad_read(buf, len, pos, 4) != 0) return -1;"
791 );
792 let _ = writeln!(self.out, " if (*pos + 8 > len) return -1;");
793 let _ = writeln!(self.out, " uint64_t v = 0;");
794 let _ = writeln!(
795 self.out,
796 " for (int i = 0; i < 8; ++i) {{ int sh = big_endian ? (8 * (7 - i)) : (8 * i); v |= (uint64_t)buf[*pos + (size_t)i] << sh; }}"
797 );
798 let _ = writeln!(self.out, " *pos += 8; *out = v; return 0;");
799 let _ = writeln!(self.out, "}}");
800 let _ = writeln!(
801 self.out,
802 "static inline int zd_x2_read_i64(const uint8_t* buf, size_t len, size_t* pos, int64_t* out, int big_endian) {{ uint64_t u; int rc = zd_x2_read_u64(buf, len, pos, &u, big_endian); if (rc != 0) return rc; *out = (int64_t)u; return 0; }}"
803 );
804 let _ = writeln!(
805 self.out,
806 "static inline int zd_x2_read_f64(const uint8_t* buf, size_t len, size_t* pos, double* out, int big_endian) {{ uint64_t u; int rc = zd_x2_read_u64(buf, len, pos, &u, big_endian); if (rc != 0) return rc; memcpy(out, &u, sizeof(*out)); return 0; }}"
807 );
808 let _ = writeln!(self.out, "#endif");
809 let _ = writeln!(self.out);
810 }
811
812 fn helper_call_prefix(helper: &str) -> &'static str {
818 match helper {
819 "u64" | "i64" | "f64" => "zd_x2_",
820 _ => "zerodds_xcdr2_c_",
821 }
822 }
823
824 fn bits_helper(&self, name: &str) -> Option<&'static str> {
828 let holder = self
829 .reg
830 .bitmasks
831 .get(name)
832 .or_else(|| self.reg.bitsets.get(name))
833 .map(|(_, h)| *h)?;
834 Some(match holder {
835 "uint8_t" => "u8",
836 "uint16_t" => "u16",
837 "uint32_t" => "u32",
838 _ => "u64",
839 })
840 }
841
842 fn emit_postamble(&mut self) {
843 let _ = writeln!(self.out, "#ifdef __cplusplus");
844 let _ = writeln!(self.out, "}}");
845 let _ = writeln!(self.out, "#endif");
846 let _ = writeln!(self.out, "#endif");
847 }
848
849 fn walk_definitions(
850 &mut self,
851 defs: &[Definition],
852 scope: &[String],
853 ) -> Result<(), CppGenError> {
854 for d in defs {
855 match d {
856 Definition::Module(m) => self.walk_module(m, scope)?,
857 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Struct(sd))) => {
858 if let zerodds_idl::ast::StructDcl::Def(def) = sd {
859 self.emit_struct(def, scope)?;
860 }
861 }
862 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Enum(_)))
867 | Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Bitmask(_)))
868 | Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Bitset(_)))
869 | Definition::Type(TypeDecl::Typedef(_)) => {}
870 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Union(ud))) => {
871 if let UnionDcl::Def(def) = ud {
875 self.emit_union_typesupport(def, scope)?;
876 }
877 }
878 Definition::Type(_) => {
879 return Err(unsupported("non-struct type"));
880 }
881 Definition::Const(_)
883 | Definition::Annotation(_)
884 | Definition::TypeId(_)
885 | Definition::TypePrefix(_)
886 | Definition::Import(_) => {
887 }
889 _ => {
890 return Err(unsupported("non-struct definition"));
891 }
892 }
893 }
894 Ok(())
895 }
896
897 fn walk_module(&mut self, m: &ModuleDef, scope: &[String]) -> Result<(), CppGenError> {
898 let mut new_scope = scope.to_vec();
899 new_scope.push(m.name.text.clone());
900 self.walk_definitions(&m.definitions, &new_scope)
901 }
902
903 fn emit_struct_typedef(
909 &mut self,
910 def: &StructDef,
911 scope: &[String],
912 ) -> Result<(), CppGenError> {
913 let c_name = c_identifier(scope, &def.name.text);
914 let _ = writeln!(self.out, "typedef struct {c_name}_s {{");
915 for member in &def.members {
916 let optional = is_optional(&member.annotations);
917 for decl in &member.declarators {
918 let m_name = decl.name();
919 let c_type = c_type_for(self.reg, &member.type_spec)?;
920 let dims = effective_array_dims(self.reg, &member.type_spec, decl)?;
923 if dims.is_empty() {
924 let _ = writeln!(self.out, " {c_type} {field};", field = m_name.text);
925 } else {
926 let suffix: String = dims.iter().map(|n| format!("[{n}]")).collect();
927 let _ = writeln!(
928 self.out,
929 " {c_type} {field}{suffix};",
930 field = m_name.text
931 );
932 }
933 if optional {
936 let _ = writeln!(
937 self.out,
938 " uint8_t {field}_present;",
939 field = m_name.text
940 );
941 }
942 }
943 }
944 if def.members.is_empty() {
945 let _ = writeln!(self.out, " uint8_t _zerodds_empty;");
947 }
948 let _ = writeln!(self.out, "}} {c_name}_t;");
949 let _ = writeln!(self.out);
950 Ok(())
951 }
952
953 fn emit_all_aggregate_typedefs(&mut self, defs: &[Definition]) -> Result<(), CppGenError> {
963 let mut order: Vec<(String, Vec<String>, AggDef)> = Vec::new();
965 collect_aggregates(defs, &[], &mut order);
966 for (name, _, agg) in &order {
968 let mut seen = BTreeSet::new();
969 if self.by_value_reaches(agg, name, &mut seen) {
970 return Err(CppGenError::UnsupportedConstruct {
971 construct: "infinite-size type: a struct/union member references its own \
972 type by value (a self-reference is only legal heap-indirected, \
973 e.g. through a sequence)"
974 .to_string(),
975 context: Some(name.clone()),
976 });
977 }
978 }
979 let mut emitted: BTreeSet<String> = BTreeSet::new();
981 let mut remaining: Vec<(String, Vec<String>, AggDef)> = order;
982 let max_passes = remaining.len() + 1;
985 for _ in 0..max_passes {
986 if remaining.is_empty() {
987 break;
988 }
989 let mut progressed = false;
990 let mut next: Vec<(String, Vec<String>, AggDef)> = Vec::new();
991 for (name, scope, agg) in remaining.drain(..) {
992 let deps = self.by_value_agg_deps(&agg);
993 if deps.iter().all(|d| emitted.contains(d) || d == &name) {
994 match &agg {
995 AggDef::Struct(s) => self.emit_struct_typedef(s, &scope)?,
996 AggDef::Union(u) => self.emit_union_typedef(u, &scope)?,
997 }
998 emitted.insert(name);
999 progressed = true;
1000 } else {
1001 next.push((name, scope, agg));
1002 }
1003 }
1004 remaining = next;
1005 if !progressed {
1006 for (name, scope, agg) in remaining.drain(..) {
1009 match &agg {
1010 AggDef::Struct(s) => self.emit_struct_typedef(s, &scope)?,
1011 AggDef::Union(u) => self.emit_union_typedef(u, &scope)?,
1012 }
1013 emitted.insert(name);
1014 }
1015 break;
1016 }
1017 }
1018 Ok(())
1019 }
1020
1021 fn by_value_agg_deps(&self, agg: &AggDef) -> Vec<String> {
1025 let mut out = Vec::new();
1026 let push_ts = |ts: &TypeSpec, out: &mut Vec<String>| {
1027 let resolved = resolve_alias(self.reg, ts);
1028 if let TypeSpec::Scoped(sc) = &resolved {
1029 if let Some(last) = scoped_last(sc) {
1030 if self.reg.structs.contains_key(&last) || self.reg.unions.contains_key(&last) {
1031 out.push(last);
1032 }
1033 }
1034 }
1035 };
1036 match agg {
1037 AggDef::Struct(s) => {
1038 for m in &s.members {
1039 push_ts(&m.type_spec, &mut out);
1040 }
1041 }
1042 AggDef::Union(u) => {
1043 for c in &u.cases {
1044 push_ts(&c.element.type_spec, &mut out);
1045 }
1046 }
1047 }
1048 out
1049 }
1050
1051 fn by_value_reaches(&self, agg: &AggDef, target: &str, seen: &mut BTreeSet<String>) -> bool {
1056 for dep in self.by_value_agg_deps(agg) {
1057 if dep == target {
1058 return true;
1059 }
1060 if !seen.insert(dep.clone()) {
1061 continue;
1062 }
1063 let next = self
1064 .reg
1065 .structs
1066 .get(&dep)
1067 .map(|(_, s)| AggDef::Struct(s.clone()))
1068 .or_else(|| {
1069 self.reg
1070 .unions
1071 .get(&dep)
1072 .map(|(_, u)| AggDef::Union(u.clone()))
1073 });
1074 if let Some(next) = next {
1075 if self.by_value_reaches(&next, target, seen) {
1076 return true;
1077 }
1078 }
1079 }
1080 false
1081 }
1082
1083 fn emit_recursive_helpers(&mut self) -> Result<(), CppGenError> {
1089 let mut recs: Vec<(String, AggDef)> = Vec::new();
1091 for name in self.reg.recursive.clone() {
1092 if let Some((cn, s)) = self.reg.structs.get(&name).cloned() {
1093 recs.push((cn, AggDef::Struct(s)));
1094 } else if let Some((cn, u)) = self.reg.unions.get(&name).cloned() {
1095 recs.push((cn, AggDef::Union(u)));
1096 }
1097 }
1098 if recs.is_empty() {
1099 return Ok(());
1100 }
1101 for (cn, _) in &recs {
1103 let _ = writeln!(
1104 self.out,
1105 "static int {cn}_write_body(const {cn}_t* v, uint8_t** w_buf_pp, size_t* w_len_pp, size_t* w_cap_pp, int representation);"
1106 );
1107 let _ = writeln!(
1108 self.out,
1109 "static int {cn}_read_body(const uint8_t* buf, size_t len, size_t* pos_pp, {cn}_t* v, int zd_be, int representation);"
1110 );
1111 }
1112 let _ = writeln!(self.out);
1113 for (cn, agg) in &recs {
1115 self.emit_recursive_write_body(cn, agg)?;
1116 self.emit_recursive_read_body(cn, agg)?;
1117 }
1118 Ok(())
1119 }
1120
1121 fn emit_recursive_write_body(&mut self, cn: &str, agg: &AggDef) -> Result<(), CppGenError> {
1127 let _ = writeln!(
1128 self.out,
1129 "static int {cn}_write_body(const {cn}_t* v, uint8_t** w_buf_pp, size_t* w_len_pp, size_t* w_cap_pp, int representation) {{"
1130 );
1131 let _ = writeln!(self.out, "#define w_buf (*w_buf_pp)");
1132 let _ = writeln!(self.out, "#define w_len (*w_len_pp)");
1133 let _ = writeln!(self.out, "#define w_cap (*w_cap_pp)");
1134 let _ = writeln!(self.out, " const {cn}_t* s = v; (void)s;");
1135 let _ = writeln!(
1136 self.out,
1137 " size_t zd_ma = representation ? 4 : 8; (void)zd_ma;"
1138 );
1139 match agg {
1140 AggDef::Struct(s) => self.emit_struct_body_writes(s)?,
1141 AggDef::Union(u) => self.emit_union_write("(*s)", u)?,
1142 }
1143 let _ = writeln!(self.out, " return 0;");
1144 let _ = writeln!(self.out, "fail:");
1145 let _ = writeln!(self.out, " return -1;");
1146 let _ = writeln!(self.out, "#undef w_buf");
1147 let _ = writeln!(self.out, "#undef w_len");
1148 let _ = writeln!(self.out, "#undef w_cap");
1149 let _ = writeln!(self.out, "}}");
1150 let _ = writeln!(self.out);
1151 Ok(())
1152 }
1153
1154 fn emit_recursive_read_body(&mut self, cn: &str, agg: &AggDef) -> Result<(), CppGenError> {
1158 let _ = writeln!(
1159 self.out,
1160 "static int {cn}_read_body(const uint8_t* buf, size_t len, size_t* pos_pp, {cn}_t* v, int zd_be, int representation) {{"
1161 );
1162 let _ = writeln!(self.out, "#define pos (*pos_pp)");
1163 let _ = writeln!(self.out, " {cn}_t* s = v; (void)s;");
1164 let _ = writeln!(
1165 self.out,
1166 " size_t zd_ma = representation ? 4 : 8; (void)zd_ma;"
1167 );
1168 match agg {
1169 AggDef::Struct(s) => self.emit_struct_body_reads(s)?,
1170 AggDef::Union(u) => self.emit_union_read("(*s)", u)?,
1171 }
1172 let _ = writeln!(self.out, " return 0;");
1173 let _ = writeln!(self.out, "#undef pos");
1174 let _ = writeln!(self.out, "}}");
1175 let _ = writeln!(self.out);
1176 Ok(())
1177 }
1178
1179 fn emit_struct(&mut self, def: &StructDef, scope: &[String]) -> Result<(), CppGenError> {
1180 let ext = extensibility_of(&def.annotations);
1181 let c_name = c_identifier(scope, &def.name.text);
1182 let dds_name = dds_type_name(scope, &def.name.text);
1183
1184 let _ = writeln!(
1190 self.out,
1191 "static int {c_name}_encode(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len);"
1192 );
1193 let _ = writeln!(
1194 self.out,
1195 "static int {c_name}_decode(const uint8_t* buf, size_t len, void* out_sample);\nstatic int {c_name}_decode_e(const uint8_t* buf, size_t len, void* out_sample, int zd_be);"
1196 );
1197 let _ = writeln!(
1198 self.out,
1199 "static int {c_name}_decode_repr(const uint8_t* buf, size_t len, uint8_t representation, void* out_sample);"
1200 );
1201 let _ = writeln!(self.out, "static void {c_name}_sample_free(void* sample);");
1202 let has_key = struct_has_key(def);
1203 if has_key {
1204 let _ = writeln!(
1205 self.out,
1206 "static int {c_name}_key_hash(const void* sample, uint8_t out_hash[16]);"
1207 );
1208 }
1209 let _ = writeln!(self.out);
1210
1211 let _ = writeln!(
1213 self.out,
1214 "static const char {c_name}_type_name[] = \"{dds_name}\";"
1215 );
1216 let _ = writeln!(
1217 self.out,
1218 "static const zerodds_typesupport_t {c_name}_typesupport = {{"
1219 );
1220 let _ = writeln!(self.out, " .type_hash = {{0}},");
1221 let _ = writeln!(self.out, " .type_name = {c_name}_type_name,");
1222 let _ = writeln!(self.out, " .is_keyed = {},", if has_key { 1 } else { 0 });
1223 let _ = writeln!(self.out, " .extensibility = {},", ext.as_u8());
1224 let _ = writeln!(self.out, " ._reserved = {{0}},");
1225 let _ = writeln!(self.out, " .encode = {c_name}_encode,");
1226 let _ = writeln!(self.out, " .decode = {c_name}_decode,");
1227 if has_key {
1228 let _ = writeln!(self.out, " .key_hash = {c_name}_key_hash,");
1229 } else {
1230 let _ = writeln!(self.out, " .key_hash = NULL,");
1231 }
1232 let _ = writeln!(self.out, " .sample_free = {c_name}_sample_free,");
1233 let _ = writeln!(self.out, " .decode_repr = {c_name}_decode_repr,");
1234 let _ = writeln!(self.out, "}};");
1235 let _ = writeln!(self.out);
1236
1237 self.emit_encode_body(&c_name, def, ext)?;
1239 self.emit_decode_body(&c_name, def, ext)?;
1241 self.emit_free_body(&c_name, def);
1243 if has_key {
1245 self.emit_key_hash_body(&c_name, def);
1246 }
1247 Ok(())
1248 }
1249
1250 fn emit_encode_body(
1251 &mut self,
1252 c_name: &str,
1253 def: &StructDef,
1254 ext: Extensibility,
1255 ) -> Result<(), CppGenError> {
1256 let _ = writeln!(
1261 self.out,
1262 "static int {c_name}_encode_repr(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len, int representation);"
1263 );
1264 let _ = writeln!(
1265 self.out,
1266 "static int {c_name}_encode(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len) {{ return {c_name}_encode_repr(sample, out_buf, out_cap, out_len, 1); }}"
1267 );
1268 let _ = writeln!(
1269 self.out,
1270 "static int {c_name}_encode_repr(const void* sample, uint8_t* out_buf, size_t out_cap, size_t* out_len, int representation) {{"
1271 );
1272 let _ = writeln!(
1273 self.out,
1274 " const {c_name}_t* s = (const {c_name}_t*)sample;"
1275 );
1276 let _ = writeln!(self.out, " (void)s;");
1277 let _ = writeln!(
1279 self.out,
1280 " size_t zd_ma = representation ? 4 : 8; (void)zd_ma;"
1281 );
1282 let _ = writeln!(self.out, " /* Two-pass: grow the buffer, then copy. */");
1283 let _ = writeln!(self.out, " uint8_t* w_buf = NULL;");
1284 let _ = writeln!(self.out, " size_t w_len = 0;");
1285 let _ = writeln!(self.out, " size_t w_cap = 0;");
1286 let _ = writeln!(
1287 self.out,
1288 " if (out_buf == NULL && out_cap > 0) goto fail;"
1289 );
1290 match ext {
1291 Extensibility::Final => {
1292 self.emit_struct_body_writes(def)?;
1293 }
1294 Extensibility::Appendable => {
1295 let _ = writeln!(self.out, " size_t dheader_pos = 0; (void)dheader_pos;");
1298 let _ = writeln!(self.out, " if (representation) {{");
1299 let _ = writeln!(
1300 self.out,
1301 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1302 );
1303 let _ = writeln!(self.out, " dheader_pos = w_len; w_len += 4;");
1304 let _ = writeln!(self.out, " }}");
1305 let _ = writeln!(self.out, " size_t body_start = w_len;");
1306 self.emit_struct_body_writes(def)?;
1307 let _ = writeln!(self.out, " if (representation) {{");
1308 let _ = writeln!(
1309 self.out,
1310 " zerodds_xcdr2_c_put_u32_at(w_buf, dheader_pos, (uint32_t)(w_len - body_start));"
1311 );
1312 let _ = writeln!(self.out, " }}");
1313 }
1314 Extensibility::Mutable => {
1315 let _ = writeln!(self.out, " if (representation) {{");
1318 let _ = writeln!(
1319 self.out,
1320 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1321 );
1322 let _ = writeln!(self.out, " size_t dheader_pos = w_len; w_len += 4;");
1323 let _ = writeln!(self.out, " size_t mut_body_start = w_len;");
1324 self.emit_mutable_member_writes(def)?;
1325 let _ = writeln!(
1326 self.out,
1327 " zerodds_xcdr2_c_put_u32_at(w_buf, dheader_pos, (uint32_t)(w_len - mut_body_start));"
1328 );
1329 let _ = writeln!(self.out, " }} else {{");
1330 self.emit_pl_cdr1_member_writes(def)?;
1331 let _ = writeln!(self.out, " }}");
1332 }
1333 }
1334 let _ = writeln!(self.out, " if (out_len) *out_len = w_len;");
1336 let _ = writeln!(
1337 self.out,
1338 " if (out_buf == NULL || out_cap < w_len) {{ free(w_buf); return -13; }}"
1339 );
1340 let _ = writeln!(
1341 self.out,
1342 " if (w_len > 0) memcpy(out_buf, w_buf, w_len);"
1343 );
1344 let _ = writeln!(self.out, " free(w_buf);");
1345 let _ = writeln!(self.out, " return 0;");
1346 let _ = writeln!(self.out, "fail:");
1347 let _ = writeln!(self.out, " free(w_buf);");
1348 let _ = writeln!(self.out, " return -1;");
1349 let _ = writeln!(self.out, "}}");
1350 let _ = writeln!(self.out);
1351 Ok(())
1352 }
1353
1354 fn emit_struct_body_writes(&mut self, def: &StructDef) -> Result<(), CppGenError> {
1355 for member in &def.members {
1356 let optional = is_optional(&member.annotations);
1357 for decl in &member.declarators {
1358 let f = &decl.name().text;
1359 let dims = effective_array_dims(self.reg, &member.type_spec, decl)?;
1360 if optional {
1361 let _ = writeln!(
1364 self.out,
1365 " if (zerodds_xcdr2_c_write_u8(&w_buf, &w_len, &w_cap, s->{f}_present ? 1 : 0) != 0) goto fail;"
1366 );
1367 let _ = writeln!(self.out, " if (s->{f}_present) {{");
1368 self.emit_array_or_scalar_write(&format!("s->{f}"), &member.type_spec, &dims)?;
1369 let _ = writeln!(self.out, " }}");
1370 } else {
1371 self.emit_array_or_scalar_write(&format!("s->{f}"), &member.type_spec, &dims)?;
1372 }
1373 }
1374 }
1375 Ok(())
1376 }
1377
1378 fn emit_array_or_scalar_write(
1381 &mut self,
1382 var: &str,
1383 type_spec: &TypeSpec,
1384 dims: &[u64],
1385 ) -> Result<(), CppGenError> {
1386 if dims.is_empty() {
1387 return self.emit_member_write(var, type_spec);
1388 }
1389 let needs_dheader = !self.seq_elem_is_primitive(type_spec);
1396 if needs_dheader {
1397 let _ = writeln!(self.out, " {{");
1401 let _ = writeln!(
1402 self.out,
1403 " size_t arr_dheader_pos = 0; (void)arr_dheader_pos;"
1404 );
1405 let _ = writeln!(self.out, " if (representation) {{");
1406 let _ = writeln!(
1407 self.out,
1408 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1409 );
1410 let _ = writeln!(self.out, " arr_dheader_pos = w_len; w_len += 4;");
1411 let _ = writeln!(self.out, " }}");
1412 let _ = writeln!(
1413 self.out,
1414 " size_t arr_body_start = w_len; (void)arr_body_start;"
1415 );
1416 }
1417 let mut acc = var.to_string();
1418 for (d, _n) in dims.iter().enumerate() {
1419 let iv = format!("ai{d}");
1420 let _ = writeln!(
1421 self.out,
1422 " for (uint32_t {iv} = 0; {iv} < {n}; ++{iv}) {{",
1423 n = dims[d]
1424 );
1425 acc = format!("{acc}[{iv}]");
1426 }
1427 self.emit_member_write(&acc, type_spec)?;
1428 for _ in dims {
1429 let _ = writeln!(self.out, " }}");
1430 }
1431 if needs_dheader {
1432 let _ = writeln!(
1433 self.out,
1434 " if (representation) {{ zerodds_xcdr2_c_put_u32_at(w_buf, arr_dheader_pos, (uint32_t)(w_len - arr_body_start)); }}"
1435 );
1436 let _ = writeln!(self.out, " }}"); }
1438 Ok(())
1439 }
1440
1441 fn emit_member_write(&mut self, var: &str, type_spec: &TypeSpec) -> Result<(), CppGenError> {
1443 let resolved = resolve_alias(self.reg, type_spec);
1445 match &resolved {
1446 TypeSpec::Primitive(p) => self.emit_primitive_write(var, *p),
1447 TypeSpec::String(st) => {
1448 if st.wide {
1449 return self.emit_wstring_write(var, st.bound.as_ref());
1450 }
1451 if let Some(n) = self.eval_bound(st.bound.as_ref()) {
1454 let _ = writeln!(
1455 self.out,
1456 " if (({var}) != NULL && strlen({var}) > {n}u) goto fail;"
1457 );
1458 }
1459 let _ = writeln!(
1460 self.out,
1461 " if (zerodds_xcdr2_c_write_string(&w_buf, &w_len, &w_cap, {var}) != 0) goto fail;"
1462 );
1463 Ok(())
1464 }
1465 TypeSpec::Sequence(seq) => self.emit_sequence_write(var, &seq.elem, seq.bound.as_ref()),
1466 TypeSpec::Map(m) => self.emit_map_write(var, &m.key, &m.value, m.bound.as_ref()),
1467 TypeSpec::Scoped(sc) => {
1468 let last = scoped_last(sc).ok_or_else(|| unsupported("empty scoped name"))?;
1469 if self.reg.enums.contains_key(&last) {
1470 let bytes = self.reg.enum_bytes.get(&last).copied().unwrap_or(4);
1474 let line = match bytes {
1475 1 => format!(
1476 " if (zerodds_xcdr2_c_write_u8(&w_buf, &w_len, &w_cap, (uint8_t)({var})) != 0) goto fail;"
1477 ),
1478 2 => format!(
1479 " if (zerodds_xcdr2_c_write_u16(&w_buf, &w_len, &w_cap, (uint16_t)({var})) != 0) goto fail;"
1480 ),
1481 _ => format!(
1482 " if (zerodds_xcdr2_c_write_i32(&w_buf, &w_len, &w_cap, (int32_t)({var})) != 0) goto fail;"
1483 ),
1484 };
1485 let _ = writeln!(self.out, "{line}");
1486 return Ok(());
1487 }
1488 if let Some(helper) = self.bits_helper(&last) {
1490 let prefix = Self::helper_call_prefix(helper);
1491 let _ = writeln!(
1492 self.out,
1493 " if ({prefix}write_{helper}(&w_buf, &w_len, &w_cap, {var}) != 0) goto fail;"
1494 );
1495 return Ok(());
1496 }
1497 if let Some((cn, ndef)) = self.reg.structs.get(&last).cloned() {
1498 if self.reg.is_recursive(&last) {
1504 let ext = extensibility_of(&ndef.annotations);
1514 if matches!(ext, Extensibility::Final) {
1515 let _ = writeln!(
1516 self.out,
1517 " if ({cn}_write_body(&({var}), &w_buf, &w_len, &w_cap, representation) != 0) goto fail;"
1518 );
1519 } else {
1520 let _ = writeln!(self.out, " {{");
1523 let _ = writeln!(
1524 self.out,
1525 " size_t rec_dheader_pos = 0; (void)rec_dheader_pos;"
1526 );
1527 let _ = writeln!(self.out, " if (representation) {{");
1528 let _ = writeln!(
1529 self.out,
1530 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1531 );
1532 let _ =
1533 writeln!(self.out, " rec_dheader_pos = w_len; w_len += 4;");
1534 let _ = writeln!(self.out, " }}");
1535 let _ = writeln!(
1536 self.out,
1537 " size_t rec_body_start = w_len; (void)rec_body_start;"
1538 );
1539 let _ = writeln!(
1540 self.out,
1541 " if ({cn}_write_body(&({var}), &w_buf, &w_len, &w_cap, representation) != 0) goto fail;"
1542 );
1543 let _ = writeln!(
1544 self.out,
1545 " if (representation) {{ zerodds_xcdr2_c_put_u32_at(w_buf, rec_dheader_pos, (uint32_t)(w_len - rec_body_start)); }}"
1546 );
1547 let _ = writeln!(self.out, " }}");
1548 }
1549 return Ok(());
1550 }
1551 return self.emit_nested_struct_write(var, &ndef);
1552 }
1553 if let Some((cn, udef)) = self.reg.unions.get(&last).cloned() {
1554 if self.reg.is_recursive(&last) {
1555 let _ = writeln!(
1556 self.out,
1557 " if ({cn}_write_body(&({var}), &w_buf, &w_len, &w_cap, representation) != 0) goto fail;"
1558 );
1559 return Ok(());
1560 }
1561 return self.emit_union_write(var, &udef);
1562 }
1563 Err(unsupported("unresolved scoped member (C backend)"))
1564 }
1565 TypeSpec::Fixed(f) => {
1566 let p = const_expr_to_u64(self.reg, &f.digits)
1569 .ok_or_else(|| unsupported("fixed: non-constant digit count"))?;
1570 let n = (p + 2) / 2;
1571 let _ = writeln!(
1572 self.out,
1573 " for (size_t __fi = 0; __fi < {n}; __fi++) {{ if (zerodds_xcdr2_c_write_u8(&w_buf, &w_len, &w_cap, (uint8_t)(({var}).bcd[__fi])) != 0) goto fail; }}"
1574 );
1575 Ok(())
1576 }
1577 TypeSpec::Any => Err(unsupported("any")),
1578 }
1579 }
1580
1581 fn emit_wstring_write(
1584 &mut self,
1585 var: &str,
1586 bound: Option<&ConstExpr>,
1587 ) -> Result<(), CppGenError> {
1588 let _ = writeln!(self.out, " {{");
1589 let _ = writeln!(
1590 self.out,
1591 " const uint16_t* ws_p = (const uint16_t*)({var});"
1592 );
1593 let _ = writeln!(self.out, " uint32_t ws_n = 0;");
1594 let _ = writeln!(self.out, " if (ws_p) while (ws_p[ws_n]) ++ws_n;");
1595 if let Some(n) = self.eval_bound(bound) {
1597 let _ = writeln!(self.out, " if (ws_n > {n}u) goto fail;");
1598 }
1599 let _ = writeln!(
1600 self.out,
1601 " if (zerodds_xcdr2_c_write_u32(&w_buf, &w_len, &w_cap, ws_n * 2u) != 0) goto fail;"
1602 );
1603 let _ = writeln!(
1604 self.out,
1605 " for (uint32_t wi = 0; wi < ws_n; ++wi) {{ if (zerodds_xcdr2_c_write_u16(&w_buf, &w_len, &w_cap, ws_p[wi]) != 0) goto fail; }}"
1606 );
1607 let _ = writeln!(self.out, " }}");
1608 Ok(())
1609 }
1610
1611 fn emit_map_write(
1615 &mut self,
1616 var: &str,
1617 key: &TypeSpec,
1618 value: &TypeSpec,
1619 bound: Option<&ConstExpr>,
1620 ) -> Result<(), CppGenError> {
1621 let _ = writeln!(self.out, " {{");
1622 if let Some(n) = self.eval_bound(bound) {
1624 let _ = writeln!(self.out, " if (({var}).len > {n}u) goto fail;");
1625 }
1626 let _ = writeln!(
1630 self.out,
1631 " if (zerodds_xcdr2_c_pad_to(&w_buf, &w_len, &w_cap, 4) != 0) goto fail;"
1632 );
1633 let map_dh = !(self.seq_elem_is_primitive(key) && self.seq_elem_is_primitive(value));
1638 let _ = writeln!(
1639 self.out,
1640 " size_t map_dheader_pos = 0; (void)map_dheader_pos;"
1641 );
1642 if map_dh {
1643 let _ = writeln!(self.out, " if (representation) {{");
1644 let _ = writeln!(
1645 self.out,
1646 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1647 );
1648 let _ = writeln!(self.out, " map_dheader_pos = w_len; w_len += 4;");
1649 let _ = writeln!(self.out, " }}");
1650 }
1651 let _ = writeln!(
1652 self.out,
1653 " size_t map_body_start = w_len; (void)map_body_start;"
1654 );
1655 let _ = writeln!(
1656 self.out,
1657 " if (zerodds_xcdr2_c_write_u32(&w_buf, &w_len, &w_cap, ({var}).len) != 0) goto fail;"
1658 );
1659 let mv = format!("mi{}", self.coll_depth);
1660 let _ = writeln!(
1661 self.out,
1662 " for (uint32_t {mv} = 0; {mv} < ({var}).len; ++{mv}) {{"
1663 );
1664 self.coll_depth += 1;
1665 let rk = self.emit_member_write(&format!("({var}).keys[{mv}]"), key);
1666 let rv = if rk.is_ok() {
1667 self.emit_member_write(&format!("({var}).vals[{mv}]"), value)
1668 } else {
1669 Ok(())
1670 };
1671 self.coll_depth -= 1;
1672 rk.and(rv)?;
1673 let _ = writeln!(self.out, " }}");
1674 if map_dh {
1675 let _ = writeln!(
1676 self.out,
1677 " if (representation) {{ zerodds_xcdr2_c_put_u32_at(w_buf, map_dheader_pos, (uint32_t)(w_len - map_body_start)); }}"
1678 );
1679 }
1680 let _ = writeln!(self.out, " }}");
1681 Ok(())
1682 }
1683
1684 fn emit_union_write(&mut self, var: &str, udef: &UnionDef) -> Result<(), CppGenError> {
1687 let u_dheader = !matches!(extensibility_of(&udef.annotations), Extensibility::Final);
1693 if u_dheader {
1694 let _ = writeln!(self.out, " {{");
1695 let _ = writeln!(
1696 self.out,
1697 " size_t u_dheader_pos = 0; (void)u_dheader_pos;"
1698 );
1699 let _ = writeln!(self.out, " if (representation) {{");
1700 let _ = writeln!(
1701 self.out,
1702 " if (zerodds_xcdr2_c_pad_to(&w_buf, &w_len, &w_cap, 4) != 0) goto fail;"
1703 );
1704 let _ = writeln!(
1705 self.out,
1706 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1707 );
1708 let _ = writeln!(self.out, " u_dheader_pos = w_len; w_len += 4;");
1709 let _ = writeln!(self.out, " }}");
1710 let _ = writeln!(
1711 self.out,
1712 " size_t u_body_start = w_len; (void)u_body_start;"
1713 );
1714 }
1715 let disc_ts = switch_type_spec(&udef.switch_type);
1717 self.emit_member_write(&format!("({var})._d"), &disc_ts)?;
1718 let _ = writeln!(self.out, " switch (({var})._d) {{");
1719 let mut default_case: Option<&Case> = None;
1720 for case in &udef.cases {
1721 let field = union_case_field(case);
1722 let mut has_value_label = false;
1723 for label in &case.labels {
1724 match label {
1725 CaseLabel::Value(expr) => {
1726 has_value_label = true;
1727 let lit = self.case_label_literal(expr)?;
1728 let _ = writeln!(self.out, " case {lit}:");
1729 }
1730 CaseLabel::Default => {
1731 default_case = Some(case);
1732 }
1733 }
1734 }
1735 if has_value_label {
1736 self.emit_member_write(&format!("({var})._u.{field}"), &case.element.type_spec)?;
1737 let _ = writeln!(self.out, " break;");
1738 }
1739 }
1740 if let Some(case) = default_case {
1741 let field = union_case_field(case);
1742 let _ = writeln!(self.out, " default:");
1743 self.emit_member_write(&format!("({var})._u.{field}"), &case.element.type_spec)?;
1744 let _ = writeln!(self.out, " break;");
1745 } else {
1746 let _ = writeln!(self.out, " default: break;");
1747 }
1748 let _ = writeln!(self.out, " }}");
1749 if u_dheader {
1750 let _ = writeln!(
1751 self.out,
1752 " if (representation) {{ zerodds_xcdr2_c_put_u32_at(w_buf, u_dheader_pos, (uint32_t)(w_len - u_body_start)); }}"
1753 );
1754 let _ = writeln!(self.out, " }}");
1755 }
1756 Ok(())
1757 }
1758
1759 fn emit_nested_struct_write(&mut self, var: &str, ndef: &StructDef) -> Result<(), CppGenError> {
1762 let ext = extensibility_of(&ndef.annotations);
1771 if !matches!(ext, Extensibility::Final) {
1772 let _ = writeln!(self.out, " {{");
1777 let _ = writeln!(
1778 self.out,
1779 " size_t nst_dheader_pos = 0; (void)nst_dheader_pos;"
1780 );
1781 let _ = writeln!(self.out, " if (representation) {{");
1782 let _ = writeln!(
1783 self.out,
1784 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1785 );
1786 let _ = writeln!(self.out, " nst_dheader_pos = w_len; w_len += 4;");
1787 let _ = writeln!(self.out, " }}");
1788 let _ = writeln!(
1789 self.out,
1790 " size_t nst_body_start = w_len; (void)nst_body_start;"
1791 );
1792 if matches!(ext, Extensibility::Mutable) {
1793 self.emit_mutable_member_writes_base(ndef, &format!("({var})."))?;
1794 } else {
1795 self.emit_nested_struct_inline_write(var, ndef)?;
1796 }
1797 let _ = writeln!(
1798 self.out,
1799 " if (representation) {{ zerodds_xcdr2_c_put_u32_at(w_buf, nst_dheader_pos, (uint32_t)(w_len - nst_body_start)); }}"
1800 );
1801 let _ = writeln!(self.out, " }}");
1802 return Ok(());
1803 }
1804 self.emit_nested_struct_inline_write(var, ndef)
1805 }
1806
1807 fn emit_nested_struct_inline_write(
1812 &mut self,
1813 var: &str,
1814 ndef: &StructDef,
1815 ) -> Result<(), CppGenError> {
1816 for member in &ndef.members {
1817 let optional = is_optional(&member.annotations);
1818 for decl in &member.declarators {
1819 let f = &decl.name().text;
1820 let dims = effective_array_dims(self.reg, &member.type_spec, decl)?;
1821 if optional {
1822 let _ = writeln!(
1827 self.out,
1828 " if (zerodds_xcdr2_c_write_u8(&w_buf, &w_len, &w_cap, ({var}).{f}_present ? 1 : 0) != 0) goto fail;"
1829 );
1830 let _ = writeln!(self.out, " if (({var}).{f}_present) {{");
1831 self.emit_array_or_scalar_write(
1832 &format!("({var}).{f}"),
1833 &member.type_spec,
1834 &dims,
1835 )?;
1836 let _ = writeln!(self.out, " }}");
1837 } else {
1838 self.emit_array_or_scalar_write(
1839 &format!("({var}).{f}"),
1840 &member.type_spec,
1841 &dims,
1842 )?;
1843 }
1844 }
1845 }
1846 Ok(())
1847 }
1848
1849 fn emit_primitive_write(&mut self, var: &str, p: PrimitiveType) -> Result<(), CppGenError> {
1850 let helper = match p {
1851 PrimitiveType::Boolean | PrimitiveType::Octet => "u8",
1852 PrimitiveType::Char => "u8",
1853 PrimitiveType::WideChar => "u16",
1854 PrimitiveType::Integer(IntegerType::Short)
1855 | PrimitiveType::Integer(IntegerType::Int16) => "i16",
1856 PrimitiveType::Integer(IntegerType::UShort)
1857 | PrimitiveType::Integer(IntegerType::UInt16) => "u16",
1858 PrimitiveType::Integer(IntegerType::Long)
1859 | PrimitiveType::Integer(IntegerType::Int32) => "i32",
1860 PrimitiveType::Integer(IntegerType::ULong)
1861 | PrimitiveType::Integer(IntegerType::UInt32) => "u32",
1862 PrimitiveType::Integer(IntegerType::LongLong)
1863 | PrimitiveType::Integer(IntegerType::Int64) => "i64",
1864 PrimitiveType::Integer(IntegerType::ULongLong)
1865 | PrimitiveType::Integer(IntegerType::UInt64) => "u64",
1866 PrimitiveType::Integer(IntegerType::Int8) => "i8",
1867 PrimitiveType::Integer(IntegerType::UInt8) => "u8",
1868 PrimitiveType::Floating(FloatingType::Float) => "f32",
1869 PrimitiveType::Floating(FloatingType::Double) => "f64",
1870 PrimitiveType::Floating(FloatingType::LongDouble) => {
1871 return Err(unsupported("long double"));
1872 }
1873 };
1874 if matches!(helper, "u64" | "i64" | "f64") {
1875 let _ = writeln!(
1879 self.out,
1880 " if (representation) {{ if (zd_x2_write_{helper}(&w_buf, &w_len, &w_cap, {var}) != 0) goto fail; }}"
1881 );
1882 let _ = writeln!(
1883 self.out,
1884 " else {{ if (zerodds_xcdr2_c_write_{helper}(&w_buf, &w_len, &w_cap, {var}) != 0) goto fail; }}"
1885 );
1886 return Ok(());
1887 }
1888 let prefix = Self::helper_call_prefix(helper);
1889 let _ = writeln!(
1890 self.out,
1891 " if ({prefix}write_{helper}(&w_buf, &w_len, &w_cap, {var}) != 0) goto fail;"
1892 );
1893 Ok(())
1894 }
1895
1896 fn emit_sequence_write(
1897 &mut self,
1898 var: &str,
1899 elem: &TypeSpec,
1900 bound: Option<&ConstExpr>,
1901 ) -> Result<(), CppGenError> {
1902 let non_primitive = !self.seq_elem_is_primitive(elem);
1908 let _ = writeln!(self.out, " {{");
1910 if let Some(n) = self.eval_bound(bound) {
1913 let _ = writeln!(self.out, " if (({var}).len > {n}u) goto fail;");
1914 }
1915 if non_primitive {
1916 let _ = writeln!(
1919 self.out,
1920 " size_t seq_dheader_pos = 0; (void)seq_dheader_pos;"
1921 );
1922 let _ = writeln!(self.out, " if (representation) {{");
1923 let _ = writeln!(
1924 self.out,
1925 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
1926 );
1927 let _ = writeln!(self.out, " seq_dheader_pos = w_len; w_len += 4;");
1928 let _ = writeln!(self.out, " }}");
1929 let _ = writeln!(
1930 self.out,
1931 " size_t seq_body_start = w_len; (void)seq_body_start;"
1932 );
1933 }
1934 let _ = writeln!(
1935 self.out,
1936 " if (zerodds_xcdr2_c_write_u32(&w_buf, &w_len, &w_cap, ({var}).len) != 0) goto fail;"
1937 );
1938 let iv = format!("i{}", self.coll_depth);
1939 let _ = writeln!(
1940 self.out,
1941 " for (uint32_t {iv} = 0; {iv} < ({var}).len; ++{iv}) {{"
1942 );
1943 self.coll_depth += 1;
1948 let r = self.emit_member_write(&format!("({var}).elems[{iv}]"), elem);
1949 self.coll_depth -= 1;
1950 r?;
1951 let _ = writeln!(self.out, " }}");
1952 if non_primitive {
1953 let _ = writeln!(
1954 self.out,
1955 " if (representation) {{ zerodds_xcdr2_c_put_u32_at(w_buf, seq_dheader_pos, (uint32_t)(w_len - seq_body_start)); }}"
1956 );
1957 }
1958 let _ = writeln!(self.out, " }}");
1959 Ok(())
1960 }
1961
1962 fn emit_mutable_member_writes(&mut self, def: &StructDef) -> Result<(), CppGenError> {
1963 self.emit_mutable_member_writes_base(def, "s->")
1964 }
1965
1966 fn emit_mutable_member_writes_base(
1971 &mut self,
1972 def: &StructDef,
1973 base: &str,
1974 ) -> Result<(), CppGenError> {
1975 let mut auto_id: u32 = 0;
1981 for member in &def.members {
1982 let id = id_annotation(&member.annotations).unwrap_or(auto_id);
1983 auto_id = id + 1;
1984 let dims_per_decl: Vec<Vec<u64>> = member
1985 .declarators
1986 .iter()
1987 .map(|d| effective_array_dims(self.reg, &member.type_spec, d))
1988 .collect::<Result<_, _>>()?;
1989 let optional = is_optional(&member.annotations);
1990 for (decl, dims) in member.declarators.iter().zip(dims_per_decl.iter()) {
1991 let f = format!("{base}{}", decl.name().text);
1992 let f = f.as_str();
1993 let compact_lc = mutable_compact_lc(self.reg, &member.type_spec, dims, optional);
2002 match compact_lc {
2003 Some(lc) => {
2004 let emheader: u32 = (u32::from(lc) << 28) | id;
2007 let _ = writeln!(self.out, " {{");
2008 let _ = writeln!(
2009 self.out,
2010 " if (zerodds_xcdr2_c_write_u32(&w_buf, &w_len, &w_cap, 0x{emheader:08X}u) != 0) goto fail;"
2011 );
2012 self.emit_array_or_scalar_write(f, &member.type_spec, dims)?;
2013 let _ = writeln!(self.out, " }}");
2014 }
2015 None => {
2016 let emheader: u32 = (4u32 << 28) | id;
2018 let _ = writeln!(self.out, " {{");
2019 let _ = writeln!(
2020 self.out,
2021 " if (zerodds_xcdr2_c_write_u32(&w_buf, &w_len, &w_cap, 0x{emheader:08X}u) != 0) goto fail;"
2022 );
2023 let _ = writeln!(
2024 self.out,
2025 " if (zerodds_xcdr2_c_grow(&w_buf, &w_cap, w_len + 4) != 0) goto fail;"
2026 );
2027 let _ = writeln!(self.out, " size_t m_nextint_pos = w_len;");
2028 let _ = writeln!(self.out, " w_len += 4;");
2029 let _ = writeln!(self.out, " size_t m_body_start = w_len;");
2030 self.emit_array_or_scalar_write(f, &member.type_spec, dims)?;
2031 let _ = writeln!(
2032 self.out,
2033 " uint32_t m_body_len = (uint32_t)(w_len - m_body_start);"
2034 );
2035 let _ = writeln!(
2036 self.out,
2037 " zerodds_xcdr2_c_put_u32_at(w_buf, m_nextint_pos, m_body_len);"
2038 );
2039 let _ = writeln!(self.out, " }}");
2040 }
2041 }
2042 }
2043 }
2044 Ok(())
2045 }
2046
2047 fn emit_pl_cdr1_member_writes(&mut self, def: &StructDef) -> Result<(), CppGenError> {
2054 let mut auto_id: u32 = 0;
2055 for member in &def.members {
2056 let id = id_annotation(&member.annotations).unwrap_or(auto_id);
2057 auto_id = id + 1;
2058 let dims_per_decl: Vec<Vec<u64>> = member
2059 .declarators
2060 .iter()
2061 .map(|d| effective_array_dims(self.reg, &member.type_spec, d))
2062 .collect::<Result<_, _>>()?;
2063 let optional = is_optional(&member.annotations);
2064 for (decl, dims) in member.declarators.iter().zip(dims_per_decl.iter()) {
2065 let fname = decl.name().text.clone();
2066 let f = format!("s->{fname}");
2067 if optional {
2068 let _ = writeln!(self.out, " if (s->{fname}_present) {{");
2071 }
2072 let _ = writeln!(self.out, " {{");
2073 let _ = writeln!(
2076 self.out,
2077 " uint8_t* m_buf = w_buf; size_t m_len = w_len; size_t m_cap = w_cap;"
2078 );
2079 let _ = writeln!(self.out, " w_buf = NULL; w_len = 0; w_cap = 0;");
2080 self.emit_array_or_scalar_write(&f, &member.type_spec, dims)?;
2081 let _ = writeln!(
2083 self.out,
2084 " if (zerodds_xcdr2_c_pl1_write_member(&m_buf, &m_len, &m_cap, {id}u, w_buf, w_len) != 0) {{ free(w_buf); w_buf = m_buf; w_len = m_len; w_cap = m_cap; goto fail; }}"
2085 );
2086 let _ = writeln!(
2087 self.out,
2088 " free(w_buf); w_buf = m_buf; w_len = m_len; w_cap = m_cap;"
2089 );
2090 let _ = writeln!(self.out, " }}");
2091 if optional {
2092 let _ = writeln!(self.out, " }}");
2093 }
2094 }
2095 }
2096 let _ = writeln!(
2098 self.out,
2099 " if (zerodds_xcdr2_c_pl1_sentinel(&w_buf, &w_len, &w_cap) != 0) goto fail;"
2100 );
2101 Ok(())
2102 }
2103
2104 fn emit_pl_cdr1_member_reads(&mut self, def: &StructDef) -> Result<(), CppGenError> {
2110 let _ = writeln!(self.out, " while (pos + 4 <= len) {{");
2111 let _ = writeln!(
2112 self.out,
2113 " uint32_t pl_id = 0; size_t pl_blen = 0; int pl_end = 0;"
2114 );
2115 let _ = writeln!(
2116 self.out,
2117 " if (zerodds_xcdr2_c_pl1_read_header(buf, len, &pos, &pl_id, &pl_blen, &pl_end, zd_be) != 0) return -7;"
2118 );
2119 let _ = writeln!(self.out, " if (pl_end) break;");
2120 let _ = writeln!(self.out, " if (pos + pl_blen > len) return -7;");
2121 let _ = writeln!(self.out, " size_t pl_body_start = pos;");
2122 let _ = writeln!(self.out, " switch (pl_id) {{");
2123 let mut auto_id: u32 = 0;
2124 for member in &def.members {
2125 let id = id_annotation(&member.annotations).unwrap_or(auto_id);
2126 auto_id = id + 1;
2127 let dims_per_decl: Vec<Vec<u64>> = member
2128 .declarators
2129 .iter()
2130 .map(|d| effective_array_dims(self.reg, &member.type_spec, d))
2131 .collect::<Result<_, _>>()?;
2132 let optional = is_optional(&member.annotations);
2133 for (decl, dims) in member.declarators.iter().zip(dims_per_decl.iter()) {
2134 let fname = decl.name().text.clone();
2135 let f = format!("s->{fname}");
2136 let _ = writeln!(self.out, " case {id}u: {{");
2137 let _ = writeln!(
2139 self.out,
2140 " const uint8_t* mb = buf; size_t ml = len; size_t mp = pos;"
2141 );
2142 let _ = writeln!(
2143 self.out,
2144 " buf = mb + pl_body_start; len = pl_blen; pos = 0;"
2145 );
2146 if optional {
2147 let _ = writeln!(self.out, " s->{fname}_present = 1;");
2148 }
2149 self.emit_array_or_scalar_read(&f, &member.type_spec, dims)?;
2150 let _ = writeln!(self.out, " buf = mb; len = ml; pos = mp;");
2151 let _ = writeln!(self.out, " break;");
2152 let _ = writeln!(self.out, " }}");
2153 }
2154 }
2155 let _ = writeln!(self.out, " default: break;");
2156 let _ = writeln!(self.out, " }}");
2157 let _ = writeln!(self.out, " pos = pl_body_start + pl_blen;");
2158 let _ = writeln!(
2160 self.out,
2161 " {{ size_t pl_pad = (4u - (pl_blen % 4u)) % 4u; pos += pl_pad; if (pos > len) pos = len; }}"
2162 );
2163 let _ = writeln!(self.out, " }}");
2164 Ok(())
2165 }
2166
2167 fn emit_decode_body(
2168 &mut self,
2169 c_name: &str,
2170 def: &StructDef,
2171 ext: Extensibility,
2172 ) -> Result<(), CppGenError> {
2173 let _ = writeln!(
2181 self.out,
2182 "static int {c_name}_decode_core(const uint8_t* buf, size_t len, void* out_sample, int zd_be, int representation);"
2183 );
2184 let _ = writeln!(
2185 self.out,
2186 "static int {c_name}_decode(const uint8_t* buf, size_t len, void* out_sample) {{ return {c_name}_decode_core(buf, len, out_sample, 0, 1); }}"
2187 );
2188 let _ = writeln!(
2189 self.out,
2190 "static int {c_name}_decode_e(const uint8_t* buf, size_t len, void* out_sample, int zd_be) {{ return {c_name}_decode_core(buf, len, out_sample, zd_be, 1); }}"
2191 );
2192 let _ = writeln!(
2193 self.out,
2194 "static int {c_name}_decode_repr(const uint8_t* buf, size_t len, uint8_t representation, void* out_sample) {{ return {c_name}_decode_core(buf, len, out_sample, 0, representation ? 1 : 0); }}"
2195 );
2196 let _ = writeln!(
2197 self.out,
2198 "static int {c_name}_decode_core(const uint8_t* buf, size_t len, void* out_sample, int zd_be, int representation) {{"
2199 );
2200 let _ = writeln!(self.out, " {c_name}_t* s = ({c_name}_t*)out_sample;");
2201 let _ = writeln!(self.out, " size_t pos = 0;");
2202 let _ = writeln!(
2203 self.out,
2204 " size_t zd_ma = representation ? 4 : 8; (void)zd_ma;"
2205 );
2206 match ext {
2207 Extensibility::Final => {
2208 self.emit_struct_body_reads(def)?;
2209 }
2210 Extensibility::Appendable => {
2211 let _ = writeln!(self.out, " size_t body_end = len;");
2213 let _ = writeln!(self.out, " if (representation) {{");
2214 let _ = writeln!(self.out, " uint32_t dheader = 0;");
2215 let _ = writeln!(
2216 self.out,
2217 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &dheader, zd_be) != 0) return -7;"
2218 );
2219 let _ = writeln!(self.out, " body_end = pos + dheader;");
2220 let _ = writeln!(self.out, " if (body_end > len) return -7;");
2221 let _ = writeln!(self.out, " }}");
2222 self.emit_struct_body_reads(def)?;
2223 let _ = writeln!(self.out, " if (representation) pos = body_end;");
2224 }
2225 Extensibility::Mutable => {
2226 let _ = writeln!(self.out, " if (!representation) {{");
2227 self.emit_pl_cdr1_member_reads(def)?;
2228 let _ = writeln!(self.out, " }} else {{");
2229 let _ = writeln!(self.out, " uint32_t dheader = 0;");
2230 let _ = writeln!(
2231 self.out,
2232 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &dheader, zd_be) != 0) return -7;"
2233 );
2234 let _ = writeln!(self.out, " size_t body_end = pos + dheader;");
2235 let _ = writeln!(self.out, " if (body_end > len) return -7;");
2236 let _ = writeln!(self.out, " while (pos < body_end) {{");
2237 let _ = writeln!(self.out, " uint32_t emheader = 0;");
2238 let _ = writeln!(
2239 self.out,
2240 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &emheader, zd_be) != 0) return -7;"
2241 );
2242 let _ = writeln!(self.out, " uint32_t mid = emheader & 0x0FFFFFFFu;");
2243 let _ = writeln!(self.out, " uint32_t lc = (emheader >> 28) & 0x7u;");
2244 let _ = writeln!(self.out, " uint32_t nextint = 0;");
2245 let _ = writeln!(self.out, " size_t body_len = 0;");
2246 let _ = writeln!(
2253 self.out,
2254 " if (lc == 0) body_len = 1; else if (lc == 1) body_len = 2; else if (lc == 2) body_len = 4; else if (lc == 3) body_len = 8;"
2255 );
2256 let _ = writeln!(self.out, " else if (lc == 5) {{");
2257 let _ = writeln!(self.out, " size_t peek_pos = pos;");
2258 let _ = writeln!(
2259 self.out,
2260 " if (zerodds_xcdr2_c_read_u32(buf, len, &peek_pos, &nextint, zd_be) != 0) return -7;"
2261 );
2262 let _ = writeln!(self.out, " body_len = 4u + (size_t)nextint;");
2263 let _ = writeln!(self.out, " }} else {{");
2264 let _ = writeln!(
2265 self.out,
2266 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &nextint, zd_be) != 0) return -7;"
2267 );
2268 let _ = writeln!(self.out, " body_len = nextint;");
2269 let _ = writeln!(self.out, " }}");
2270 let _ = writeln!(
2271 self.out,
2272 " if (pos + body_len > body_end) return -7;"
2273 );
2274 self.emit_mutable_member_dispatch(def)?;
2275 let _ = writeln!(self.out, " }}"); let _ = writeln!(self.out, " }}"); }
2278 }
2279 let _ = writeln!(self.out, " (void)s;");
2280 let _ = writeln!(self.out, " return 0;");
2281 let _ = writeln!(self.out, "}}");
2282 let _ = writeln!(self.out);
2283 Ok(())
2284 }
2285
2286 fn emit_struct_body_reads(&mut self, def: &StructDef) -> Result<(), CppGenError> {
2287 for member in &def.members {
2288 let optional = is_optional(&member.annotations);
2289 for decl in &member.declarators {
2290 let f = &decl.name().text;
2291 let dims = effective_array_dims(self.reg, &member.type_spec, decl)?;
2292 if optional {
2293 let _ = writeln!(self.out, " {{");
2294 let _ = writeln!(self.out, " uint8_t present = 0;");
2295 let _ = writeln!(
2296 self.out,
2297 " if (zerodds_xcdr2_c_read_u8(buf, len, &pos, &present, zd_be) != 0) return -7;"
2298 );
2299 let _ = writeln!(self.out, " s->{f}_present = present;");
2300 let _ = writeln!(self.out, " if (present) {{");
2301 self.emit_array_or_scalar_read(&format!("s->{f}"), &member.type_spec, &dims)?;
2302 let _ = writeln!(self.out, " }}");
2303 let _ = writeln!(self.out, " }}");
2304 } else {
2305 self.emit_array_or_scalar_read(&format!("s->{f}"), &member.type_spec, &dims)?;
2306 }
2307 }
2308 }
2309 Ok(())
2310 }
2311
2312 fn emit_array_or_scalar_read(
2313 &mut self,
2314 var: &str,
2315 type_spec: &TypeSpec,
2316 dims: &[u64],
2317 ) -> Result<(), CppGenError> {
2318 if dims.is_empty() {
2319 return self.emit_member_read(var, type_spec);
2320 }
2321 let needs_dheader = !self.seq_elem_is_primitive(type_spec);
2325 if needs_dheader {
2326 let _ = writeln!(
2327 self.out,
2328 " if (representation) {{ uint32_t arr_dheader = 0; if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &arr_dheader, zd_be) != 0) return -7; (void)arr_dheader; }}"
2329 );
2330 }
2331 let mut acc = var.to_string();
2332 for (d, _n) in dims.iter().enumerate() {
2333 let iv = format!("ri{d}");
2334 let _ = writeln!(
2335 self.out,
2336 " for (uint32_t {iv} = 0; {iv} < {n}; ++{iv}) {{",
2337 n = dims[d]
2338 );
2339 acc = format!("{acc}[{iv}]");
2340 }
2341 self.emit_member_read(&acc, type_spec)?;
2342 for _ in dims {
2343 let _ = writeln!(self.out, " }}");
2344 }
2345 Ok(())
2346 }
2347
2348 fn emit_member_read(&mut self, var: &str, type_spec: &TypeSpec) -> Result<(), CppGenError> {
2350 let resolved = resolve_alias(self.reg, type_spec);
2351 match &resolved {
2352 TypeSpec::Primitive(p) => {
2353 let helper = primitive_helper(*p)?;
2354 if matches!(helper, "u64" | "i64" | "f64") {
2355 let _ = writeln!(
2358 self.out,
2359 " if (representation) {{ if (zd_x2_read_{helper}(buf, len, &pos, &({var}), zd_be) != 0) return -7; }}"
2360 );
2361 let _ = writeln!(
2362 self.out,
2363 " else {{ if (zerodds_xcdr2_c_read_{helper}(buf, len, &pos, &({var}), zd_be) != 0) return -7; }}"
2364 );
2365 return Ok(());
2366 }
2367 let prefix = Self::helper_call_prefix(helper);
2368 let _ = writeln!(
2369 self.out,
2370 " if ({prefix}read_{helper}(buf, len, &pos, &({var}), zd_be) != 0) return -7;"
2371 );
2372 Ok(())
2373 }
2374 TypeSpec::String(st) => {
2375 if st.wide {
2376 return self.emit_wstring_read(var);
2377 }
2378 let _ = writeln!(
2379 self.out,
2380 " if (zerodds_xcdr2_c_read_string(buf, len, &pos, &({var}), zd_be) != 0) return -7;"
2381 );
2382 Ok(())
2383 }
2384 TypeSpec::Sequence(seq) => self.emit_sequence_read(var, &seq.elem),
2385 TypeSpec::Map(m) => self.emit_map_read(var, &m.key, &m.value),
2386 TypeSpec::Scoped(sc) => {
2387 let last = scoped_last(sc).ok_or_else(|| unsupported("empty scoped name"))?;
2388 if self.reg.enums.contains_key(&last) {
2389 let bytes = self.reg.enum_bytes.get(&last).copied().unwrap_or(4);
2392 let line = match bytes {
2393 1 => format!(
2394 " {{ uint8_t zd_e8 = 0; if (zerodds_xcdr2_c_read_u8(buf, len, &pos, &zd_e8, zd_be) != 0) return -7; ({var}) = (int32_t)(int8_t)zd_e8; }}"
2395 ),
2396 2 => format!(
2397 " {{ uint16_t zd_e16 = 0; if (zerodds_xcdr2_c_read_u16(buf, len, &pos, &zd_e16, zd_be) != 0) return -7; ({var}) = (int32_t)(int16_t)zd_e16; }}"
2398 ),
2399 _ => format!(
2400 " if (zerodds_xcdr2_c_read_i32(buf, len, &pos, (int32_t*)&({var}), zd_be) != 0) return -7;"
2401 ),
2402 };
2403 let _ = writeln!(self.out, "{line}");
2404 return Ok(());
2405 }
2406 if let Some(helper) = self.bits_helper(&last) {
2408 let prefix = Self::helper_call_prefix(helper);
2409 let _ = writeln!(
2410 self.out,
2411 " if ({prefix}read_{helper}(buf, len, &pos, &({var}), zd_be) != 0) return -7;"
2412 );
2413 return Ok(());
2414 }
2415 if let Some((cn, ndef)) = self.reg.structs.get(&last).cloned() {
2416 if self.reg.is_recursive(&last) {
2417 let ext = extensibility_of(&ndef.annotations);
2421 if !matches!(ext, Extensibility::Final) {
2422 let _ = writeln!(
2423 self.out,
2424 " if (representation) {{ uint32_t rec_dheader = 0; if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &rec_dheader, zd_be) != 0) return -7; (void)rec_dheader; }}"
2425 );
2426 }
2427 let _ = writeln!(
2428 self.out,
2429 " if ({cn}_read_body(buf, len, &pos, &({var}), zd_be, representation) != 0) return -7;"
2430 );
2431 return Ok(());
2432 }
2433 return self.emit_nested_struct_read(var, &ndef);
2434 }
2435 if let Some((cn, udef)) = self.reg.unions.get(&last).cloned() {
2436 if self.reg.is_recursive(&last) {
2437 let _ = writeln!(
2438 self.out,
2439 " if ({cn}_read_body(buf, len, &pos, &({var}), zd_be, representation) != 0) return -7;"
2440 );
2441 return Ok(());
2442 }
2443 return self.emit_union_read(var, &udef);
2444 }
2445 Err(unsupported("unresolved scoped member read (C backend)"))
2446 }
2447 TypeSpec::Fixed(f) => {
2448 let p = const_expr_to_u64(self.reg, &f.digits)
2450 .ok_or_else(|| unsupported("fixed: non-constant digit count"))?;
2451 let n = (p + 2) / 2;
2452 let _ = writeln!(
2453 self.out,
2454 " for (size_t __fi = 0; __fi < {n}; __fi++) {{ uint8_t __fb; if (zerodds_xcdr2_c_read_u8(buf, len, &pos, &__fb, zd_be) != 0) return -7; ({var}).bcd[__fi] = __fb; }}"
2455 );
2456 Ok(())
2457 }
2458 _ => Err(unsupported("complex member read")),
2459 }
2460 }
2461
2462 fn emit_nested_struct_read(&mut self, var: &str, ndef: &StructDef) -> Result<(), CppGenError> {
2464 let ext = extensibility_of(&ndef.annotations);
2470 if !matches!(ext, Extensibility::Final) {
2471 let d = self.coll_depth;
2472 self.coll_depth += 1;
2473 let r = self.emit_nested_struct_read_delimited(var, ndef, ext, d);
2474 self.coll_depth -= 1;
2475 return r;
2476 }
2477 self.emit_nested_struct_inline_read(var, ndef)
2478 }
2479
2480 fn emit_nested_struct_read_delimited(
2485 &mut self,
2486 var: &str,
2487 ndef: &StructDef,
2488 ext: Extensibility,
2489 depth: u32,
2490 ) -> Result<(), CppGenError> {
2491 let _ = writeln!(self.out, " {{");
2492 let _ = writeln!(
2497 self.out,
2498 " size_t nst_end{depth} = len; (void)nst_end{depth};"
2499 );
2500 let _ = writeln!(self.out, " if (representation) {{");
2501 let _ = writeln!(self.out, " uint32_t nst_dheader{depth} = 0;");
2502 let _ = writeln!(
2503 self.out,
2504 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &nst_dheader{depth}, zd_be) != 0) return -7;"
2505 );
2506 let _ = writeln!(
2507 self.out,
2508 " nst_end{depth} = pos + nst_dheader{depth};"
2509 );
2510 let _ = writeln!(self.out, " if (nst_end{depth} > len) return -7;");
2511 let _ = writeln!(self.out, " }}");
2512 if matches!(ext, Extensibility::Mutable) {
2513 let _ = writeln!(
2514 self.out,
2515 " while (representation && pos < nst_end{depth}) {{"
2516 );
2517 let _ = writeln!(self.out, " uint32_t emheader{depth} = 0;");
2518 let _ = writeln!(
2519 self.out,
2520 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &emheader{depth}, zd_be) != 0) return -7;"
2521 );
2522 let _ = writeln!(
2523 self.out,
2524 " uint32_t mid{depth} = emheader{depth} & 0x0FFFFFFFu;"
2525 );
2526 let _ = writeln!(
2527 self.out,
2528 " uint32_t lc{depth} = (emheader{depth} >> 28) & 0x7u;"
2529 );
2530 let _ = writeln!(self.out, " uint32_t nextint{depth} = 0;");
2531 let _ = writeln!(self.out, " size_t body_len{depth} = 0;");
2532 let _ = writeln!(
2533 self.out,
2534 " if (lc{depth} == 0) body_len{depth} = 1; else if (lc{depth} == 1) body_len{depth} = 2; else if (lc{depth} == 2) body_len{depth} = 4; else if (lc{depth} == 3) body_len{depth} = 8;"
2535 );
2536 let _ = writeln!(self.out, " else if (lc{depth} == 5) {{");
2537 let _ = writeln!(self.out, " size_t peek_pos{depth} = pos;");
2538 let _ = writeln!(
2539 self.out,
2540 " if (zerodds_xcdr2_c_read_u32(buf, len, &peek_pos{depth}, &nextint{depth}, zd_be) != 0) return -7;"
2541 );
2542 let _ = writeln!(
2543 self.out,
2544 " body_len{depth} = 4u + (size_t)nextint{depth};"
2545 );
2546 let _ = writeln!(self.out, " }} else {{");
2547 let _ = writeln!(
2548 self.out,
2549 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &nextint{depth}, zd_be) != 0) return -7;"
2550 );
2551 let _ = writeln!(
2552 self.out,
2553 " body_len{depth} = nextint{depth};"
2554 );
2555 let _ = writeln!(self.out, " }}");
2556 let _ = writeln!(
2557 self.out,
2558 " if (pos + body_len{depth} > nst_end{depth}) return -7;"
2559 );
2560 self.emit_mutable_member_dispatch_base(
2561 ndef,
2562 &format!("({var})."),
2563 &format!("mid{depth}"),
2564 &format!("body_len{depth}"),
2565 )?;
2566 let _ = writeln!(self.out, " }}");
2567 } else {
2568 self.emit_nested_struct_inline_read(var, ndef)?;
2569 let _ = writeln!(
2570 self.out,
2571 " if (representation) pos = nst_end{depth};"
2572 );
2573 }
2574 let _ = writeln!(self.out, " }}");
2575 Ok(())
2576 }
2577
2578 fn emit_nested_struct_inline_read(
2582 &mut self,
2583 var: &str,
2584 ndef: &StructDef,
2585 ) -> Result<(), CppGenError> {
2586 for member in &ndef.members {
2587 let optional = is_optional(&member.annotations);
2588 for decl in &member.declarators {
2589 let f = &decl.name().text;
2590 let dims = effective_array_dims(self.reg, &member.type_spec, decl)?;
2591 if optional {
2592 let _ = writeln!(self.out, " {{");
2593 let _ = writeln!(self.out, " uint8_t present = 0;");
2594 let _ = writeln!(
2595 self.out,
2596 " if (zerodds_xcdr2_c_read_u8(buf, len, &pos, &present, zd_be) != 0) return -7;"
2597 );
2598 let _ = writeln!(self.out, " ({var}).{f}_present = present;");
2599 let _ = writeln!(self.out, " if (present) {{");
2600 self.emit_array_or_scalar_read(
2601 &format!("({var}).{f}"),
2602 &member.type_spec,
2603 &dims,
2604 )?;
2605 let _ = writeln!(self.out, " }}");
2606 let _ = writeln!(self.out, " }}");
2607 } else {
2608 self.emit_array_or_scalar_read(
2609 &format!("({var}).{f}"),
2610 &member.type_spec,
2611 &dims,
2612 )?;
2613 }
2614 }
2615 }
2616 Ok(())
2617 }
2618
2619 fn emit_wstring_read(&mut self, var: &str) -> Result<(), CppGenError> {
2621 let _ = writeln!(self.out, " {{");
2622 let _ = writeln!(self.out, " uint32_t ws_bytes = 0;");
2623 let _ = writeln!(
2624 self.out,
2625 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &ws_bytes, zd_be) != 0) return -7;"
2626 );
2627 let _ = writeln!(self.out, " uint32_t ws_n = ws_bytes / 2u;");
2628 let _ = writeln!(
2629 self.out,
2630 " uint16_t* ws_p = (uint16_t*)malloc(((size_t)ws_n + 1) * sizeof(uint16_t));"
2631 );
2632 let _ = writeln!(self.out, " if (ws_p == NULL) return -7;");
2633 let _ = writeln!(
2634 self.out,
2635 " for (uint32_t wi = 0; wi < ws_n; ++wi) {{ if (zerodds_xcdr2_c_read_u16(buf, len, &pos, &ws_p[wi], zd_be) != 0) {{ free(ws_p); return -7; }} }}"
2636 );
2637 let _ = writeln!(self.out, " ws_p[ws_n] = 0;");
2638 let _ = writeln!(self.out, " ({var}) = ws_p;");
2639 let _ = writeln!(self.out, " }}");
2640 Ok(())
2641 }
2642
2643 fn emit_map_read(
2646 &mut self,
2647 var: &str,
2648 key: &TypeSpec,
2649 value: &TypeSpec,
2650 ) -> Result<(), CppGenError> {
2651 let kc = c_type_for(self.reg, key)?;
2652 let vc = c_type_for(self.reg, value)?;
2653 let _ = writeln!(self.out, " {{");
2654 let _ = writeln!(
2657 self.out,
2658 " if (zerodds_xcdr2_c_pad_read(buf, len, &pos, 4) != 0) return -1;"
2659 );
2660 if !(self.seq_elem_is_primitive(key) && self.seq_elem_is_primitive(value)) {
2661 let _ = writeln!(self.out, " if (representation) {{");
2662 let _ = writeln!(self.out, " uint32_t map_dheader = 0;");
2663 let _ = writeln!(
2664 self.out,
2665 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &map_dheader, zd_be) != 0) return -7;"
2666 );
2667 let _ = writeln!(self.out, " (void)map_dheader;");
2668 let _ = writeln!(self.out, " }}");
2669 }
2670 let _ = writeln!(self.out, " uint32_t map_len = 0;");
2671 let _ = writeln!(
2672 self.out,
2673 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &map_len, zd_be) != 0) return -7;"
2674 );
2675 let _ = writeln!(self.out, " ({var}).len = map_len;");
2676 let _ = writeln!(
2677 self.out,
2678 " ({var}).keys = ({kc}*)calloc(map_len ? map_len : 1, sizeof({kc}));"
2679 );
2680 let _ = writeln!(
2681 self.out,
2682 " ({var}).vals = ({vc}*)calloc(map_len ? map_len : 1, sizeof({vc}));"
2683 );
2684 let _ = writeln!(
2685 self.out,
2686 " if (((({var}).keys == NULL) || (({var}).vals == NULL)) && map_len > 0) return -7;"
2687 );
2688 let mv = format!("mi{}", self.coll_depth);
2689 let _ = writeln!(
2690 self.out,
2691 " for (uint32_t {mv} = 0; {mv} < map_len; ++{mv}) {{"
2692 );
2693 self.coll_depth += 1;
2694 let rk = self.emit_member_read(&format!("({var}).keys[{mv}]"), key);
2695 let rv = if rk.is_ok() {
2696 self.emit_member_read(&format!("({var}).vals[{mv}]"), value)
2697 } else {
2698 Ok(())
2699 };
2700 self.coll_depth -= 1;
2701 rk.and(rv)?;
2702 let _ = writeln!(self.out, " }}");
2703 let _ = writeln!(self.out, " }}");
2704 Ok(())
2705 }
2706
2707 fn emit_union_read(&mut self, var: &str, udef: &UnionDef) -> Result<(), CppGenError> {
2710 let u_dheader = !matches!(extensibility_of(&udef.annotations), Extensibility::Final);
2713 if u_dheader {
2714 let _ = writeln!(self.out, " if (representation) {{");
2717 let _ = writeln!(
2718 self.out,
2719 " if (zerodds_xcdr2_c_pad_read(buf, len, &pos, 4) != 0) return -1;"
2720 );
2721 let _ = writeln!(
2722 self.out,
2723 " {{ uint32_t u_dh = 0; if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &u_dh, zd_be) != 0) return -7; (void)u_dh; }}"
2724 );
2725 let _ = writeln!(self.out, " }}");
2726 }
2727 let disc_ts = switch_type_spec(&udef.switch_type);
2728 self.emit_member_read(&format!("({var})._d"), &disc_ts)?;
2729 let _ = writeln!(self.out, " switch (({var})._d) {{");
2730 let mut default_case: Option<&Case> = None;
2731 for case in &udef.cases {
2732 let field = union_case_field(case);
2733 let mut has_value_label = false;
2734 for label in &case.labels {
2735 match label {
2736 CaseLabel::Value(expr) => {
2737 has_value_label = true;
2738 let lit = self.case_label_literal(expr)?;
2739 let _ = writeln!(self.out, " case {lit}:");
2740 }
2741 CaseLabel::Default => {
2742 default_case = Some(case);
2743 }
2744 }
2745 }
2746 if has_value_label {
2747 self.emit_member_read(&format!("({var})._u.{field}"), &case.element.type_spec)?;
2748 let _ = writeln!(self.out, " break;");
2749 }
2750 }
2751 if let Some(case) = default_case {
2752 let field = union_case_field(case);
2753 let _ = writeln!(self.out, " default:");
2754 self.emit_member_read(&format!("({var})._u.{field}"), &case.element.type_spec)?;
2755 let _ = writeln!(self.out, " break;");
2756 } else {
2757 let _ = writeln!(self.out, " default: break;");
2758 }
2759 let _ = writeln!(self.out, " }}");
2760 Ok(())
2761 }
2762
2763 fn eval_bound(&self, bound: Option<&ConstExpr>) -> Option<u64> {
2767 let expr = bound?;
2768 evaluate(expr, &self.reg.consts)
2769 .ok()
2770 .and_then(|v| v.as_i64())
2771 .filter(|n| *n >= 0)
2772 .map(|n| n as u64)
2773 }
2774
2775 fn case_label_literal(&self, expr: &ConstExpr) -> Result<String, CppGenError> {
2778 if let Ok(v) = evaluate(expr, &self.reg.consts) {
2781 if let Some(i) = v.as_i64() {
2782 return Ok(i.to_string());
2783 }
2784 }
2785 Err(unsupported("non-integer union case label (C backend)"))
2786 }
2787
2788 fn emit_sequence_read(&mut self, var: &str, elem: &TypeSpec) -> Result<(), CppGenError> {
2789 let _ = writeln!(self.out, " {{");
2790 if !self.seq_elem_is_primitive(elem) {
2793 let _ = writeln!(self.out, " if (representation) {{");
2794 let _ = writeln!(self.out, " uint32_t seq_dheader = 0;");
2795 let _ = writeln!(
2796 self.out,
2797 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &seq_dheader, zd_be) != 0) return -7;"
2798 );
2799 let _ = writeln!(self.out, " (void)seq_dheader;");
2800 let _ = writeln!(self.out, " }}");
2801 }
2802 let _ = writeln!(self.out, " uint32_t seq_len = 0;");
2803 let _ = writeln!(
2804 self.out,
2805 " if (zerodds_xcdr2_c_read_u32(buf, len, &pos, &seq_len, zd_be) != 0) return -7;"
2806 );
2807 let elem_c = c_type_for(self.reg, elem)?;
2808 let _ = writeln!(self.out, " ({var}).len = seq_len;");
2809 let _ = writeln!(
2810 self.out,
2811 " ({var}).elems = ({elem_c}*)calloc(seq_len ? seq_len : 1, sizeof({elem_c}));"
2812 );
2813 let _ = writeln!(
2814 self.out,
2815 " if (({var}).elems == NULL && seq_len > 0) return -7;"
2816 );
2817 let iv = format!("i{}", self.coll_depth);
2818 let _ = writeln!(
2819 self.out,
2820 " for (uint32_t {iv} = 0; {iv} < seq_len; ++{iv}) {{"
2821 );
2822 self.coll_depth += 1;
2826 let r = self.emit_member_read(&format!("({var}).elems[{iv}]"), elem);
2827 self.coll_depth -= 1;
2828 r?;
2829 let _ = writeln!(self.out, " }}");
2830 let _ = writeln!(self.out, " }}");
2831 Ok(())
2832 }
2833
2834 fn seq_elem_is_primitive(&self, elem: &TypeSpec) -> bool {
2838 let resolved = resolve_alias(self.reg, elem);
2839 match &resolved {
2840 TypeSpec::Primitive(_) => true,
2841 TypeSpec::Scoped(sc) => scoped_last(sc).is_some_and(|last| {
2842 self.reg.enums.contains_key(&last)
2845 || self.reg.bitmasks.contains_key(&last)
2846 || self.reg.bitsets.contains_key(&last)
2847 }),
2848 _ => false,
2849 }
2850 }
2851
2852 fn emit_mutable_member_dispatch(&mut self, def: &StructDef) -> Result<(), CppGenError> {
2853 self.emit_mutable_member_dispatch_base(def, "s->", "mid", "body_len")
2854 }
2855
2856 fn emit_mutable_member_dispatch_base(
2861 &mut self,
2862 def: &StructDef,
2863 base: &str,
2864 mid_var: &str,
2865 body_len_var: &str,
2866 ) -> Result<(), CppGenError> {
2867 let _ = writeln!(self.out, " switch ({mid_var}) {{");
2868 let mut auto_id: u32 = 0;
2870 for member in &def.members {
2871 let id = id_annotation(&member.annotations).unwrap_or(auto_id);
2872 auto_id = id + 1;
2873 for decl in &member.declarators {
2874 let f = format!("{base}{}", decl.name().text);
2875 let dims = effective_array_dims(self.reg, &member.type_spec, decl)?;
2876 let _ = writeln!(self.out, " case {id}: {{");
2877 self.emit_array_or_scalar_read(&f, &member.type_spec, &dims)?;
2878 let _ = writeln!(self.out, " break;");
2879 let _ = writeln!(self.out, " }}");
2880 }
2881 }
2882 let _ = writeln!(self.out, " default: pos += {body_len_var}; break;");
2883 let _ = writeln!(self.out, " }}");
2884 Ok(())
2885 }
2886
2887 fn emit_free_body(&mut self, c_name: &str, def: &StructDef) {
2888 let _ = writeln!(
2889 self.out,
2890 "static void {c_name}_sample_free(void* sample) {{"
2891 );
2892 let _ = writeln!(self.out, " if (sample == NULL) return;");
2893 let _ = writeln!(self.out, " {c_name}_t* s = ({c_name}_t*)sample;");
2894 let _ = writeln!(self.out, " (void)s;");
2895 for member in &def.members {
2896 let resolved = resolve_alias(self.reg, &member.type_spec);
2897 for decl in &member.declarators {
2898 let f = &decl.name().text;
2899 let dims =
2900 effective_array_dims(self.reg, &member.type_spec, decl).unwrap_or_default();
2901 if dims.is_empty() {
2902 self.emit_free_member(&format!("s->{f}"), &resolved);
2904 } else {
2905 let mut acc = format!("s->{f}");
2909 for (d, n) in dims.iter().enumerate() {
2910 let iv = format!("fi{d}");
2911 let _ = writeln!(
2912 self.out,
2913 " for (uint32_t {iv} = 0; {iv} < {n}; ++{iv}) {{"
2914 );
2915 acc = format!("{acc}[{iv}]");
2916 }
2917 self.emit_free_member(&acc, &resolved);
2918 for _ in &dims {
2919 let _ = writeln!(self.out, " }}");
2920 }
2921 }
2922 }
2923 }
2924 let _ = writeln!(self.out, "}}");
2925 let _ = writeln!(self.out);
2926 }
2927
2928 fn emit_free_member(&mut self, acc: &str, resolved: &TypeSpec) {
2932 match resolved {
2933 TypeSpec::String(_) => {
2934 let _ = writeln!(self.out, " free({acc}); {acc} = NULL;");
2936 }
2937 TypeSpec::Sequence(seq) => {
2938 if matches!(resolve_alias(self.reg, &seq.elem), TypeSpec::String(_)) {
2939 let _ = writeln!(
2940 self.out,
2941 " for (uint32_t fsi = 0; fsi < ({acc}).len; ++fsi) free(({acc}).elems[fsi]);"
2942 );
2943 }
2944 let _ = writeln!(
2945 self.out,
2946 " free(({acc}).elems); ({acc}).elems = NULL; ({acc}).len = 0;"
2947 );
2948 }
2949 TypeSpec::Map(m) => {
2950 if matches!(resolve_alias(self.reg, &m.key), TypeSpec::String(_)) {
2951 let _ = writeln!(
2952 self.out,
2953 " for (uint32_t fki = 0; fki < ({acc}).len; ++fki) free(({acc}).keys[fki]);"
2954 );
2955 }
2956 if matches!(resolve_alias(self.reg, &m.value), TypeSpec::String(_)) {
2957 let _ = writeln!(
2958 self.out,
2959 " for (uint32_t fvi = 0; fvi < ({acc}).len; ++fvi) free(({acc}).vals[fvi]);"
2960 );
2961 }
2962 let _ = writeln!(self.out, " free(({acc}).keys); ({acc}).keys = NULL;");
2963 let _ = writeln!(
2964 self.out,
2965 " free(({acc}).vals); ({acc}).vals = NULL; ({acc}).len = 0;"
2966 );
2967 }
2968 _ => {}
2969 }
2970 }
2971
2972 fn emit_key_hash_body(&mut self, c_name: &str, def: &StructDef) {
2973 let _ = writeln!(
2976 self.out,
2977 "static int {c_name}_key_hash(const void* sample, uint8_t out_hash[16]) {{"
2978 );
2979 let _ = writeln!(
2980 self.out,
2981 " const {c_name}_t* s = (const {c_name}_t*)sample;"
2982 );
2983 let _ = writeln!(self.out, " uint8_t* kh_buf = NULL;");
2984 let _ = writeln!(self.out, " size_t kh_len = 0;");
2985 let _ = writeln!(self.out, " size_t kh_cap = 0;");
2986 for member in &def.members {
2987 if !is_key(&member.annotations) {
2988 continue;
2989 }
2990 for decl in &member.declarators {
2991 let f = &decl.name().text;
2992 match &member.type_spec {
2993 TypeSpec::Primitive(p) => {
2994 let helper = match primitive_helper(*p) {
2995 Ok(h) => h,
2996 Err(_) => continue,
2997 };
2998 let _ = writeln!(
2999 self.out,
3000 " if (zerodds_xcdr2_c_kh_write_{helper}(&kh_buf, &kh_len, &kh_cap, s->{f}) != 0) {{ free(kh_buf); return -1; }}"
3001 );
3002 }
3003 TypeSpec::String(_) => {
3004 let _ = writeln!(
3005 self.out,
3006 " if (zerodds_xcdr2_c_kh_write_string(&kh_buf, &kh_len, &kh_cap, s->{f}) != 0) {{ free(kh_buf); return -1; }}"
3007 );
3008 }
3009 _ => {}
3010 }
3011 }
3012 }
3013 let _ = writeln!(
3014 self.out,
3015 " zerodds_xcdr2_c_compute_key_hash(kh_buf, kh_len, /*max_size_static=*/0, out_hash);"
3016 );
3017 let _ = writeln!(self.out, " free(kh_buf);");
3018 let _ = writeln!(self.out, " return 0;");
3019 let _ = writeln!(self.out, "}}");
3020 let _ = writeln!(self.out);
3021 }
3022}
3023
3024#[derive(Clone)]
3030enum AggDef {
3031 Struct(StructDef),
3032 Union(UnionDef),
3033}
3034
3035fn collect_aggregates(
3039 defs: &[Definition],
3040 scope: &[String],
3041 out: &mut Vec<(String, Vec<String>, AggDef)>,
3042) {
3043 for d in defs {
3044 match d {
3045 Definition::Module(m) => {
3046 let mut s = scope.to_vec();
3047 s.push(m.name.text.clone());
3048 collect_aggregates(&m.definitions, &s, out);
3049 }
3050 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Struct(StructDcl::Def(s)))) => {
3051 out.push((
3052 s.name.text.clone(),
3053 scope.to_vec(),
3054 AggDef::Struct(s.clone()),
3055 ));
3056 }
3057 Definition::Type(TypeDecl::Constr(ConstrTypeDecl::Union(UnionDcl::Def(u)))) => {
3058 out.push((
3059 u.name.text.clone(),
3060 scope.to_vec(),
3061 AggDef::Union(u.clone()),
3062 ));
3063 }
3064 _ => {}
3065 }
3066 }
3067}
3068
3069fn dds_type_name(scope: &[String], name: &str) -> String {
3070 if scope.is_empty() {
3071 name.to_string()
3072 } else {
3073 let mut s = scope.join("::");
3074 s.push_str("::");
3075 s.push_str(name);
3076 s
3077 }
3078}
3079
3080fn switch_type_spec(s: &SwitchTypeSpec) -> TypeSpec {
3083 match s {
3084 SwitchTypeSpec::Integer(it) => TypeSpec::Primitive(PrimitiveType::Integer(*it)),
3085 SwitchTypeSpec::Char => TypeSpec::Primitive(PrimitiveType::Char),
3086 SwitchTypeSpec::Boolean => TypeSpec::Primitive(PrimitiveType::Boolean),
3087 SwitchTypeSpec::Octet => TypeSpec::Primitive(PrimitiveType::Octet),
3088 SwitchTypeSpec::Scoped(sn) => TypeSpec::Scoped(sn.clone()),
3089 }
3090}
3091
3092fn union_case_field(case: &Case) -> String {
3094 case.element.declarator.name().text.clone()
3095}
3096
3097fn scope_join(scope: &[String], name: &str, sep: &str) -> String {
3099 if scope.is_empty() {
3100 name.to_string()
3101 } else {
3102 let mut s = scope.join(sep);
3103 s.push_str(sep);
3104 s.push_str(name);
3105 s
3106 }
3107}
3108
3109fn c_identifier(scope: &[String], name: &str) -> String {
3110 if scope.is_empty() {
3111 name.to_string()
3112 } else {
3113 let mut s = scope.join("_");
3114 s.push('_');
3115 s.push_str(name);
3116 s
3117 }
3118}
3119
3120impl Extensibility {
3121 fn as_u8(self) -> u8 {
3122 match self {
3123 Self::Final => 0,
3124 Self::Appendable => 1,
3125 Self::Mutable => 2,
3126 }
3127 }
3128}
3129
3130fn extensibility_of(annotations: &[Annotation]) -> Extensibility {
3131 for a in annotations {
3132 if let Some(name) = a.name.parts.last() {
3133 match name.text.as_str() {
3134 "final" | "Final" => return Extensibility::Final,
3135 "appendable" | "Appendable" => return Extensibility::Appendable,
3136 "mutable" | "Mutable" => return Extensibility::Mutable,
3137 _ => {}
3138 }
3139 }
3140 }
3141 Extensibility::Appendable
3149}
3150
3151fn is_optional(annotations: &[Annotation]) -> bool {
3152 annotations.iter().any(|a| {
3153 a.name
3154 .parts
3155 .last()
3156 .is_some_and(|p| p.text == "optional" || p.text == "Optional")
3157 })
3158}
3159
3160fn primitive_wire_bytes(p: PrimitiveType) -> u32 {
3163 match p {
3164 PrimitiveType::Boolean | PrimitiveType::Octet | PrimitiveType::Char => 1,
3165 PrimitiveType::WideChar => 2,
3166 PrimitiveType::Integer(IntegerType::Int8 | IntegerType::UInt8) => 1,
3167 PrimitiveType::Integer(
3168 IntegerType::Short | IntegerType::Int16 | IntegerType::UShort | IntegerType::UInt16,
3169 ) => 2,
3170 PrimitiveType::Integer(
3171 IntegerType::Long | IntegerType::Int32 | IntegerType::ULong | IntegerType::UInt32,
3172 ) => 4,
3173 PrimitiveType::Integer(
3174 IntegerType::LongLong
3175 | IntegerType::Int64
3176 | IntegerType::ULongLong
3177 | IntegerType::UInt64,
3178 ) => 8,
3179 PrimitiveType::Floating(FloatingType::Float) => 4,
3180 PrimitiveType::Floating(FloatingType::Double) => 8,
3181 PrimitiveType::Floating(FloatingType::LongDouble) => 16,
3183 }
3184}
3185
3186fn mutable_compact_lc(
3192 reg: &TypeReg,
3193 type_spec: &TypeSpec,
3194 dims: &[u64],
3195 optional: bool,
3196) -> Option<u8> {
3197 if !dims.is_empty() || optional {
3198 return None;
3199 }
3200 let resolved = resolve_alias(reg, type_spec);
3201 match &resolved {
3202 TypeSpec::Primitive(p) => match primitive_wire_bytes(*p) {
3203 1 => Some(0),
3204 2 => Some(1),
3205 4 => Some(2),
3206 8 => Some(3),
3207 _ => None, },
3209 _ if member_body_has_leading_dheader_c(reg, &resolved) => Some(5),
3218 _ => None,
3219 }
3220}
3221
3222fn member_body_has_leading_dheader_c(reg: &TypeReg, type_spec: &TypeSpec) -> bool {
3235 match resolve_alias(reg, type_spec) {
3236 TypeSpec::String(_) => true,
3237 TypeSpec::Map(_) => true,
3238 TypeSpec::Sequence(seq) => !seq_elem_is_primitive_reg(reg, &seq.elem),
3239 TypeSpec::Scoped(sc) => scoped_last(&sc)
3240 .and_then(|last| reg.structs.get(&last).cloned())
3241 .is_some_and(|(_, ndef)| {
3242 !matches!(extensibility_of(&ndef.annotations), Extensibility::Final)
3243 }),
3244 _ => false,
3245 }
3246}
3247
3248fn seq_elem_is_primitive_reg(reg: &TypeReg, elem: &TypeSpec) -> bool {
3253 match resolve_alias(reg, elem) {
3254 TypeSpec::Primitive(_) => true,
3255 TypeSpec::Scoped(sc) => scoped_last(&sc).is_some_and(|last| {
3256 reg.enums.contains_key(&last)
3257 || reg.bitmasks.contains_key(&last)
3258 || reg.bitsets.contains_key(&last)
3259 }),
3260 _ => false,
3261 }
3262}
3263
3264fn array_dims(reg: &TypeReg, decl: &Declarator) -> Result<Vec<u64>, CppGenError> {
3270 match decl {
3271 Declarator::Simple(_) => Ok(Vec::new()),
3272 Declarator::Array(arr) => {
3273 let mut dims = Vec::with_capacity(arr.sizes.len());
3274 for sz in &arr.sizes {
3275 let n = const_expr_to_u64(reg, sz)
3276 .ok_or_else(|| unsupported("non-literal array bound"))?;
3277 dims.push(n);
3278 }
3279 Ok(dims)
3280 }
3281 }
3282}
3283
3284fn effective_array_dims(
3290 reg: &TypeReg,
3291 type_spec: &TypeSpec,
3292 decl: &Declarator,
3293) -> Result<Vec<u64>, CppGenError> {
3294 let mut dims = Vec::new();
3295 if let TypeSpec::Scoped(sc) = type_spec {
3296 if let Some(last) = scoped_last(sc) {
3297 if let Some(td) = reg.typedef_arrays.get(&last) {
3298 dims.extend_from_slice(td);
3299 }
3300 }
3301 }
3302 dims.extend(array_dims(reg, decl)?);
3303 Ok(dims)
3304}
3305
3306fn holder_uint_c_type(bits: u32) -> &'static str {
3308 match bits {
3309 0..=8 => "uint8_t",
3310 9..=16 => "uint16_t",
3311 17..=32 => "uint32_t",
3312 _ => "uint64_t",
3313 }
3314}
3315
3316fn bitmask_holder_c_type(b: &BitmaskDecl) -> &'static str {
3319 let bound = extract_int_annotation_c(&b.annotations, "bit_bound").unwrap_or(32);
3324 holder_uint_c_type(bound)
3325}
3326
3327fn bitset_holder_c_type(b: &BitsetDecl) -> &'static str {
3331 let mut total: u32 = 0;
3332 for f in &b.bitfields {
3333 if let ConstExpr::Literal(l) = &f.spec.width {
3334 if l.kind == LiteralKind::Integer {
3335 if let Ok(w) = l.raw.trim().parse::<u32>() {
3336 total = total.saturating_add(w);
3337 }
3338 }
3339 }
3340 }
3341 holder_uint_c_type(total)
3342}
3343
3344fn extract_int_annotation_c(anns: &[Annotation], name: &str) -> Option<u32> {
3347 let a = anns
3348 .iter()
3349 .find(|a| a.name.parts.last().map(|p| p.text.as_str()) == Some(name))?;
3350 if let AnnotationParams::Single(ConstExpr::Literal(l)) = &a.params {
3351 if l.kind == LiteralKind::Integer {
3352 return l.raw.trim().parse::<u32>().ok();
3353 }
3354 }
3355 None
3356}
3357
3358fn const_expr_to_u64_pre(consts: &SymbolTable, e: &ConstExpr) -> Option<u64> {
3362 if let ConstExpr::Literal(l) = e {
3363 if l.kind == LiteralKind::Integer {
3364 let raw = l.raw.trim();
3365 return if let Some(hex) = raw.strip_prefix("0x").or_else(|| raw.strip_prefix("0X")) {
3366 u64::from_str_radix(hex, 16).ok()
3367 } else {
3368 raw.parse::<u64>().ok()
3369 };
3370 }
3371 }
3372 evaluate_positive_int(e, consts, e.span()).ok()
3373}
3374
3375fn const_expr_to_u64(reg: &TypeReg, e: &ConstExpr) -> Option<u64> {
3376 if let ConstExpr::Literal(l) = e {
3378 if l.kind == LiteralKind::Integer {
3379 let raw = l.raw.trim();
3380 let parsed =
3381 if let Some(hex) = raw.strip_prefix("0x").or_else(|| raw.strip_prefix("0X")) {
3382 u64::from_str_radix(hex, 16).ok()
3383 } else {
3384 raw.parse::<u64>().ok()
3385 };
3386 if let Some(v) = parsed {
3387 return Some(v);
3388 }
3389 }
3390 }
3391 evaluate_positive_int(e, ®.consts, e.span()).ok()
3394}
3395
3396fn is_key(annotations: &[Annotation]) -> bool {
3397 annotations.iter().any(|a| {
3398 a.name
3399 .parts
3400 .last()
3401 .is_some_and(|p| p.text == "key" || p.text == "Key")
3402 })
3403}
3404
3405fn struct_has_key(def: &StructDef) -> bool {
3406 def.members.iter().any(|m| is_key(&m.annotations))
3407}
3408
3409fn id_annotation(annotations: &[Annotation]) -> Option<u32> {
3410 for a in annotations {
3411 let last = a.name.parts.last()?;
3412 if last.text != "id" && last.text != "Id" {
3413 continue;
3414 }
3415 if let AnnotationParams::Single(ConstExpr::Literal(lit)) = &a.params {
3416 if lit.kind == LiteralKind::Integer {
3417 if let Ok(v) = lit.raw.parse::<u32>() {
3418 return Some(v);
3419 }
3420 }
3421 }
3422 }
3423 None
3424}
3425fn c_type_for(reg: &TypeReg, type_spec: &TypeSpec) -> Result<String, CppGenError> {
3427 let s = match type_spec {
3428 TypeSpec::Scoped(sc) => {
3429 let last = scoped_last(sc).ok_or_else(|| unsupported("empty scoped name"))?;
3430 if let Some(cn) = reg.enums.get(&last) {
3432 return Ok(format!("{cn}_t"));
3433 }
3434 if let Some((cn, _)) = reg.bitmasks.get(&last) {
3436 return Ok(format!("{cn}_t"));
3437 }
3438 if let Some((cn, _)) = reg.bitsets.get(&last) {
3439 return Ok(format!("{cn}_t"));
3440 }
3441 if reg.typedefs.contains_key(&last) {
3446 let resolved = resolve_alias(reg, type_spec);
3447 return c_type_for(reg, &resolved);
3448 }
3449 if let Some((cn, _)) = reg.structs.get(&last) {
3454 if reg.is_recursive(&last) {
3455 return Ok(format!("struct {cn}_s"));
3456 }
3457 return Ok(format!("{cn}_t"));
3458 }
3459 if let Some((cn, _)) = reg.unions.get(&last) {
3461 if reg.is_recursive(&last) {
3462 return Ok(format!("struct {cn}_s"));
3463 }
3464 return Ok(format!("{cn}_t"));
3465 }
3466 return Err(unsupported("unresolved scoped type (C backend)"));
3467 }
3468 TypeSpec::Primitive(p) => match p {
3469 PrimitiveType::Boolean => "uint8_t",
3470 PrimitiveType::Octet => "uint8_t",
3471 PrimitiveType::Char => "char",
3472 PrimitiveType::WideChar => "uint16_t",
3473 PrimitiveType::Integer(IntegerType::Short)
3474 | PrimitiveType::Integer(IntegerType::Int16) => "int16_t",
3475 PrimitiveType::Integer(IntegerType::UShort)
3476 | PrimitiveType::Integer(IntegerType::UInt16) => "uint16_t",
3477 PrimitiveType::Integer(IntegerType::Long)
3478 | PrimitiveType::Integer(IntegerType::Int32) => "int32_t",
3479 PrimitiveType::Integer(IntegerType::ULong)
3480 | PrimitiveType::Integer(IntegerType::UInt32) => "uint32_t",
3481 PrimitiveType::Integer(IntegerType::LongLong)
3482 | PrimitiveType::Integer(IntegerType::Int64) => "int64_t",
3483 PrimitiveType::Integer(IntegerType::ULongLong)
3484 | PrimitiveType::Integer(IntegerType::UInt64) => "uint64_t",
3485 PrimitiveType::Integer(IntegerType::Int8) => "int8_t",
3486 PrimitiveType::Integer(IntegerType::UInt8) => "uint8_t",
3487 PrimitiveType::Floating(FloatingType::Float) => "float",
3488 PrimitiveType::Floating(FloatingType::Double) => "double",
3489 PrimitiveType::Floating(FloatingType::LongDouble) => {
3490 return Err(unsupported("long double"));
3491 }
3492 },
3493 TypeSpec::String(st) => {
3494 if st.wide {
3495 "uint16_t*"
3497 } else {
3498 "char*"
3499 }
3500 }
3501 TypeSpec::Sequence(seq) => {
3502 let elem = c_type_for(reg, &seq.elem)?;
3503 return Ok(format!("struct {{ uint32_t len; {elem}* elems; }}"));
3504 }
3505 TypeSpec::Map(m) => {
3506 let kc = c_type_for(reg, &m.key)?;
3508 let vc = c_type_for(reg, &m.value)?;
3509 return Ok(format!(
3510 "struct {{ uint32_t len; {kc}* keys; {vc}* vals; }}"
3511 ));
3512 }
3513 TypeSpec::Fixed(f) => {
3514 let p = const_expr_to_u64(reg, &f.digits)
3518 .ok_or_else(|| unsupported("fixed: non-constant digit count"))?;
3519 let n = (p + 2) / 2;
3520 return Ok(format!("struct {{ uint8_t bcd[{n}]; }}"));
3521 }
3522 _ => {
3523 return Err(unsupported("non-primitive type in field"));
3524 }
3525 };
3526 Ok(s.to_string())
3527}
3528
3529fn primitive_helper(p: PrimitiveType) -> Result<&'static str, CppGenError> {
3530 Ok(match p {
3531 PrimitiveType::Boolean | PrimitiveType::Octet => "u8",
3532 PrimitiveType::Char => "u8",
3533 PrimitiveType::WideChar => "u16",
3534 PrimitiveType::Integer(IntegerType::Short) | PrimitiveType::Integer(IntegerType::Int16) => {
3535 "i16"
3536 }
3537 PrimitiveType::Integer(IntegerType::UShort)
3538 | PrimitiveType::Integer(IntegerType::UInt16) => "u16",
3539 PrimitiveType::Integer(IntegerType::Long) | PrimitiveType::Integer(IntegerType::Int32) => {
3540 "i32"
3541 }
3542 PrimitiveType::Integer(IntegerType::ULong)
3543 | PrimitiveType::Integer(IntegerType::UInt32) => "u32",
3544 PrimitiveType::Integer(IntegerType::LongLong)
3545 | PrimitiveType::Integer(IntegerType::Int64) => "i64",
3546 PrimitiveType::Integer(IntegerType::ULongLong)
3547 | PrimitiveType::Integer(IntegerType::UInt64) => "u64",
3548 PrimitiveType::Integer(IntegerType::Int8) => "i8",
3549 PrimitiveType::Integer(IntegerType::UInt8) => "u8",
3550 PrimitiveType::Floating(FloatingType::Float) => "f32",
3551 PrimitiveType::Floating(FloatingType::Double) => "f64",
3552 PrimitiveType::Floating(FloatingType::LongDouble) => {
3553 return Err(unsupported("long double"));
3554 }
3555 })
3556}
3557
3558#[cfg(test)]
3559mod tests {
3560 #![allow(clippy::expect_used)]
3561 use super::*;
3562 use zerodds_idl::config::ParserConfig;
3563
3564 fn gen_c(src: &str) -> String {
3565 let ast = zerodds_idl::parse(src, &ParserConfig::default()).expect("parse ok");
3566 generate_c_header(&ast, &CGenOptions::default()).expect("c-gen ok")
3567 }
3568
3569 #[test]
3570 fn empty_final_struct_emits_typedef_and_typesupport() {
3571 let h = gen_c("@final struct Empty {};");
3572 assert!(h.contains("typedef struct Empty_s"));
3573 assert!(h.contains("Empty_typesupport"));
3574 assert!(h.contains(".extensibility = 0"));
3575 }
3576
3577 #[test]
3578 fn primitive_struct_maps_types() {
3579 let h = gen_c("@final struct Point { long x; long y; };");
3580 assert!(h.contains("int32_t x;"));
3581 assert!(h.contains("int32_t y;"));
3582 assert!(h.contains("\"Point\""));
3583 }
3584
3585 #[test]
3586 fn nested_module_yields_scoped_type_name() {
3587 let h = gen_c("module Outer { module Inner { @final struct S { long x; }; }; };");
3588 assert!(h.contains("typedef struct Outer_Inner_S_s"));
3589 assert!(h.contains("\"Outer::Inner::S\""));
3590 }
3591
3592 #[test]
3593 fn appendable_default_when_no_annotation() {
3594 let h = gen_c("struct V { long a; long b; };");
3598 assert!(h.contains(".extensibility = 1"));
3599 }
3600
3601 #[test]
3602 fn mutable_struct_marks_extensibility() {
3603 let h = gen_c("@mutable struct M { @id(1) long a; };");
3604 assert!(h.contains(".extensibility = 2"));
3605 }
3606
3607 #[test]
3608 fn key_member_sets_is_keyed_and_emits_key_hash() {
3609 let h = gen_c("@final struct Sensor { @key long id; double value; };");
3610 assert!(h.contains(".is_keyed = 1"));
3611 assert!(h.contains("Sensor_key_hash"));
3612 }
3613
3614 #[test]
3617 fn enum_member_no_longer_rejected() {
3618 let h = gen_c("enum Color { RED, GREEN, BLUE }; @final struct S { Color c; };");
3620 assert!(h.contains("typedef int32_t Color_t;"));
3621 assert!(h.contains("Color_GREEN = 1"));
3622 assert!(h.contains("Color_t c;"));
3624 assert!(h.contains("zerodds_xcdr2_c_write_i32(&w_buf, &w_len, &w_cap, (int32_t)(s->c))"));
3625 assert!(h.contains("zerodds_xcdr2_c_read_i32(buf, len, &pos, (int32_t*)&(s->c), zd_be)"));
3626 }
3627
3628 #[test]
3629 fn typedef_member_resolves_to_underlying() {
3630 let h = gen_c("typedef double Amps; @final struct S { Amps battery; };");
3631 assert!(h.contains("double battery;"));
3632 assert!(h.contains("zd_x2_write_f64(&w_buf, &w_len, &w_cap, s->battery)"));
3635 assert!(h.contains("static inline int zd_x2_write_f64"));
3636 }
3637
3638 #[test]
3639 fn nested_struct_member_inlined() {
3640 let h = gen_c(
3641 "@final struct Point { long x; long y; }; @final struct Line { Point a; Point b; };",
3642 );
3643 assert!(h.contains("Point_t a;"));
3644 assert!(h.contains("Point_t b;"));
3645 assert!(h.contains("(s->a).x"));
3647 assert!(h.contains("(s->b).y"));
3648 }
3649
3650 #[test]
3651 fn fixed_array_member_no_length_prefix() {
3652 let h = gen_c("@final struct G { long grid[3]; };");
3653 assert!(h.contains("int32_t grid[3];"));
3654 assert!(h.contains("ai0 = 0; ai0 < 3"));
3656 }
3657
3658 #[test]
3661 fn optional_member_gets_presence_flag() {
3662 let h = gen_c("@final struct O { @optional long maybe; };");
3663 assert!(h.contains("int32_t maybe;"));
3664 assert!(h.contains("uint8_t maybe_present;"));
3665 assert!(h.contains("s->maybe_present ? 1 : 0"));
3667 assert!(h.contains("if (s->maybe_present) {"));
3668 }
3669
3670 #[test]
3671 fn header_does_not_include_conflicting_zerodds_h() {
3672 let h = gen_c("@final struct S { long x; };");
3675 assert!(h.contains("#include \"zerodds_xcdr2.h\""));
3676 assert!(!h.contains("#include \"zerodds.h\""));
3677 }
3678
3679 #[test]
3682 fn union_emits_tagged_union_codec() {
3683 let h = gen_c("union U switch (long) { case 1: long a; default: long b; };");
3685 assert!(h.contains("typedef struct U_s"));
3686 assert!(h.contains("} _u;"));
3687 assert!(h.contains("U_typesupport"));
3688 assert!(h.contains("._d) {"));
3690 assert!(h.contains("case 1:"));
3691 assert!(h.contains("default:"));
3692 }
3693
3694 #[test]
3695 fn const_array_bound_resolves_to_literal() {
3696 let h = gen_c("const long N = 4; @final struct A { long v[N]; };");
3698 assert!(
3699 h.contains("int32_t v[4];"),
3700 "named const bound not folded:\n{h}"
3701 );
3702 }
3703
3704 #[test]
3705 fn map_member_emits_parallel_arrays_and_codec() {
3706 let h = gen_c("@final struct M { map<string, long> counters; };");
3707 assert!(h.contains("keys;"));
3708 assert!(h.contains("vals;"));
3709 assert!(h.contains("map_dheader_pos"));
3711 }
3712
3713 #[test]
3714 fn wstring_member_maps_to_uint16_ptr() {
3715 let h = gen_c("@final struct W { wstring label; };");
3716 assert!(h.contains("uint16_t* label;"));
3717 assert!(h.contains("ws_n * 2u"));
3719 }
3720
3721 #[test]
3722 fn sequence_of_struct_resolves_element_type() {
3723 let h = gen_c("@final struct P { long x; }; @final struct S { sequence<P> ps; };");
3724 assert!(h.contains("P_t* elems; } ps;"));
3725 assert!(h.contains(".elems[i0]).x") || h.contains(".elems[i0])"));
3727 }
3728
3729 #[test]
3730 fn typedef_to_aggregate_resolves_to_struct() {
3731 let h = gen_c(
3732 "@final struct Point { long x; }; typedef Point Position; \
3733 @final struct S { Position p; };",
3734 );
3735 assert!(h.contains("Point_t p;"));
3736 }
3737
3738 #[test]
3742 fn typedef_alias_chain_resolves_to_root() {
3743 let h = gen_c("typedef double A; typedef A B; @final struct S { B v; };");
3744 assert!(h.contains("double v;"), "alias chain not resolved:\n{h}");
3746 }
3747
3748 #[test]
3749 fn typedef_to_array_contributes_dims_at_use_site() {
3750 let h = gen_c("typedef long Matrix3[3][3]; @final struct S { Matrix3 m; };");
3751 assert!(
3752 h.contains("int32_t m[3][3];"),
3753 "typedef-to-array dims lost:\n{h}"
3754 );
3755 }
3756
3757 #[test]
3758 fn bitmask_maps_to_holder_uint_and_flag_constants() {
3759 let h = gen_c(
3760 "bitmask Permissions { READ, WRITE, EXECUTE }; @final struct S { Permissions p; };",
3761 );
3762 assert!(
3766 h.contains("typedef uint32_t Permissions_t;"),
3767 "holder uint:\n{h}"
3768 );
3769 assert!(
3770 h.contains("Permissions_WRITE = (1u << 1)"),
3771 "flag bit:\n{h}"
3772 );
3773 assert!(h.contains("Permissions_t p;"), "member type:\n{h}");
3774 assert!(h.contains("zerodds_xcdr2_c_write_u32(&w_buf, &w_len, &w_cap, s->p)"));
3776 }
3777
3778 #[test]
3779 fn bitset_maps_to_packed_holder_and_accessors() {
3780 let h = gen_c(
3781 "bitset Flags { bitfield<3> kind; bitfield<1> active; bitfield<4> priority; }; \
3782 @final struct S { Flags f; };",
3783 );
3784 assert!(
3786 h.contains("typedef uint8_t Flags_t;"),
3787 "packed holder:\n{h}"
3788 );
3789 assert!(h.contains("Flags_active_SHIFT = 3"), "field offset:\n{h}");
3790 assert!(
3791 h.contains("#define Flags_priority_MASK 0xFu"),
3792 "field mask:\n{h}"
3793 );
3794 assert!(h.contains("zerodds_xcdr2_c_write_u8(&w_buf, &w_len, &w_cap, s->f)"));
3795 }
3796
3797 #[test]
3798 fn recursive_type_through_sequence_splices_via_helper() {
3799 let h = gen_c("struct TreeNode { long value; sequence<TreeNode> children; };");
3800 assert!(
3802 h.contains("struct TreeNode_s* elems;"),
3803 "pointer-to-tag elem:\n{h}"
3804 );
3805 assert!(
3806 h.contains("static int TreeNode_write_body("),
3807 "write helper:\n{h}"
3808 );
3809 assert!(
3810 h.contains("static int TreeNode_read_body("),
3811 "read helper:\n{h}"
3812 );
3813 assert!(
3814 h.contains("TreeNode_write_body(&((s->children).elems[i0])"),
3815 "recursive splice call:\n{h}"
3816 );
3817 }
3818
3819 #[test]
3820 fn forward_declared_then_defined_struct_and_union_generate() {
3821 let h = gen_c(
3824 "module conf { \
3825 struct Node; union Variant; \
3826 struct Node { long value; sequence<Node> next; }; \
3827 union Variant switch (long) { case 0: long a; case 1: Node n; }; \
3828 };",
3829 );
3830 assert!(
3831 h.contains("typedef struct conf_Node_s"),
3832 "node typedef:\n{h}"
3833 );
3834 assert!(
3835 h.contains("typedef struct conf_Variant_s"),
3836 "variant typedef:\n{h}"
3837 );
3838 let ni = h
3840 .find("typedef struct conf_Node_s")
3841 .expect("Node typedef present");
3842 let vi = h
3843 .find("typedef struct conf_Variant_s")
3844 .expect("Variant typedef present");
3845 assert!(ni < vi, "Node typedef must precede Variant typedef");
3846 }
3847
3848 #[test]
3849 fn direct_by_value_self_membership_is_rejected() {
3850 let ast = zerodds_idl::parse("struct Node { long v; Node n; };", &ParserConfig::default());
3852 if let Ok(ast) = ast {
3853 assert!(
3854 generate_c_header(&ast, &CGenOptions::default()).is_err(),
3855 "infinite by-value self-membership must be rejected"
3856 );
3857 }
3858 }
3859
3860 #[test]
3861 fn fixed_decimal_is_a_bcd_byte_field() {
3862 let ast = zerodds_idl::parse(
3865 "@final struct S { fixed<5,2> price; };",
3866 &ParserConfig::default(),
3867 )
3868 .expect("parse");
3869 let c = generate_c_header(&ast, &CGenOptions::default()).expect("gen");
3870 assert!(
3871 c.contains("uint8_t bcd[3]"),
3872 "fixed<5,2> -> 3-octet BCD field:\n{c}"
3873 );
3874 assert!(
3875 c.contains("zerodds_xcdr2_c_write_u8") && c.contains("zerodds_xcdr2_c_read_u8"),
3876 "fixed must emit a raw BCD write/read loop"
3877 );
3878 }
3879
3880 #[test]
3881 fn any_remains_out_of_scope() {
3882 let ast = zerodds_idl::parse("@final struct S { any value; };", &ParserConfig::default())
3884 .expect("parse");
3885 assert!(generate_c_header(&ast, &CGenOptions::default()).is_err());
3886 }
3887}