Skip to main content

cyclonedds/
topicable.rs

1/// A type that can be used as a DDS topic payload.
2///
3/// Implement this trait to register a type as a DDS topic payload. The derive
4/// macro [`Topicable`](cyclonedds_macros::Topicable) handles the common case;
5/// implement manually when you need control over the key type or type name.
6///
7/// # Keys
8///
9/// Every [`Topicable`] type has an associated [`Key`](Topicable::Key) type that
10/// uniquely identifies an instance. For unkeyed topics, use any zero-sized type
11/// as the key ([`()`](primitive@unit) being the straightforward choice), and
12/// all samples will be treated as belonging to a single instance.
13///
14/// If using the [`derive`](cyclonedds_macros::Topicable) macro, a hidden type
15/// gets generated which contains just the fields marked as a key fields. To
16/// access this type see the [`Key` type alias](crate::topicable::Key).
17///
18/// # Examples
19///
20/// ```
21/// #[derive(
22///     cyclonedds::Topicable, serde::Serialize, serde::Deserialize, Default, Clone, Debug,
23/// )]
24/// struct Temperature {
25///     #[dds(key)]
26///     sensor_id: u32,
27///     value: f32,
28/// }
29/// ```
30///
31/// Manual implementation:
32///
33/// ```
34/// #[derive(serde::Serialize, serde::Deserialize, Clone, Default, Debug)]
35/// struct Temperature {
36///     sensor_id: u32,
37///     value: f32,
38/// }
39///
40/// impl cyclonedds::Topicable for Temperature {
41///     type Key = u32;
42///
43///     fn from_key(key: &u32) -> Self {
44///         Self {
45///             sensor_id: *key,
46///             value: 0.0,
47///         }
48///     }
49///
50///     fn as_key(&self) -> u32 {
51///         self.sensor_id
52///     }
53/// }
54/// ```
55pub trait Topicable:
56    serde::ser::Serialize + serde::de::DeserializeOwned + std::clone::Clone + std::fmt::Debug
57{
58    /// The key type that uniquely identifies an instance of this topic.
59    ///
60    /// For unkeyed topics, use any zero-sized type as the key
61    /// ([`()`](primitive@unit) being the straightforward choice), and all
62    /// samples will be treated as belonging to a single instance.
63    ///
64    /// The key type must implement [`CdrBounds`](crate::cdr_bounds::CdrBounds)
65    /// to provide serialization size information required by DDS when
66    /// computing keyhashes.
67    type Key: serde::ser::Serialize
68        + serde::de::DeserializeOwned
69        + std::clone::Clone
70        + std::fmt::Debug
71        + std::cmp::PartialEq
72        + std::hash::Hash
73        + crate::cdr_bounds::CdrBounds;
74
75    /// Whether this type has a meaningful key.
76    ///
77    /// `false` when `Self::Key` is `()`, in which case all samples belong to a
78    /// single instance. Derived from the size of `Self::Key` at compile time.
79    ///
80    /// This can technically be overridden, but doing so will produce
81    /// unintuitive behavior. The default derived value should be correct in
82    /// virtually all cases.
83    #[doc(hidden)]
84    const IS_KEYED: bool = std::mem::size_of::<Self::Key>() != 0;
85
86    /// Forces MD5 keyhash generation regardless of key size.
87    ///
88    /// By default, the big-endian CDR serialization of the key is used as the
89    /// keyhash when the maximum serialized key size is 16 bytes or fewer, and
90    /// MD5 otherwise. Set this to `true` to force MD5 unconditionally.
91    const FORCE_MD5_KEYHASH: bool = false;
92
93    /// Constructs a default instance of `Self` from a key.
94    ///
95    /// Used to materialize a full sample from a key-only notification. Fields
96    /// not part of the key should be set to their default values.
97    fn from_key(key: &Self::Key) -> Self;
98
99    /// Extracts the key from this instance.
100    fn as_key(&self) -> Self::Key;
101
102    /// Returns the DDS type name for this type.
103    ///
104    /// Defaults to the Rust type name as it would appear within the crate.
105    /// Override when interoperating with an existing system whose IDL type
106    /// names differ from the Rust type names.
107    #[must_use]
108    fn dds_type_name() -> impl AsRef<str> {
109        let full_type_path = std::any::type_name::<Self>();
110
111        // Strip out the leading module if it exists or leave it as the full
112        // type path otherwise.
113        full_type_path
114            .split_once("::")
115            .map_or(full_type_path, |(_, type_path)| type_path)
116    }
117}
118
119/// Evaluates to the [`Key`](Topicable::Key) type associated with the
120/// [`Topicable`] type `T`.
121///
122/// # Examples
123/// ```
124/// use cyclonedds::{Key, Topicable};
125///
126/// #[derive(Topicable, serde::Serialize, serde::Deserialize, Default, Clone, Debug)]
127/// struct Data {
128///     #[dds(key)]
129///     pub x: i32,
130///     #[dds(key)]
131///     pub y: i32,
132///     pub message: String,
133/// }
134///
135/// let data = Data {
136///     x: 1,
137///     y: 2,
138///     ..Data::default()
139/// };
140///
141/// // Access the `Key` of `Data` via the type alias.
142/// let key = Key::<Data> { x: 1, y: 2 };
143///
144/// // The keys are equal.
145/// assert_eq!(key, data.as_key());
146/// ```
147pub type Key<T> = <T as Topicable>::Key;