Skip to main content

zerodds_idl_cpp/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! Fehler-Typen fuer den IDL→C++-Codegen.
4
5use core::fmt;
6
7/// Top-Level-Fehler des C++-Code-Generators.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum CppGenError {
10    /// IDL-Konstrukt ist im aktuellen Foundation-Scope (C5.1-a) nicht
11    /// unterstuetzt. `construct` ist eine kurze Bezeichnung (z.B.
12    /// `"interface"`, `"valuetype"`, `"fixed"`, `"any"`, `"map"`).
13    UnsupportedConstruct {
14        /// Name des nicht-unterstuetzten Konstrukts.
15        construct: String,
16        /// Optional: Identifier-Name (Type-Name oder Member-Name).
17        context: Option<String>,
18    },
19    /// Identifier kollidiert mit einem reservierten C++-Keyword
20    /// (§7.4.5 Implementation-Mapping verlangt Kollisionsvermeidung).
21    InvalidName {
22        /// Der unzulaessige Identifier.
23        name: String,
24        /// Grund der Ablehnung (z.B. `"reserved C++ keyword"`).
25        reason: String,
26    },
27    /// Inheritance-Cycle im Struct-Graphen (Self-Reference oder
28    /// indirekte Schleife). Wird vor der Emission erkannt.
29    InheritanceCycle {
30        /// Beteiligter Type-Name am Cycle.
31        type_name: String,
32    },
33    /// Generierter Output ist intern inkonsistent (sollte nicht
34    /// auftreten — Bug-Indikator).
35    Internal(String),
36}
37
38impl fmt::Display for CppGenError {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            Self::UnsupportedConstruct { construct, context } => match context {
42                Some(ctx) => write!(
43                    f,
44                    "unsupported IDL construct '{construct}' in '{ctx}' (C5.1-a Foundation scope)",
45                ),
46                None => write!(
47                    f,
48                    "unsupported IDL construct '{construct}' (C5.1-a Foundation scope)",
49                ),
50            },
51            Self::InvalidName { name, reason } => {
52                write!(f, "invalid identifier '{name}': {reason}")
53            }
54            Self::InheritanceCycle { type_name } => {
55                write!(f, "inheritance cycle detected at type '{type_name}'")
56            }
57            Self::Internal(msg) => write!(f, "internal codegen error: {msg}"),
58        }
59    }
60}
61
62impl std::error::Error for CppGenError {}
63
64#[cfg(test)]
65mod tests {
66    #![allow(clippy::expect_used, clippy::panic)]
67    use super::*;
68
69    #[test]
70    fn unsupported_display_has_context() {
71        let e = CppGenError::UnsupportedConstruct {
72            construct: "interface".into(),
73            context: Some("Foo".into()),
74        };
75        let s = format!("{e}");
76        assert!(s.contains("interface"));
77        assert!(s.contains("Foo"));
78    }
79
80    #[test]
81    fn unsupported_display_without_context() {
82        let e = CppGenError::UnsupportedConstruct {
83            construct: "any".into(),
84            context: None,
85        };
86        let s = format!("{e}");
87        assert!(s.contains("any"));
88    }
89
90    #[test]
91    fn invalid_name_display() {
92        let e = CppGenError::InvalidName {
93            name: "class".into(),
94            reason: "reserved C++ keyword".into(),
95        };
96        assert!(format!("{e}").contains("reserved"));
97    }
98
99    #[test]
100    fn inheritance_cycle_display() {
101        let e = CppGenError::InheritanceCycle {
102            type_name: "Loop".into(),
103        };
104        assert!(format!("{e}").contains("Loop"));
105    }
106
107    #[test]
108    fn internal_display() {
109        let e = CppGenError::Internal("oops".into());
110        assert!(format!("{e}").contains("oops"));
111    }
112}