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;