Skip to main content

zerodds_ami4ccm/
exception_holder.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! `CCM_AMI::ExceptionHolder` Modell — Spec §7.4.1.
5//!
6//! Spec-IDL (Annex A — `ami4ccm.idl`):
7//! ```idl
8//! module CCM_AMI {
9//!     native UserExceptionBase;
10//!     local interface ExceptionHolder {
11//!         void raise_exception() raises (UserExceptionBase);
12//!     };
13//! };
14//! ```
15
16use alloc::string::String;
17use alloc::vec::Vec;
18
19/// `CCM_AMI::UserExceptionBase` (Spec §7.4.1, S. 9).
20///
21/// Spec-Zitat: "Language mapping of this native type should allow any
22/// user exception to be raised from this method. For instance, it is
23/// mapped to CORBA::UserException in C++ and to org.omg.CORBA.
24/// UserException in java."
25///
26/// In ZeroDDS modellieren wir die `native`-Form als (Repository-ID,
27/// marshaled-Bytes)-Paar. Das ist ausreichend, um eine User-Exception
28/// von Server-Side serialisiert und im Client wieder rekonstruiert zu
29/// erhalten — Sprach-Mapping (CORBA::UserException, java.lang.Throwable,
30/// etc.) erfolgt beim Codegen.
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct UserExceptionBase {
33    /// CORBA Repository-ID der originalen Exception
34    /// (z.B. `IDL:Stock/InvalidStock:1.0`).
35    pub repository_id: String,
36    /// CDR-marshaled Member-State der Exception.
37    pub marshaled_exception: Vec<u8>,
38}
39
40impl UserExceptionBase {
41    /// Konstruiert eine `UserExceptionBase` aus Repository-ID + Bytes.
42    #[must_use]
43    pub fn new(repository_id: impl Into<String>, marshaled_exception: Vec<u8>) -> Self {
44        Self {
45            repository_id: repository_id.into(),
46            marshaled_exception,
47        }
48    }
49}
50
51/// `CCM_AMI::ExceptionHolder`-Instanz (Spec §7.4.1, S. 9).
52///
53/// Spec-Zitat: "The CCM_AMI::ExceptionHolder interface encapsulates the
54/// exception data and enough information to turn that data back into a
55/// raised exception."
56///
57/// Operation `raise_exception()` (Spec §7.4.1) rekonstruiert die
58/// Exception aus dem Holder. In ZeroDDS modellieren wir das als
59/// `Result<(), UserExceptionBase>` — `Err(...)` ist der "raise"-Pfad.
60#[derive(Debug, Clone, PartialEq, Eq)]
61pub struct ExceptionHolder {
62    inner: UserExceptionBase,
63}
64
65impl ExceptionHolder {
66    /// Konstruiert `ExceptionHolder` aus `UserExceptionBase`.
67    #[must_use]
68    pub fn new(exception: UserExceptionBase) -> Self {
69        Self { inner: exception }
70    }
71
72    /// Spec §7.4.1 — `raise_exception()`. Liefert die enthaltene
73    /// Exception als `Err`-Variante. Da Exceptions nicht auf
74    /// `core::error::Error`-Trait gemappt werden (das ist Sprach-spezifisch),
75    /// ist der Rueckgabe-Typ `Err(UserExceptionBase)`.
76    ///
77    /// # Errors
78    /// Diese Operation gibt **immer** `Err` zurueck — der Holder
79    /// existiert genau, um eine Exception zu transportieren. Der `Ok(())`-
80    /// Pfad ist nur formal, um den Spec-Signature-Style abzubilden.
81    pub fn raise_exception(&self) -> Result<(), UserExceptionBase> {
82        Err(self.inner.clone())
83    }
84
85    /// Read-Only-Zugriff auf die enthaltene Exception (z.B. fuer
86    /// Diagnostik, ohne sie zu "raisen").
87    #[must_use]
88    pub const fn user_exception(&self) -> &UserExceptionBase {
89        &self.inner
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn user_exception_base_new_stores_id_and_bytes() {
99        let ub = UserExceptionBase::new("IDL:Stock/InvalidStock:1.0", alloc::vec![0xDE, 0xAD]);
100        assert_eq!(ub.repository_id, "IDL:Stock/InvalidStock:1.0");
101        assert_eq!(ub.marshaled_exception, alloc::vec![0xDE, 0xAD]);
102    }
103
104    #[test]
105    fn raise_exception_returns_err_with_user_exception() {
106        // Spec §7.4.1 — raise_exception() raises UserExceptionBase.
107        let ub = UserExceptionBase::new("IDL:Foo:1.0", alloc::vec![1, 2, 3]);
108        let holder = ExceptionHolder::new(ub.clone());
109        let result = holder.raise_exception();
110        assert_eq!(result, Err(ub));
111    }
112
113    #[test]
114    fn user_exception_accessor_returns_inner() {
115        let ub = UserExceptionBase::new("IDL:Bar:1.0", alloc::vec![]);
116        let holder = ExceptionHolder::new(ub.clone());
117        assert_eq!(holder.user_exception(), &ub);
118    }
119}