zerodds-idl-rust 1.0.0-rc.1

IDL4 โ†’ Rust code generator for ZeroDDS DataTypes (impl DdsType from zerodds-dcps).
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 ZeroDDS Contributors
//! Emittiert IDL `union` โ†’ Rust `enum` mit Discriminator.
//!
//! XTypes 1.3 ยง7.4.1.4.5 Union-Wire-Format:
//!
//! ```text
//! discriminator-value : <switch-type>
//! variant-body         : <case-type>
//! ```
//!
//! Rust-Mapping: tagged enum mit `repr` der Switch-Type. Variants
//! tragen die jeweilige Case-Body-Struct.

use zerodds_idl::ast::types::{Case, SwitchTypeSpec, UnionDef};

use crate::error::{Result, RustGenError};
use crate::type_map::escape_keyword;
use crate::type_map::rust_type_for;

/// Emittiert eine Rust-Enum-Repraesentation einer IDL-Union.
pub fn emit_union(out: &mut String, u: &UnionDef) -> Result<()> {
    out.push_str("/// Generated by `zerodds-idl-rust` from IDL union.\n");
    out.push_str("#[derive(Debug, Clone, PartialEq)]\n");
    out.push_str("pub enum ");
    out.push_str(&escape_keyword(&u.name.text));
    out.push_str(" {\n");
    for case in &u.cases {
        emit_case_variant(out, case)?;
    }
    out.push_str("}\n\n");

    // Default-Impl: erste Variante
    if let Some(first) = u.cases.first() {
        let variant_name = &first.element.declarator.name().text;
        out.push_str("impl Default for ");
        out.push_str(&escape_keyword(&u.name.text));
        out.push_str(" {\n");
        out.push_str("    fn default() -> Self {\n");
        // Default-Wert der ersten Variante
        let elem_type = rust_type_for(&first.element.type_spec)?;
        out.push_str(&format!(
            "        Self::{} (<{}>::default())\n",
            capitalize(variant_name),
            elem_type
        ));
        out.push_str("    }\n");
        out.push_str("}\n\n");
    }

    let _ = &u.switch_type; // Phase E+: Discriminator-encoding folgt
    Ok(())
}

fn emit_case_variant(out: &mut String, case: &Case) -> Result<()> {
    let variant_name = case.element.declarator.name();
    let elem_type = rust_type_for(&case.element.type_spec)?;
    out.push_str("    ");
    out.push_str(&capitalize(&variant_name.text));
    out.push('(');
    out.push_str(&elem_type);
    out.push_str("),\n");
    Ok(())
}

fn capitalize(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(first) => first.to_uppercase().chain(c).collect(),
    }
}

#[allow(dead_code)]
fn switch_repr(spec: &SwitchTypeSpec) -> Result<&'static str> {
    use zerodds_idl::ast::types::IntegerType;
    match spec {
        SwitchTypeSpec::Integer(IntegerType::Int8) => Ok("i8"),
        SwitchTypeSpec::Integer(IntegerType::UInt8) => Ok("u8"),
        SwitchTypeSpec::Integer(IntegerType::Short | IntegerType::Int16) => Ok("i16"),
        SwitchTypeSpec::Integer(IntegerType::UShort | IntegerType::UInt16) => Ok("u16"),
        SwitchTypeSpec::Integer(IntegerType::Long | IntegerType::Int32) => Ok("i32"),
        SwitchTypeSpec::Integer(IntegerType::ULong | IntegerType::UInt32) => Ok("u32"),
        SwitchTypeSpec::Integer(IntegerType::LongLong | IntegerType::Int64) => Ok("i64"),
        SwitchTypeSpec::Integer(IntegerType::ULongLong | IntegerType::UInt64) => Ok("u64"),
        SwitchTypeSpec::Char | SwitchTypeSpec::Octet => Ok("u8"),
        SwitchTypeSpec::Boolean => Ok("u8"),
        SwitchTypeSpec::Scoped(_) => Err(RustGenError::Unsupported {
            what: "union discriminator scoped",
            at: 0,
        }),
    }
}