zerodds-corba-rust 1.0.0-rc.1

IDL → Rust code generator for CORBA service constructs (interfaces, valuetypes, components, homes) — analogous to zerodds-idl-cpp/-csharp/-java but for Rust output.
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 ZeroDDS Contributors
//! Top-Level-Emitter: AST → CORBA-Rust-Code.

use std::collections::HashMap;

use zerodds_idl::ast::types::{Definition, InterfaceDef, Specification};

use crate::error::Result;

/// Registry aller Interface-Definitionen indiziert nach Simple-Namen.
/// Wird vor dem eigentlichen Emit aufgebaut, damit Stubs `impl Base for
/// DerivedStub`-Bloecke fuer alle transitiven Basen emittieren koennen.
pub(crate) type InterfaceRegistry<'a> = HashMap<String, &'a InterfaceDef>;

/// Optionen fuer den CORBA-Codegen.
#[derive(Debug, Clone, Default)]
pub struct CorbaRustGenOptions {
    /// Header-Kommentar oben in der erzeugten Datei. Wird verbatim
    /// uebernommen.
    pub header_comment: Option<String>,
}

/// Erzeugt aus einer geparsten IDL-Spec ein einzelnes Rust-Modul-File
/// mit CORBA-Service-Konstrukten (Interface-Stubs/Skeletons +
/// Valuetypes).
///
/// # Errors
/// `Unsupported` fuer IDL-Konstrukte ausserhalb des Service-Scopes.
pub fn generate_corba_rust_module(
    spec: &Specification,
    opts: &CorbaRustGenOptions,
) -> Result<String> {
    let mut out = String::new();
    out.push_str("// SPDX-License-Identifier: Apache-2.0\n");
    if let Some(c) = &opts.header_comment {
        for line in c.lines() {
            out.push_str("// ");
            out.push_str(line);
            out.push('\n');
        }
    }
    out.push_str("// Auto-generated by `zerodds-corba-rust`. Do not edit by hand.\n\n");
    out.push_str("#![allow(clippy::too_many_lines)]\n");
    out.push_str("#![allow(unused_imports, unused_variables)]\n\n");

    let mut registry: InterfaceRegistry<'_> = HashMap::new();
    collect_interfaces(spec, &mut registry);

    for def in &spec.definitions {
        emit_definition(&mut out, def, &registry)?;
    }
    Ok(out)
}

/// zerodds-lint: recursion-depth 16
fn collect_interfaces<'a>(spec: &'a Specification, reg: &mut InterfaceRegistry<'a>) {
    for def in &spec.definitions {
        collect_from_def(def, reg);
    }
}

/// zerodds-lint: recursion-depth 16
fn collect_from_def<'a>(def: &'a Definition, reg: &mut InterfaceRegistry<'a>) {
    use zerodds_idl::ast::types::InterfaceDcl;
    match def {
        Definition::Interface(InterfaceDcl::Def(d)) => {
            reg.insert(d.name.text.clone(), d);
        }
        Definition::Module(m) => {
            for inner in &m.definitions {
                collect_from_def(inner, reg);
            }
        }
        _ => {}
    }
}

/// zerodds-lint: recursion-depth 16
/// IDL-Modul-Schachtelung — 16 Ebenen reichen fuer alle bekannten
/// OMG-Spec-IDL-Files.
fn emit_definition(
    out: &mut String,
    def: &Definition,
    registry: &InterfaceRegistry<'_>,
) -> Result<()> {
    match def {
        Definition::Module(m) => emit_module(out, m, registry)?,
        Definition::Interface(i_dcl) => {
            use zerodds_idl::ast::types::InterfaceDcl;
            match i_dcl {
                InterfaceDcl::Def(def) => {
                    crate::interface_emit::emit_interface(out, def, registry)?;
                    out.push('\n');
                }
                InterfaceDcl::Forward(_) => {}
            }
        }
        Definition::ValueDef(v) => {
            crate::valuetype_emit::emit_valuetype(out, v)?;
            out.push('\n');
        }
        Definition::Component(c) => {
            crate::component_emit::emit_component(out, c)?;
            out.push('\n');
        }
        Definition::Home(h) => {
            crate::component_emit::emit_home(out, h)?;
            out.push('\n');
        }
        // ValueBox/ValueForward: Phase-2.
        // Type/Const/Except sind im idl-rust-DataType-Pfad.
        _ => {}
    }
    Ok(())
}

/// zerodds-lint: recursion-depth 16
fn emit_module(
    out: &mut String,
    m: &zerodds_idl::ast::types::ModuleDef,
    registry: &InterfaceRegistry<'_>,
) -> Result<()> {
    out.push_str("pub mod ");
    out.push_str(&m.name.text);
    out.push_str(" {\n");
    for inner in &m.definitions {
        let mut inner_out = String::new();
        emit_definition(&mut inner_out, inner, registry)?;
        for line in inner_out.lines() {
            if line.is_empty() {
                out.push('\n');
            } else {
                out.push_str("    ");
                out.push_str(line);
                out.push('\n');
            }
        }
    }
    out.push_str("}\n\n");
    Ok(())
}