Skip to main content

zerodds_corba_codegen/
stub.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! Stub code-generation helper โ€” spec Annex-A.1 operation mapping.
5//!
6//! A **stub** is the client-side proxy that marshals an IDL operation
7//! into a GIOP request, sends it over IIOP, and demarshals the reply.
8//! We provide a language-agnostic data structure that the codegen
9//! processes per target language.
10
11use alloc::string::String;
12use alloc::vec::Vec;
13
14use crate::special_types::TargetLanguage;
15
16/// Parameter direction.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum ParamDirection {
19    /// `in`.
20    In,
21    /// `out`.
22    Out,
23    /// `inout`.
24    InOut,
25}
26
27/// Operation parameter.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct StubParam {
30    /// IDL name.
31    pub name: String,
32    /// IDL type spec (caller representation).
33    pub type_spec: String,
34    /// Direction.
35    pub direction: ParamDirection,
36}
37
38/// Operation definition for stub generation.
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub struct StubOp {
41    /// Operation name.
42    pub name: String,
43    /// Return-type spec (`void` if none).
44    pub return_type: String,
45    /// Parameters.
46    pub params: Vec<StubParam>,
47    /// `oneway` (spec ยง7.4.16) โ€” no reply expected.
48    pub oneway: bool,
49}
50
51/// Renders a textual stub-skeleton preamble with the concrete
52/// language names. This is a **helper** for tests and documentation;
53/// the real codegen happens in `crates/idl-cpp/` etc., which consumes
54/// this data structure.
55#[must_use]
56pub fn render_stub_op(op: &StubOp, lang: TargetLanguage) -> String {
57    let lang_label = match lang {
58        TargetLanguage::Cpp => "C++",
59        TargetLanguage::CSharp => "C#",
60        TargetLanguage::Java => "Java",
61        TargetLanguage::Rust => "Rust",
62    };
63    let oneway_marker = if op.oneway { "[oneway]" } else { "" };
64    let mut s = alloc::format!("// {lang_label} stub for {oneway_marker}{}", op.name);
65    s.push_str(&alloc::format!("\n//   return: {}", op.return_type));
66    for p in &op.params {
67        let dir = match p.direction {
68            ParamDirection::In => "in",
69            ParamDirection::Out => "out",
70            ParamDirection::InOut => "inout",
71        };
72        s.push_str(&alloc::format!("\n//   {dir} {} {}", p.type_spec, p.name));
73    }
74    s
75}
76
77#[cfg(test)]
78#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
79mod tests {
80    use super::*;
81
82    fn echo_op() -> StubOp {
83        StubOp {
84            name: "echo".into(),
85            return_type: "string".into(),
86            params: alloc::vec![StubParam {
87                name: "msg".into(),
88                type_spec: "string".into(),
89                direction: ParamDirection::In,
90            }],
91            oneway: false,
92        }
93    }
94
95    #[test]
96    fn render_stub_lists_params_per_language() {
97        let s = render_stub_op(&echo_op(), TargetLanguage::Cpp);
98        assert!(s.contains("C++ stub"));
99        assert!(s.contains("in string msg"));
100    }
101
102    #[test]
103    fn oneway_marker_present_for_oneway_ops() {
104        let mut op = echo_op();
105        op.oneway = true;
106        op.return_type = "void".into();
107        let s = render_stub_op(&op, TargetLanguage::Java);
108        assert!(s.contains("[oneway]"));
109    }
110
111    #[test]
112    fn out_and_inout_params_render() {
113        let op = StubOp {
114            name: "swap".into(),
115            return_type: "void".into(),
116            params: alloc::vec![
117                StubParam {
118                    name: "a".into(),
119                    type_spec: "long".into(),
120                    direction: ParamDirection::InOut,
121                },
122                StubParam {
123                    name: "b".into(),
124                    type_spec: "long".into(),
125                    direction: ParamDirection::Out,
126                },
127            ],
128            oneway: false,
129        };
130        let s = render_stub_op(&op, TargetLanguage::CSharp);
131        assert!(s.contains("inout long a"));
132        assert!(s.contains("out long b"));
133    }
134}