Skip to main content

cyclonedds/
domain.rs

1//! A Domain defines the boundary of a shared data-space (identified by a 32-bit
2//! domain ID). Only entities within the same domain can publish or subscribe to
3//! each other's data.
4
5use crate::internal::ffi;
6use crate::{Error, Result};
7
8/// A communication boundary for DDS publish-subscribe traffic.
9#[derive(Debug)]
10pub struct Domain {
11    pub(crate) id: cyclonedds_sys::dds_domainid_t,
12    pub(crate) inner: cyclonedds_sys::dds_entity_t,
13}
14
15impl Domain {
16    /// Creates a new domain with the given `domain_id` using the default
17    /// Cyclone DDS configuration.
18    ///
19    /// # Errors
20    ///
21    /// Returns an [`Error`] if Cyclone DDS fails to create the domain, for
22    /// example if the `domain_id` is out of range or already in use.
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// use cyclonedds::Domain;
28    /// // Create a default domain.
29    /// let default_domain = Domain::default();
30    ///
31    /// // Create a new domain with the domain ID of 1.
32    /// let domain = Domain::new(1)?;
33    /// # Ok::<_, cyclonedds::Error>(())
34    /// ```
35    pub fn new(domain_id: u32) -> Result<Self> {
36        let inner = ffi::dds_create_domain(domain_id)?;
37        Ok(Self {
38            id: domain_id,
39            inner,
40        })
41    }
42
43    /// Creates a new domain with the given `domain_id` and an XML `config`
44    /// string passed directly to Cyclone DDS.
45    ///
46    /// The `config` must be a valid Cyclone DDS XML configuration fragment. See
47    /// the [Cyclone DDS
48    /// documentation](https://github.com/eclipse-cyclonedds/cyclonedds/blob/master/docs/manual/options.md)
49    /// for the full set of configuration options.
50    ///
51    /// # Errors
52    ///
53    /// Returns an [`Error`] if the `config` contains interior null bytes or if
54    /// the domain cannot be created with the provided domain ID and
55    /// configuration.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use cyclonedds::Domain;
61    ///
62    /// let config = r#"
63    ///     <Domain>
64    ///         <Tracing>
65    ///             <Verbosity>warning</Verbosity>
66    ///             <OutputFile>stderr</OutputFile>
67    ///         </Tracing>
68    ///     </Domain>"#;
69    ///
70    /// // Create a new domain with the configuration and a domain ID of 1.
71    /// let domain = Domain::new_with_xml_config(1, config)?;
72    /// # Ok::<_, cyclonedds::Error>(())
73    /// ```
74    pub fn new_with_xml_config(domain_id: u32, config: &str) -> Result<Self> {
75        let config = std::ffi::CString::new(config).map_err(|_err| Error::BadParameter)?;
76        let inner = ffi::dds_create_domain_with_config(domain_id, &config)?;
77        Ok(Self {
78            id: domain_id,
79            inner,
80        })
81    }
82}
83
84impl Drop for Domain {
85    fn drop(&mut self) {
86        if self.inner != 0 {
87            let result = ffi::dds_delete(self.inner);
88            debug_assert!(
89                result.is_ok(),
90                "unable to delete {self:?}: failed with {result:?}"
91            );
92        }
93    }
94}
95
96impl Default for Domain {
97    fn default() -> Self {
98        Self {
99            id: cyclonedds_sys::DOMAIN_DEFAULT,
100            inner: 0,
101        }
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[test]
110    fn test_domain_create() {
111        let domain_id = crate::tests::domain::unique_id();
112        Domain::new(domain_id).unwrap();
113    }
114
115    #[test]
116    fn test_domain_create_default() {
117        let domain = Domain::default();
118        assert_eq!(domain.id, cyclonedds_sys::DOMAIN_DEFAULT);
119    }
120
121    #[test]
122    fn test_domain_create_with_explicit_default_id() {
123        let domain_id = cyclonedds_sys::DOMAIN_DEFAULT;
124        let domain = Domain::new(domain_id).unwrap_err();
125        assert_eq!(domain, Error::BadParameter);
126    }
127
128    #[test]
129    fn test_domain_create_with_empty_xml_config() {
130        let domain_id = crate::tests::domain::unique_id();
131        let xml_config = "";
132        Domain::new_with_xml_config(domain_id, xml_config).unwrap();
133    }
134
135    #[test]
136    fn test_domain_create_with_xml_config_with_invalid_string() {
137        let domain_id = crate::tests::domain::unique_id();
138        let xml_config = "\0";
139        let domain = Domain::new_with_xml_config(domain_id, xml_config).unwrap_err();
140        assert_eq!(domain, Error::BadParameter);
141    }
142
143    #[test]
144    fn test_domain_create_with_xml_config_with_explicit_default_id() {
145        let domain_id = cyclonedds_sys::DOMAIN_DEFAULT;
146        let xml_config = "";
147        let domain = Domain::new_with_xml_config(domain_id, xml_config).unwrap_err();
148        assert_eq!(domain, Error::BadParameter);
149    }
150
151    #[test]
152    fn test_domain_create_with_xml_config_with_malformed_xml() {
153        let domain_id = crate::tests::domain::unique_id();
154        let xml_config = "<>";
155        let domain = Domain::new_with_xml_config(domain_id, xml_config).unwrap_err();
156        assert_eq!(domain, Error::NonSpecific);
157    }
158
159    #[test]
160    fn test_domain_create_with_xml_config_with_valid_xml() {
161        let domain_id = crate::tests::domain::unique_id();
162        let xml_config = "<Domain><General><MaxMessageSize>1400B</MaxMessageSize></General>";
163        Domain::new_with_xml_config(domain_id, xml_config).unwrap();
164    }
165}