Skip to main content

zerodds_rtps/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! RTPS-Wire-Format-Fehler.
4
5use core::fmt;
6
7/// Fehler beim Encodieren oder Decodieren von RTPS-Wire-Daten.
8#[derive(Debug, Clone, PartialEq, Eq)]
9#[non_exhaustive]
10pub enum WireError {
11    /// Buffer ist zu klein fuer den Schreib-Vorgang.
12    WriteOverflow {
13        /// Wieviele Bytes gebraucht worden waeren.
14        needed: usize,
15        /// Wieviele tatsaechlich verfuegbar waren.
16        available: usize,
17    },
18    /// Eingabe endete vor dem erwarteten Ende.
19    UnexpectedEof {
20        /// Wieviele Bytes noch erwartet wurden.
21        needed: usize,
22        /// Position im Stream.
23        offset: usize,
24    },
25    /// Magic-Bytes des RTPS-Headers stimmen nicht ("RTPS").
26    InvalidMagic {
27        /// Tatsaechlich gelesene 4 Bytes.
28        found: [u8; 4],
29    },
30    /// Submessage-ID ist nicht im supported-Set.
31    UnknownSubmessageId {
32        /// Roher Submessage-ID-Byte.
33        id: u8,
34    },
35    /// Locator-Kind hat unerwarteten Wert.
36    InvalidLocatorKind {
37        /// Roher i32-Wert.
38        kind: i32,
39    },
40    /// Numerischer Wert ueberschreitet das Wire-Feld.
41    ValueOutOfRange {
42        /// Beschreibung.
43        message: &'static str,
44    },
45    /// Encapsulation-Kind im CDR-Header wird nicht unterstuetzt
46    /// (z.B. PL_CDR2, CDR_LE bei erwartetem PL_CDR).
47    UnsupportedEncapsulation {
48        /// Die beiden Encapsulation-Bytes `[kind_hi, kind_lo]`.
49        kind: [u8; 2],
50    },
51    /// Spec-konformes Wire-Feature, das in dieser Phase (noch) nicht
52    /// unterstuetzt wird (z.B. Inline-QoS in DATA_FRAG).
53    UnsupportedFeature {
54        /// Name/Kurzbeschreibung des Features.
55        what: &'static str,
56    },
57}
58
59impl fmt::Display for WireError {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match self {
62            Self::WriteOverflow { needed, available } => {
63                write!(
64                    f,
65                    "RTPS write overflow: needed {needed}, available {available}"
66                )
67            }
68            Self::UnexpectedEof { needed, offset } => {
69                write!(f, "RTPS unexpected EOF: needed {needed} at offset {offset}")
70            }
71            Self::InvalidMagic { found } => {
72                write!(f, "RTPS invalid magic: expected b\"RTPS\", got {found:?}")
73            }
74            Self::UnknownSubmessageId { id } => {
75                write!(f, "RTPS unknown submessage id 0x{id:02x}")
76            }
77            Self::InvalidLocatorKind { kind } => {
78                write!(f, "RTPS invalid locator kind {kind}")
79            }
80            Self::ValueOutOfRange { message } => write!(f, "RTPS value out of range: {message}"),
81            Self::UnsupportedEncapsulation { kind } => {
82                write!(
83                    f,
84                    "RTPS unsupported encapsulation kind 0x{:02x}{:02x}",
85                    kind[0], kind[1]
86                )
87            }
88            Self::UnsupportedFeature { what } => {
89                write!(f, "RTPS unsupported feature: {what}")
90            }
91        }
92    }
93}
94
95#[cfg(feature = "std")]
96impl std::error::Error for WireError {}
97
98#[cfg(test)]
99mod tests {
100    #![allow(clippy::expect_used)]
101    use super::*;
102
103    #[cfg(feature = "alloc")]
104    extern crate alloc;
105    #[cfg(feature = "alloc")]
106    use alloc::format;
107
108    #[cfg(feature = "alloc")]
109    #[test]
110    fn write_overflow_display() {
111        let e = WireError::WriteOverflow {
112            needed: 16,
113            available: 4,
114        };
115        let s = format!("{e}");
116        assert!(s.contains("16"));
117        assert!(s.contains("4"));
118    }
119
120    #[cfg(feature = "alloc")]
121    #[test]
122    fn invalid_magic_display() {
123        let e = WireError::InvalidMagic {
124            found: [b'X', b'X', b'X', b'X'],
125        };
126        let s = format!("{e}");
127        assert!(s.contains("RTPS"));
128    }
129
130    #[cfg(feature = "alloc")]
131    #[test]
132    fn unknown_submessage_id_display_uses_hex() {
133        let e = WireError::UnknownSubmessageId { id: 0x42 };
134        let s = format!("{e}");
135        assert!(s.contains("42"));
136    }
137
138    #[cfg(feature = "alloc")]
139    #[test]
140    fn invalid_locator_kind_display() {
141        let e = WireError::InvalidLocatorKind { kind: 99 };
142        assert!(format!("{e}").contains("99"));
143    }
144
145    #[cfg(feature = "alloc")]
146    #[test]
147    fn value_out_of_range_display() {
148        let e = WireError::ValueOutOfRange { message: "too big" };
149        assert!(format!("{e}").contains("too big"));
150    }
151
152    #[cfg(feature = "alloc")]
153    #[test]
154    fn unexpected_eof_display() {
155        let e = WireError::UnexpectedEof {
156            needed: 8,
157            offset: 12,
158        };
159        let s = format!("{e}");
160        assert!(s.contains("8"));
161        assert!(s.contains("12"));
162    }
163}