Skip to main content

zerodds_xrce/
object_kind.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! XRCE-Object-Kinds (Spec §7.2 Table 4).
5//!
6//! Jede Object-Variante hat einen 4-Bit-Code, den die niedrigeren 4 Bits
7//! der `ObjectId` tragen (siehe `crate::object_id`). Die hier gewaehlten
8//! Konstanten entsprechen den `OBJK_*`-Werten der DDS-XRCE-Spec
9//! `formal/2020-11-01`.
10//!
11//! Wir vergeben fuer jeden Spec-Wert einen `pub const u8`, plus eine
12//! Convenience-Enum mit `from_u8` / `to_u8`. Die Enum bricht
13//! `match`-Exhaustiveness in eigenem Code, der Wire-Round-Trip nutzt
14//! aber den `u8`-Repraesentanten direkt.
15
16use crate::error::XrceError;
17
18/// Reservierte Object-Kind: kein gueltiges Objekt (Spec §7.2.1).
19pub const OBJK_INVALID: u8 = 0x00;
20/// `OBJK_PARTICIPANT` — DomainParticipant.
21pub const OBJK_PARTICIPANT: u8 = 0x01;
22/// `OBJK_TOPIC` — Topic-Definition.
23pub const OBJK_TOPIC: u8 = 0x02;
24/// `OBJK_PUBLISHER` — Publisher.
25pub const OBJK_PUBLISHER: u8 = 0x03;
26/// `OBJK_SUBSCRIBER` — Subscriber.
27pub const OBJK_SUBSCRIBER: u8 = 0x04;
28/// `OBJK_DATAWRITER` — DataWriter.
29pub const OBJK_DATAWRITER: u8 = 0x05;
30/// `OBJK_DATAREADER` — DataReader.
31pub const OBJK_DATAREADER: u8 = 0x06;
32/// `OBJK_TYPE` — Type-Description (Spec §7.5.2).
33pub const OBJK_TYPE: u8 = 0x0A;
34/// `OBJK_QOSPROFILE` — QoS-Profile (Spec §7.5.2).
35pub const OBJK_QOSPROFILE: u8 = 0x0B;
36/// `OBJK_APPLICATION` — Application-Container (Spec §7.5.2).
37pub const OBJK_APPLICATION: u8 = 0x0C;
38/// `OBJK_AGENT` — Agent-Singleton (Spec §7.5.2.1).
39pub const OBJK_AGENT: u8 = 0x0D;
40/// `OBJK_CLIENT` — Client-Object, repraesentiert den ProxyClient (§7.5.1).
41pub const OBJK_CLIENT: u8 = 0x0E;
42/// `OBJK_DOMAIN` — Domain-Kind (Spec §7.5.2).
43pub const OBJK_DOMAIN: u8 = 0x0F;
44
45/// Convenience-Enum aller in der Spec definierten Object-Kinds.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47#[repr(u8)]
48#[allow(missing_docs)]
49pub enum ObjectKind {
50    Invalid = OBJK_INVALID,
51    Participant = OBJK_PARTICIPANT,
52    Topic = OBJK_TOPIC,
53    Publisher = OBJK_PUBLISHER,
54    Subscriber = OBJK_SUBSCRIBER,
55    DataWriter = OBJK_DATAWRITER,
56    DataReader = OBJK_DATAREADER,
57    Type = OBJK_TYPE,
58    QosProfile = OBJK_QOSPROFILE,
59    Application = OBJK_APPLICATION,
60    Agent = OBJK_AGENT,
61    Client = OBJK_CLIENT,
62    Domain = OBJK_DOMAIN,
63}
64
65impl ObjectKind {
66    /// Roher 4-Bit-Code als `u8`.
67    #[must_use]
68    pub fn to_u8(self) -> u8 {
69        self as u8
70    }
71
72    /// Konvertiert ein 4-Bit-Wert. Werte ausserhalb der Spec → Fehler.
73    ///
74    /// # Errors
75    /// `ValueOutOfRange`, wenn `byte` keinem `OBJK_*` entspricht. Werte
76    /// `> 0x0F` werden ebenfalls abgelehnt — die ObjectId-Bit-Layer
77    /// stellt das normalerweise sicher.
78    pub fn from_u8(byte: u8) -> Result<Self, XrceError> {
79        match byte {
80            OBJK_INVALID => Ok(Self::Invalid),
81            OBJK_PARTICIPANT => Ok(Self::Participant),
82            OBJK_TOPIC => Ok(Self::Topic),
83            OBJK_PUBLISHER => Ok(Self::Publisher),
84            OBJK_SUBSCRIBER => Ok(Self::Subscriber),
85            OBJK_DATAWRITER => Ok(Self::DataWriter),
86            OBJK_DATAREADER => Ok(Self::DataReader),
87            OBJK_TYPE => Ok(Self::Type),
88            OBJK_QOSPROFILE => Ok(Self::QosProfile),
89            OBJK_APPLICATION => Ok(Self::Application),
90            OBJK_AGENT => Ok(Self::Agent),
91            OBJK_CLIENT => Ok(Self::Client),
92            OBJK_DOMAIN => Ok(Self::Domain),
93            _ => Err(XrceError::ValueOutOfRange {
94                message: "object kind not in DDS-XRCE spec",
95            }),
96        }
97    }
98
99    /// `true`, wenn der Object-Kind ein DDS-Endpoint ist
100    /// (DataWriter oder DataReader).
101    #[must_use]
102    pub fn is_endpoint(self) -> bool {
103        matches!(self, Self::DataWriter | Self::DataReader)
104    }
105
106    /// `true`, wenn der Object-Kind ein DDS-Container ist
107    /// (Publisher / Subscriber / Participant).
108    #[must_use]
109    pub fn is_container(self) -> bool {
110        matches!(self, Self::Publisher | Self::Subscriber | Self::Participant)
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    #![allow(clippy::expect_used, clippy::unwrap_used)]
117    use super::*;
118
119    #[test]
120    fn all_spec_kinds_roundtrip() {
121        for k in [
122            ObjectKind::Invalid,
123            ObjectKind::Participant,
124            ObjectKind::Topic,
125            ObjectKind::Publisher,
126            ObjectKind::Subscriber,
127            ObjectKind::DataWriter,
128            ObjectKind::DataReader,
129            ObjectKind::Type,
130            ObjectKind::QosProfile,
131            ObjectKind::Application,
132            ObjectKind::Agent,
133            ObjectKind::Client,
134            ObjectKind::Domain,
135        ] {
136            assert_eq!(ObjectKind::from_u8(k.to_u8()).unwrap(), k);
137        }
138    }
139
140    #[test]
141    fn unknown_byte_rejected() {
142        // 0x07 ist im 4-bit-Bereich aber nicht in der Spec
143        assert!(ObjectKind::from_u8(0x07).is_err());
144        // > 0x0F → out of 4-bit-range
145        assert!(ObjectKind::from_u8(0x10).is_err());
146        assert!(ObjectKind::from_u8(0xFF).is_err());
147    }
148
149    #[test]
150    fn endpoint_classification() {
151        assert!(ObjectKind::DataWriter.is_endpoint());
152        assert!(ObjectKind::DataReader.is_endpoint());
153        assert!(!ObjectKind::Topic.is_endpoint());
154        assert!(!ObjectKind::Participant.is_endpoint());
155    }
156
157    #[test]
158    fn container_classification() {
159        assert!(ObjectKind::Publisher.is_container());
160        assert!(ObjectKind::Subscriber.is_container());
161        assert!(ObjectKind::Participant.is_container());
162        assert!(!ObjectKind::DataWriter.is_container());
163        assert!(!ObjectKind::Topic.is_container());
164    }
165
166    #[test]
167    fn raw_const_values_match_spec() {
168        // Sanity-Check: Spec §7.2 Table 4
169        assert_eq!(OBJK_PARTICIPANT, 0x01);
170        assert_eq!(OBJK_TOPIC, 0x02);
171        assert_eq!(OBJK_DATAWRITER, 0x05);
172        assert_eq!(OBJK_DATAREADER, 0x06);
173        assert_eq!(OBJK_AGENT, 0x0D);
174        assert_eq!(OBJK_CLIENT, 0x0E);
175    }
176}