nros_node/
primitive_options.rs1use nros_rmw::{
12 QoSDurabilityPolicy, QoSHistoryPolicy, QoSLivelinessPolicy, QoSProfile, QoSReliabilityPolicy,
13};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct PrimitiveOptions<'a> {
27 pub name: &'a str,
29 pub history: Option<QoSHistoryPolicy>,
31 pub depth: Option<u32>,
33 pub reliability: Option<QoSReliabilityPolicy>,
35 pub durability: Option<QoSDurabilityPolicy>,
37 pub deadline_ms: Option<u32>,
39 pub lifespan_ms: Option<u32>,
41 pub liveliness: Option<QoSLivelinessPolicy>,
43 pub liveliness_lease_ms: Option<u32>,
45 pub avoid_ros_namespace_conventions: Option<bool>,
47}
48
49impl<'a> PrimitiveOptions<'a> {
50 pub const fn new(name: &'a str) -> Self {
52 Self {
53 name,
54 history: None,
55 depth: None,
56 reliability: None,
57 durability: None,
58 deadline_ms: None,
59 lifespan_ms: None,
60 liveliness: None,
61 liveliness_lease_ms: None,
62 avoid_ros_namespace_conventions: None,
63 }
64 }
65
66 pub fn apply_to(&self, qos: &mut QoSProfile) {
69 if let Some(v) = self.history {
70 qos.history = v;
71 }
72 if let Some(v) = self.depth {
73 qos.depth = v;
74 }
75 if let Some(v) = self.reliability {
76 qos.reliability = v;
77 }
78 if let Some(v) = self.durability {
79 qos.durability = v;
80 }
81 if let Some(v) = self.deadline_ms {
82 qos.deadline_ms = v;
83 }
84 if let Some(v) = self.lifespan_ms {
85 qos.lifespan_ms = v;
86 }
87 if let Some(v) = self.liveliness {
88 qos.liveliness_kind = v;
89 }
90 if let Some(v) = self.liveliness_lease_ms {
91 qos.liveliness_lease_ms = v;
92 }
93 if let Some(v) = self.avoid_ros_namespace_conventions {
94 qos.avoid_ros_namespace_conventions = v;
95 }
96 }
97
98 pub fn resolve(&self, default: QoSProfile) -> QoSProfile {
101 let mut qos = default;
102 self.apply_to(&mut qos);
103 qos
104 }
105}
106
107fn duration_ms(d: core::time::Duration) -> u32 {
110 QoSProfile::new().deadline_duration(d).deadline_ms
111}
112
113pub trait IntoPrimitiveOptions<'a>: Sized {
119 fn into_primitive_options(self) -> PrimitiveOptions<'a>;
121
122 fn qos(self, profile: QoSProfile) -> PrimitiveOptions<'a> {
124 let mut o = self.into_primitive_options();
125 o.history = Some(profile.history);
126 o.depth = Some(profile.depth);
127 o.reliability = Some(profile.reliability);
128 o.durability = Some(profile.durability);
129 o.deadline_ms = Some(profile.deadline_ms);
130 o.lifespan_ms = Some(profile.lifespan_ms);
131 o.liveliness = Some(profile.liveliness_kind);
132 o.liveliness_lease_ms = Some(profile.liveliness_lease_ms);
133 o.avoid_ros_namespace_conventions = Some(profile.avoid_ros_namespace_conventions);
134 o
135 }
136
137 fn topics_qos(self) -> PrimitiveOptions<'a> {
139 self.qos(QoSProfile::topics_default())
140 }
141
142 fn sensor_data_qos(self) -> PrimitiveOptions<'a> {
144 self.qos(QoSProfile::sensor_data_default())
145 }
146
147 fn services_qos(self) -> PrimitiveOptions<'a> {
149 self.qos(QoSProfile::services_default())
150 }
151
152 fn system_qos(self) -> PrimitiveOptions<'a> {
154 self.qos(QoSProfile::system_default())
155 }
156
157 fn history(self, history: QoSHistoryPolicy) -> PrimitiveOptions<'a> {
159 let mut o = self.into_primitive_options();
160 o.history = Some(history);
161 o
162 }
163
164 fn keep_last(self, depth: u32) -> PrimitiveOptions<'a> {
166 let mut o = self.into_primitive_options();
167 o.history = Some(QoSHistoryPolicy::KeepLast);
168 o.depth = Some(depth);
169 o
170 }
171
172 fn keep_all(self) -> PrimitiveOptions<'a> {
174 self.history(QoSHistoryPolicy::KeepAll)
175 }
176
177 fn reliability(self, reliability: QoSReliabilityPolicy) -> PrimitiveOptions<'a> {
179 let mut o = self.into_primitive_options();
180 o.reliability = Some(reliability);
181 o
182 }
183
184 fn reliable(self) -> PrimitiveOptions<'a> {
186 self.reliability(QoSReliabilityPolicy::Reliable)
187 }
188
189 fn best_effort(self) -> PrimitiveOptions<'a> {
191 self.reliability(QoSReliabilityPolicy::BestEffort)
192 }
193
194 fn durability(self, durability: QoSDurabilityPolicy) -> PrimitiveOptions<'a> {
196 let mut o = self.into_primitive_options();
197 o.durability = Some(durability);
198 o
199 }
200
201 fn volatile(self) -> PrimitiveOptions<'a> {
203 self.durability(QoSDurabilityPolicy::Volatile)
204 }
205
206 fn transient_local(self) -> PrimitiveOptions<'a> {
208 self.durability(QoSDurabilityPolicy::TransientLocal)
209 }
210
211 fn lifespan(self, lifespan: core::time::Duration) -> PrimitiveOptions<'a> {
213 let mut o = self.into_primitive_options();
214 o.lifespan_ms = Some(duration_ms(lifespan));
215 o
216 }
217
218 fn lifespan_duration(self, duration: core::time::Duration) -> PrimitiveOptions<'a> {
220 self.lifespan(duration)
221 }
222
223 fn infinite_lifespan(self) -> PrimitiveOptions<'a> {
225 let mut o = self.into_primitive_options();
226 o.lifespan_ms = Some(0);
227 o
228 }
229
230 fn deadline(self, deadline: core::time::Duration) -> PrimitiveOptions<'a> {
232 let mut o = self.into_primitive_options();
233 o.deadline_ms = Some(duration_ms(deadline));
234 o
235 }
236
237 fn deadline_duration(self, duration: core::time::Duration) -> PrimitiveOptions<'a> {
239 self.deadline(duration)
240 }
241
242 fn no_deadline(self) -> PrimitiveOptions<'a> {
244 let mut o = self.into_primitive_options();
245 o.deadline_ms = Some(0);
246 o
247 }
248
249 fn liveliness(self, liveliness: QoSLivelinessPolicy) -> PrimitiveOptions<'a> {
251 let mut o = self.into_primitive_options();
252 o.liveliness = Some(liveliness);
253 o
254 }
255
256 fn liveliness_automatic(self) -> PrimitiveOptions<'a> {
258 self.liveliness(QoSLivelinessPolicy::Automatic)
259 }
260
261 fn liveliness_manual(self) -> PrimitiveOptions<'a> {
263 self.liveliness(QoSLivelinessPolicy::ManualByTopic)
264 }
265
266 fn liveliness_lease(self, lease: core::time::Duration) -> PrimitiveOptions<'a> {
269 let mut o = self.into_primitive_options();
270 o.liveliness_lease_ms = Some(duration_ms(lease));
271 o
272 }
273
274 fn liveliness_lease_duration(self, duration: core::time::Duration) -> PrimitiveOptions<'a> {
277 self.liveliness_lease(duration)
278 }
279
280 fn avoid_ros_namespace_conventions(self) -> PrimitiveOptions<'a> {
282 let mut o = self.into_primitive_options();
283 o.avoid_ros_namespace_conventions = Some(true);
284 o
285 }
286}
287
288impl<'a, T: core::borrow::Borrow<str> + ?Sized + 'a> IntoPrimitiveOptions<'a> for &'a T {
292 fn into_primitive_options(self) -> PrimitiveOptions<'a> {
293 PrimitiveOptions::new(self.borrow())
294 }
295}
296
297impl<'a> IntoPrimitiveOptions<'a> for PrimitiveOptions<'a> {
298 fn into_primitive_options(self) -> PrimitiveOptions<'a> {
299 self
300 }
301}
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306
307 #[test]
308 fn a_bare_name_keeps_the_kinds_default() {
309 let o = "chatter".into_primitive_options();
310 assert_eq!(
311 o.resolve(QoSProfile::services_default()),
312 QoSProfile::services_default()
313 );
314 }
315
316 #[test]
317 fn steps_overwrite_only_what_they_name() {
318 let o = "chatter".keep_last(3).best_effort().transient_local();
319 let q = o.resolve(QoSProfile::topics_default());
320 assert_eq!(q.history, QoSHistoryPolicy::KeepLast);
321 assert_eq!(q.depth, 3);
322 assert_eq!(q.reliability, QoSReliabilityPolicy::BestEffort);
323 assert_eq!(q.durability, QoSDurabilityPolicy::TransientLocal);
324 let d = QoSProfile::topics_default();
325 assert_eq!(q.deadline_ms, d.deadline_ms);
326 assert_eq!(q.liveliness_kind, d.liveliness_kind);
327 }
328
329 #[test]
330 fn a_profile_step_states_every_policy_and_later_steps_win() {
331 let q = "scan"
332 .sensor_data_qos()
333 .reliable()
334 .resolve(QoSProfile::services_default());
335 let mut want = QoSProfile::sensor_data_default();
336 want.reliability = QoSReliabilityPolicy::Reliable;
337 assert_eq!(q, want);
338 }
339
340 #[test]
341 fn duration_steps_record_milliseconds_and_infinite_is_zero() {
342 let q = "t"
343 .deadline(core::time::Duration::from_millis(250))
344 .lifespan(core::time::Duration::from_micros(10))
345 .liveliness_lease_duration(core::time::Duration::from_secs(2))
346 .resolve(QoSProfile::topics_default());
347 assert_eq!(q.deadline_ms, 250);
348 assert_eq!(
349 q.lifespan_ms, 1,
350 "a non-zero duration under 1 ms is not infinite"
351 );
352 assert_eq!(q.liveliness_lease_ms, 2000);
353 let q = "t".no_deadline().infinite_lifespan().resolve(q);
354 assert_eq!((q.deadline_ms, q.lifespan_ms), (0, 0));
355 }
356
357 #[test]
358 fn liveliness_and_namespace_steps() {
359 let q = "t"
360 .liveliness_manual()
361 .avoid_ros_namespace_conventions()
362 .resolve(QoSProfile::topics_default());
363 assert_eq!(q.liveliness_kind, QoSLivelinessPolicy::ManualByTopic);
364 assert!(q.avoid_ros_namespace_conventions);
365 }
366}