use zerodds_idl::ast::types::{
ConstrTypeDecl, Declarator, Definition, ExceptDecl, ModuleDef, Specification, TypeDecl,
};
use crate::error::Result;
use crate::struct_emit::emit_struct;
use crate::type_map::{escape_keyword, rust_type_for};
#[derive(Debug, Clone, Default)]
pub struct RustGenOptions {
pub header_comment: Option<String>,
}
pub fn generate_rust_module(spec: &Specification, opts: &RustGenOptions) -> 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-idl-rust`. Do not edit by hand.\n");
out.push('\n');
out.push_str("#![allow(clippy::too_many_lines)]\n");
out.push_str("#![allow(unused_imports)]\n");
out.push('\n');
out.push_str("use zerodds_cdr::{BufferReader, BufferWriter, CdrDecode, CdrEncode, DecodeError, EncodeError, Endianness};\n");
out.push('\n');
let mut path: Vec<String> = Vec::new();
for def in &spec.definitions {
emit_definition(&mut out, def, &mut path)?;
}
Ok(out)
}
fn emit_definition(out: &mut String, def: &Definition, path: &mut Vec<String>) -> Result<()> {
match def {
Definition::Module(m) => emit_module(out, m, path),
Definition::Type(t) => emit_type_decl(out, t, path),
Definition::Except(e) => {
emit_exception(out, e)?;
out.push('\n');
Ok(())
}
Definition::Const(_) => Ok(()),
_ => Ok(()),
}
}
fn emit_module(out: &mut String, m: &ModuleDef, path: &mut Vec<String>) -> Result<()> {
out.push_str("pub mod ");
out.push_str(&escape_keyword(&m.name.text));
out.push_str(" {\n");
out.push_str(" use zerodds_cdr::{BufferReader, BufferWriter, CdrDecode, CdrEncode, DecodeError, EncodeError, Endianness};\n\n");
path.push(m.name.text.clone());
for inner in &m.definitions {
let mut inner_out = String::new();
emit_definition(&mut inner_out, inner, path)?;
for line in inner_out.lines() {
if line.is_empty() {
out.push('\n');
} else {
out.push_str(" ");
out.push_str(line);
out.push('\n');
}
}
}
path.pop();
out.push_str("}\n\n");
Ok(())
}
fn emit_type_decl(out: &mut String, td: &TypeDecl, path: &[String]) -> Result<()> {
match td {
TypeDecl::Constr(ConstrTypeDecl::Struct(struct_dcl)) => {
use zerodds_idl::ast::types::StructDcl;
match struct_dcl {
StructDcl::Def(s) => {
emit_struct(out, s, path)?;
out.push('\n');
}
StructDcl::Forward(_) => {
}
}
}
TypeDecl::Constr(ConstrTypeDecl::Enum(e)) => {
crate::enum_emit::emit_enum(out, e)?;
out.push('\n');
}
TypeDecl::Constr(ConstrTypeDecl::Union(u)) => {
use zerodds_idl::ast::types::UnionDcl;
match u {
UnionDcl::Def(def) => {
crate::union_emit::emit_union(out, def)?;
out.push('\n');
}
UnionDcl::Forward(_) => {}
}
}
TypeDecl::Typedef(td) => {
crate::typedef_emit::emit_typedef(out, td)?;
}
TypeDecl::Constr(ConstrTypeDecl::Bitset(b)) => {
crate::bitset_emit::emit_bitset(out, b)?;
out.push('\n');
}
TypeDecl::Constr(ConstrTypeDecl::Bitmask(m)) => {
crate::bitset_emit::emit_bitmask(out, m)?;
out.push('\n');
}
}
Ok(())
}
fn emit_exception(out: &mut String, e: &ExceptDecl) -> Result<()> {
out.push_str("/// Generated by `zerodds-idl-rust` from IDL exception (CORBA 3.3 §7.4.10).\n");
out.push_str("#[derive(Debug, Clone, PartialEq, Default)]\n");
out.push_str("pub struct ");
out.push_str(&escape_keyword(&e.name.text));
out.push_str(" {\n");
for member in &e.members {
let rust_ty = rust_type_for(&member.type_spec)?;
for declarator in &member.declarators {
let raw = match declarator {
Declarator::Simple(n) => &n.text,
Declarator::Array(a) => &a.name.text,
};
let name = escape_keyword(raw);
out.push_str(&format!(" pub {name}: {rust_ty},\n"));
}
}
out.push_str("}\n");
Ok(())
}