Skip to main content

rustdds/dds/
qos.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4use speedy::{Readable, Writable};
5#[allow(unused_imports)]
6use log::{debug, error, info, trace, warn};
7
8use crate::{
9  dds::result::QosError,
10  messages::submessages::elements::parameter::Parameter,
11  serialization::{
12    pl_cdr_adapters::{PlCdrDeserializeError, PlCdrSerializeError},
13    speedy_pl_cdr_helpers::*,
14  },
15  structure::{duration::Duration, endpoint::ReliabilityKind, parameter_id::ParameterId},
16};
17
18// This is to be implemented by all DomainParticipant, Publisher, Subscriber,
19// DataWriter, DataReader, Topic
20/// Trait that is implemented by all necessary DDS Entities that are required to
21/// provide QosPolicies.
22pub trait HasQoSPolicy {
23  fn qos(&self) -> QosPolicies;
24}
25
26/// Trait that is implemented by all necessary DDS Entities that are required to
27/// have a mutable QosPolicies.
28pub trait MutQosPolicy {
29  fn set_qos(&mut self, new_qos: &QosPolicies) -> Result<(), QosError>;
30}
31
32/// DDS spec 2.3.3 defines this as "long" with named constants from 0 to 22.
33/// numbering is from IDL PSM, but it should be unnecessary at the Rust
34/// application interface
35#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
36pub enum QosPolicyId {
37  // Invalid  // We should represent this using Option<QosPolicyId> where needed
38  // UserData,  // 1
39  Durability,   // 2
40  Presentation, // 3
41  Deadline,
42  LatencyBudget, // 5
43  Ownership,
44  // OwnershipStrength, // 7
45  Liveliness,
46  TimeBasedFilter, // 9
47  // Partition,
48
49  // Note: If "Partition" is ever implemented, observe also DDS Security spec v1.1
50  // Section "7.3.5 Immutability of Publisher Partition Qos in combination with non-volatile
51  // Durability kind" when implementing.
52  Reliability, // 11
53  DestinationOrder,
54  History, // 13
55  ResourceLimits,
56  // EntityFactory, // 15
57  // WriterDataLifeCycle,
58  // ReaderDataLifeCycle, // 17
59  // TopicData, // 18
60  // GroupData,
61  // TransportPriority, // 20
62  Lifespan,
63  // DurabilityService, // 22
64  Representation, // 23 (DDS-XTypes v1.3 DATA_REPRESENTATION)
65  Property,       // No Id in the security spec (But this is from older DDS/RTPs spec.)
66}
67
68/// Utility for building [QosPolicies]
69#[derive(Default, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
70pub struct QosPolicyBuilder {
71  durability: Option<policy::Durability>,
72  presentation: Option<policy::Presentation>,
73  deadline: Option<policy::Deadline>,
74  latency_budget: Option<policy::LatencyBudget>,
75  ownership: Option<policy::Ownership>,
76  liveliness: Option<policy::Liveliness>,
77  time_based_filter: Option<policy::TimeBasedFilter>,
78  reliability: Option<policy::Reliability>,
79  destination_order: Option<policy::DestinationOrder>,
80  history: Option<policy::History>,
81  resource_limits: Option<policy::ResourceLimits>,
82  lifespan: Option<policy::Lifespan>,
83  // #[cfg(feature = "security")]
84  // property: Option<policy::Property>,
85  //
86  // QoSPolicyBuilder does not support (security) properties, because we would like to
87  // be able to make `const` QosPolicies with it. This is not possible with
88  // `policy::Property`, because it contains `Vec`, which again is incompatible with
89  // `const`. Currently, we have no need for this, either.
90}
91
92impl QosPolicyBuilder {
93  pub const fn new() -> Self {
94    // We can use Self::default() when it is availabel as "const"
95    Self {
96      durability: None,
97      presentation: None,
98      deadline: None,
99      latency_budget: None,
100      ownership: None,
101      liveliness: None,
102      time_based_filter: None,
103      reliability: None,
104      destination_order: None,
105      history: None,
106      resource_limits: None,
107      lifespan: None,
108    }
109  }
110
111  #[must_use]
112  pub const fn durability(mut self, durability: policy::Durability) -> Self {
113    self.durability = Some(durability);
114    self
115  }
116
117  #[must_use]
118  pub const fn presentation(mut self, presentation: policy::Presentation) -> Self {
119    self.presentation = Some(presentation);
120    self
121  }
122
123  #[must_use]
124  pub const fn deadline(mut self, deadline: policy::Deadline) -> Self {
125    self.deadline = Some(deadline);
126    self
127  }
128
129  #[must_use]
130  pub const fn latency_budget(mut self, latency_budget: policy::LatencyBudget) -> Self {
131    self.latency_budget = Some(latency_budget);
132    self
133  }
134
135  #[must_use]
136  pub const fn ownership(mut self, ownership: policy::Ownership) -> Self {
137    self.ownership = Some(ownership);
138    self
139  }
140
141  #[must_use]
142  pub const fn liveliness(mut self, liveliness: policy::Liveliness) -> Self {
143    self.liveliness = Some(liveliness);
144    self
145  }
146
147  #[must_use]
148  pub const fn time_based_filter(mut self, time_based_filter: policy::TimeBasedFilter) -> Self {
149    self.time_based_filter = Some(time_based_filter);
150    self
151  }
152
153  #[must_use]
154  pub const fn reliability(mut self, reliability: policy::Reliability) -> Self {
155    self.reliability = Some(reliability);
156    self
157  }
158
159  #[must_use]
160  pub const fn best_effort(mut self) -> Self {
161    self.reliability = Some(policy::Reliability::BestEffort);
162    self
163  }
164
165  #[must_use]
166  pub const fn reliable(mut self, max_blocking_time: Duration) -> Self {
167    self.reliability = Some(policy::Reliability::Reliable { max_blocking_time });
168    self
169  }
170
171  #[must_use]
172  pub const fn destination_order(mut self, destination_order: policy::DestinationOrder) -> Self {
173    self.destination_order = Some(destination_order);
174    self
175  }
176
177  #[must_use]
178  pub const fn history(mut self, history: policy::History) -> Self {
179    self.history = Some(history);
180    self
181  }
182
183  #[must_use]
184  pub const fn resource_limits(mut self, resource_limits: policy::ResourceLimits) -> Self {
185    self.resource_limits = Some(resource_limits);
186    self
187  }
188
189  #[must_use]
190  pub const fn lifespan(mut self, lifespan: policy::Lifespan) -> Self {
191    self.lifespan = Some(lifespan);
192    self
193  }
194
195  pub const fn build(self) -> QosPolicies {
196    QosPolicies {
197      durability: self.durability,
198      presentation: self.presentation,
199      deadline: self.deadline,
200      latency_budget: self.latency_budget,
201      ownership: self.ownership,
202      liveliness: self.liveliness,
203      time_based_filter: self.time_based_filter,
204      reliability: self.reliability,
205      destination_order: self.destination_order,
206      history: self.history,
207      resource_limits: self.resource_limits,
208      lifespan: self.lifespan,
209      // DATA_REPRESENTATION is not part of the (const) builder: it holds a `Vec`
210      // (drop glue) which is incompatible with `const fn`, and the built-in QoS
211      // policies never need it. Set it via `QosPolicies::with_data_representation`.
212      data_representation: None,
213      #[cfg(feature = "security")]
214      property: None,
215    }
216  }
217}
218
219/// Describes a set of RTPS/DDS QoS policies
220///
221/// QosPolicies are constructed using a [`QosPolicyBuilder`]
222#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
223pub struct QosPolicies {
224  // pub(crate) because as we want to have some builtin QoS Policies as constant.
225  pub(crate) durability: Option<policy::Durability>,
226  pub(crate) presentation: Option<policy::Presentation>,
227  pub(crate) deadline: Option<policy::Deadline>,
228  pub(crate) latency_budget: Option<policy::LatencyBudget>,
229  pub(crate) ownership: Option<policy::Ownership>,
230  pub(crate) liveliness: Option<policy::Liveliness>,
231  pub(crate) time_based_filter: Option<policy::TimeBasedFilter>,
232  pub(crate) reliability: Option<policy::Reliability>,
233  pub(crate) destination_order: Option<policy::DestinationOrder>,
234  pub(crate) history: Option<policy::History>,
235  pub(crate) resource_limits: Option<policy::ResourceLimits>,
236  pub(crate) lifespan: Option<policy::Lifespan>,
237  pub(crate) data_representation: Option<policy::DataRepresentation>,
238  #[cfg(feature = "security")]
239  pub(crate) property: Option<policy::Property>,
240}
241
242impl QosPolicies {
243  // TODO: rename this to "none", as this is already member of QosPolicies, so
244  // context in implied
245  pub fn qos_none() -> Self {
246    Self::default()
247  }
248
249  pub fn builder() -> QosPolicyBuilder {
250    QosPolicyBuilder::new()
251  }
252
253  pub const fn durability(&self) -> Option<policy::Durability> {
254    self.durability
255  }
256
257  pub fn is_volatile(&self) -> bool {
258    matches!(self.durability, Some(policy::Durability::Volatile))
259  }
260
261  pub const fn presentation(&self) -> Option<policy::Presentation> {
262    self.presentation
263  }
264
265  pub const fn deadline(&self) -> Option<policy::Deadline> {
266    self.deadline
267  }
268
269  pub const fn latency_budget(&self) -> Option<policy::LatencyBudget> {
270    self.latency_budget
271  }
272
273  pub const fn ownership(&self) -> Option<policy::Ownership> {
274    self.ownership
275  }
276
277  pub const fn liveliness(&self) -> Option<policy::Liveliness> {
278    self.liveliness
279  }
280
281  pub const fn time_based_filter(&self) -> Option<policy::TimeBasedFilter> {
282    self.time_based_filter
283  }
284
285  pub const fn reliability(&self) -> Option<policy::Reliability> {
286    self.reliability
287  }
288
289  pub fn is_reliable(&self) -> bool {
290    matches!(self.reliability, Some(policy::Reliability::Reliable { .. }))
291  }
292
293  pub const fn reliable_max_blocking_time(&self) -> Option<Duration> {
294    if let Some(policy::Reliability::Reliable { max_blocking_time }) = self.reliability {
295      Some(max_blocking_time)
296    } else {
297      None
298    }
299  }
300
301  pub const fn destination_order(&self) -> Option<policy::DestinationOrder> {
302    self.destination_order
303  }
304
305  pub const fn history(&self) -> Option<policy::History> {
306    self.history
307  }
308
309  pub const fn resource_limits(&self) -> Option<policy::ResourceLimits> {
310    self.resource_limits
311  }
312
313  pub const fn lifespan(&self) -> Option<policy::Lifespan> {
314    self.lifespan
315  }
316
317  pub fn data_representation(&self) -> Option<policy::DataRepresentation> {
318    self.data_representation.clone()
319  }
320
321  /// Set the DATA_REPRESENTATION QoS policy (DDS-XTypes v1.3 Section 7.6.3.1).
322  ///
323  /// For a DataWriter the first list element is the representation it uses; for
324  /// a DataReader the list is the set of representations it accepts. This is
325  /// not part of [`QosPolicyBuilder`] because it holds a `Vec` (incompatible
326  /// with the `const` builder used for built-in QoS).
327  #[must_use]
328  pub fn with_data_representation(
329    mut self,
330    data_representation: policy::DataRepresentation,
331  ) -> Self {
332    self.data_representation = Some(data_representation);
333    self
334  }
335
336  #[cfg(feature = "security")]
337  pub fn property(&self) -> Option<policy::Property> {
338    self.property.clone()
339  }
340
341  /// Merge two QosPolicies
342  ///
343  /// Constructs a QosPolicy, where each policy is taken from `self`,
344  /// and overwritten with those policies from `other` that are defined.
345  #[must_use]
346  // TODO: Make this "const" when support for const .or() arrives in stable Rust.
347  pub fn modify_by(&self, other: &Self) -> Self {
348    Self {
349      durability: other.durability.or(self.durability),
350      presentation: other.presentation.or(self.presentation),
351      deadline: other.deadline.or(self.deadline),
352      latency_budget: other.latency_budget.or(self.latency_budget),
353      ownership: other.ownership.or(self.ownership),
354      liveliness: other.liveliness.or(self.liveliness),
355      time_based_filter: other.time_based_filter.or(self.time_based_filter),
356      reliability: other.reliability.or(self.reliability),
357      destination_order: other.destination_order.or(self.destination_order),
358      history: other.history.or(self.history),
359      resource_limits: other.resource_limits.or(self.resource_limits),
360      lifespan: other.lifespan.or(self.lifespan),
361      data_representation: other
362        .data_representation
363        .clone()
364        .or(self.data_representation.clone()),
365      #[cfg(feature = "security")]
366      property: other.property.clone().or(self.property.clone()),
367    }
368  }
369
370  /// Check if policy complies to another policy.
371  ///
372  /// `self` is the "offered" (publisher) QoS
373  /// `other` is the "requested" (subscriber) QoS
374  ///
375  /// * None => Policies are compatible
376  /// * Some(policyId) => Failure, where policyId is (any) one of the policies
377  ///   causing incompliance
378  ///
379  /// Compliance (compatibility) is defined in the table in DDS spec v1.4
380  /// Section "2.2.3 Supported QoS"
381  ///
382  /// This is not symmetric.
383  pub fn compliance_failure_wrt(&self, other: &Self) -> Option<QosPolicyId> {
384    trace!("QoS compatibility check - offered: {self:?} - requested {other:?}");
385    let result = self.compliance_failure_wrt_impl(other);
386    trace!("Result: {result:?}");
387    result
388  }
389
390  fn compliance_failure_wrt_impl(&self, other: &Self) -> Option<QosPolicyId> {
391    // A QoS policy that is absent from an endpoint's discovery data must be
392    // treated as that policy's DDS default value (DDS spec v1.4 ยง2.2.3): the
393    // remote endpoint is in fact using the default, it just omitted the
394    // (default-valued) policy from the wire. Comparing only when *both* sides
395    // are `Some` would miss incompatibilities where one side omitted a
396    // default-valued policy (e.g. a writer that does not announce the default
397    // VOLATILE durability), causing incompatible endpoints to match.
398
399    // check Durability: Offered must be better than or equal to Requested.
400    // Default: VOLATILE (the lowest).
401    {
402      let off = self.durability.unwrap_or(policy::Durability::Volatile);
403      let req = other.durability.unwrap_or(policy::Durability::Volatile);
404      if off < req {
405        return Some(QosPolicyId::Durability);
406      }
407    }
408
409    // check Presentation:
410    // * If coherent_access is requested, it must be offered also. AND
411    // * Same for ordered_access. AND
412    // * Offered access scope is broader than requested.
413    // Default: INSTANCE scope, no coherent access, no ordered access.
414    {
415      let default = policy::Presentation {
416        access_scope: policy::PresentationAccessScope::Instance,
417        coherent_access: false,
418        ordered_access: false,
419      };
420      let off = self.presentation.unwrap_or(default);
421      let req = other.presentation.unwrap_or(default);
422      if (req.coherent_access && !off.coherent_access)
423        || (req.ordered_access && !off.ordered_access)
424        || (req.access_scope > off.access_scope)
425      {
426        return Some(QosPolicyId::Presentation);
427      }
428    }
429
430    // check Deadline: offered period <= requested period. Default: INFINITE.
431    {
432      let off = self
433        .deadline
434        .unwrap_or(policy::Deadline(Duration::INFINITE));
435      let req = other
436        .deadline
437        .unwrap_or(policy::Deadline(Duration::INFINITE));
438      if off.0 > req.0 {
439        return Some(QosPolicyId::Deadline);
440      }
441    }
442
443    // check Latency Budget: offered duration <= requested duration.
444    // Default: zero.
445    {
446      let off = self.latency_budget.unwrap_or(policy::LatencyBudget {
447        duration: Duration::ZERO,
448      });
449      let req = other.latency_budget.unwrap_or(policy::LatencyBudget {
450        duration: Duration::ZERO,
451      });
452      if off.duration > req.duration {
453        return Some(QosPolicyId::LatencyBudget);
454      }
455    }
456
457    // check Ownership: offered kind == requested kind. Default: SHARED.
458    // Only the KIND (SHARED vs EXCLUSIVE) affects compatibility. OWNERSHIP_STRENGTH
459    // is a writer-only policy (DDS spec v1.4 ยง2.2.3.10) that selects which writer's
460    // sample is delivered for EXCLUSIVE ownership; it must NOT be compared for
461    // matching, otherwise two EXCLUSIVE endpoints with differing strengths would
462    // be wrongly reported INCOMPATIBLE_QOS.
463    {
464      let off = self.ownership.unwrap_or(policy::Ownership::Shared);
465      let req = other.ownership.unwrap_or(policy::Ownership::Shared);
466      let same_kind = matches!(
467        (off, req),
468        (policy::Ownership::Shared, policy::Ownership::Shared)
469          | (
470            policy::Ownership::Exclusive { .. },
471            policy::Ownership::Exclusive { .. }
472          )
473      );
474      if !same_kind {
475        return Some(QosPolicyId::Ownership);
476      }
477    }
478
479    // check Liveliness
480    // offered kind >= requested kind
481    // Definition: AUTOMATIC < MANUAL_BY_PARTICIPANT < MANUAL_BY_TOPIC
482    // AND offered lease_duration <= requested lease_duration
483    // Default: AUTOMATIC with INFINITE lease duration.
484    //
485    // See Ord implementation on Liveliness.
486    {
487      let default = policy::Liveliness::Automatic {
488        lease_duration: Duration::INFINITE,
489      };
490      let off = self.liveliness.unwrap_or(default);
491      let req = other.liveliness.unwrap_or(default);
492      if off < req {
493        return Some(QosPolicyId::Liveliness);
494      }
495    }
496
497    // check Reliability
498    // offered kind >= requested kind
499    // kind ranking: BEST_EFFORT < RELIABLE
500    // Default differs by entity: a DataWriter (offered) defaults to RELIABLE,
501    // a DataReader (requested) defaults to BEST_EFFORT.
502    {
503      let off = self.reliability.unwrap_or(policy::Reliability::Reliable {
504        max_blocking_time: Duration::ZERO,
505      });
506      let req = other.reliability.unwrap_or(policy::Reliability::BestEffort);
507      if off < req {
508        return Some(QosPolicyId::Reliability);
509      }
510    }
511
512    // check Destination Order
513    // offered kind >= requested kind
514    // kind ranking: BY_RECEPTION_TIMESTAMP < BY_SOURCE_TIMESTAMP
515    // Default: BY_RECEPTION_TIMESTAMP (the lowest).
516    {
517      let off = self
518        .destination_order
519        .unwrap_or(policy::DestinationOrder::ByReceptionTimestamp);
520      let req = other
521        .destination_order
522        .unwrap_or(policy::DestinationOrder::ByReceptionTimestamp);
523      if off < req {
524        return Some(QosPolicyId::DestinationOrder);
525      }
526    }
527
528    // check Data Representation (DDS-XTypes v1.3 Section 7.6.3.1.1):
529    // the writer (offered = self) uses a single representation (first element of
530    // its list, or XCDR1 if absent/empty); it is compatible with the reader
531    // (requested = other) only if that representation is contained in the
532    // reader's accepted list (or [XCDR1] if the reader's is absent/empty).
533    {
534      let offered =
535        policy::DataRepresentation::offered_representation(self.data_representation.as_ref());
536      let requested =
537        policy::DataRepresentation::accepted_representations(other.data_representation.as_ref());
538      if !requested.contains(&offered) {
539        return Some(QosPolicyId::Representation);
540      }
541    }
542
543    // default value. no incompatibility detected.
544    None
545  }
546
547  // serialization
548  pub fn to_parameter_list(
549    &self,
550    ctx: speedy::Endianness,
551  ) -> Result<Vec<Parameter>, PlCdrSerializeError> {
552    let mut pl = Vec::with_capacity(8);
553
554    let QosPolicies {
555      // bind self to (a) destructure, and (b) ensure all fields are handled
556      durability,
557      presentation,
558      deadline,
559      latency_budget,
560      ownership,
561      liveliness,
562      time_based_filter,
563      reliability,
564      destination_order,
565      history,
566      resource_limits,
567      lifespan,
568      data_representation,
569      #[cfg(feature = "security")]
570        property: _, // TODO: properties to parameter list?
571    } = self;
572
573    macro_rules! emit {
574      ($pid:ident, $member:expr, $type:ty) => {
575        pl.push(Parameter::new(ParameterId::$pid, {
576          let m: &$type = $member;
577          m.write_to_vec_with_ctx(ctx)?
578        }))
579      };
580    }
581    macro_rules! emit_option {
582      ($pid:ident, $member:expr, $type:ty) => {
583        if let Some(m) = $member {
584          emit!($pid, m, $type)
585        }
586      };
587    }
588
589    use policy::*;
590
591    emit_option!(PID_DURABILITY, durability, Durability);
592    emit_option!(PID_PRESENTATION, presentation, Presentation);
593    emit_option!(PID_DEADLINE, deadline, Deadline);
594    emit_option!(PID_LATENCY_BUDGET, latency_budget, LatencyBudget);
595
596    // Ownership serializes to (maybe) two separate Parameters
597    match ownership {
598      Some(Ownership::Exclusive { strength }) => {
599        emit!(PID_OWNERSHIP, &OwnershipKind::Exclusive, OwnershipKind);
600        emit!(PID_OWNERSHIP_STRENGTH, strength, i32);
601      }
602      Some(Ownership::Shared) => {
603        emit!(PID_OWNERSHIP, &OwnershipKind::Shared, OwnershipKind);
604      }
605      None => (),
606    }
607    // This should serialize as is
608    emit_option!(PID_LIVELINESS, liveliness, policy::Liveliness);
609    emit_option!(
610      PID_TIME_BASED_FILTER,
611      time_based_filter,
612      policy::TimeBasedFilter
613    );
614
615    if let Some(rel) = reliability.as_ref() {
616      let reliability_ser = match rel {
617        Reliability::BestEffort => ReliabilitySerialization {
618          reliability_kind: ReliabilityKind::BestEffort,
619          max_blocking_time: Duration::ZERO, // dummy value for serialization
620        },
621        Reliability::Reliable { max_blocking_time } => ReliabilitySerialization {
622          reliability_kind: ReliabilityKind::Reliable,
623          max_blocking_time: *max_blocking_time,
624        },
625      };
626      emit!(PID_RELIABILITY, &reliability_ser, ReliabilitySerialization);
627    }
628
629    emit_option!(
630      PID_DESTINATION_ORDER,
631      destination_order,
632      policy::DestinationOrder
633    );
634
635    if let Some(history) = history.as_ref() {
636      let history_ser = match history {
637        History::KeepLast { depth } => HistorySerialization {
638          kind: HistoryKind::KeepLast,
639          depth: *depth,
640        },
641        History::KeepAll => HistorySerialization {
642          kind: HistoryKind::KeepAll,
643          depth: 0,
644        },
645      };
646      emit!(PID_HISTORY, &history_ser, HistorySerialization);
647    }
648    emit_option!(PID_RESOURCE_LIMITS, resource_limits, policy::ResourceLimits);
649    emit_option!(PID_LIFESPAN, lifespan, policy::Lifespan);
650    emit_option!(
651      PID_DATA_REPRESENTATION,
652      data_representation,
653      policy::DataRepresentation
654    );
655
656    Ok(pl)
657  }
658
659  pub fn from_parameter_list(
660    ctx: speedy::Endianness,
661    pl_map: &BTreeMap<ParameterId, Vec<&Parameter>>,
662  ) -> Result<QosPolicies, PlCdrDeserializeError> {
663    macro_rules! get_option {
664      ($pid:ident) => {
665        get_option_from_pl_map(pl_map, ctx, ParameterId::$pid, "<not_used>")?
666      };
667    }
668
669    let durability: Option<policy::Durability> = get_option!(PID_DURABILITY);
670    let presentation: Option<policy::Presentation> = get_option!(PID_PRESENTATION);
671    let deadline: Option<policy::Deadline> = get_option!(PID_DEADLINE);
672    let latency_budget: Option<policy::LatencyBudget> = get_option!(PID_LATENCY_BUDGET);
673
674    // Ownership is in 2 parts
675    let ownership_kind: Option<OwnershipKind> = get_option!(PID_OWNERSHIP);
676    let ownership_strength: Option<i32> = get_option!(PID_OWNERSHIP_STRENGTH);
677    let ownership = match (ownership_kind, ownership_strength) {
678      (Some(OwnershipKind::Shared), None) => Some(policy::Ownership::Shared),
679      (Some(OwnershipKind::Shared), Some(_strength)) => {
680        warn!("QosPolicies deserializer: Received OwnershipKind::Shared and a strength value.");
681        None
682      }
683      (Some(OwnershipKind::Exclusive), Some(strength)) => {
684        Some(policy::Ownership::Exclusive { strength })
685      }
686      (Some(OwnershipKind::Exclusive), None) => {
687        warn!("QosPolicies deserializer: Received OwnershipKind::Exclusive but no strength value.");
688        None
689      }
690      (None, Some(_strength)) => {
691        warn!(
692          "QosPolicies deserializer: Received ownership strength value, but no kind parameter."
693        );
694        None
695      }
696      (None, None) => None,
697    };
698
699    let reliability_ser: Option<ReliabilitySerialization> = get_option!(PID_RELIABILITY);
700    let reliability = reliability_ser.map(|rs| match rs.reliability_kind {
701      ReliabilityKind::BestEffort => policy::Reliability::BestEffort,
702      ReliabilityKind::Reliable => policy::Reliability::Reliable {
703        max_blocking_time: rs.max_blocking_time,
704      },
705    });
706    let destination_order: Option<policy::DestinationOrder> = get_option!(PID_DESTINATION_ORDER);
707
708    let history_ser: Option<HistorySerialization> = get_option!(PID_HISTORY);
709    let history = history_ser.map(|h| match h.kind {
710      HistoryKind::KeepAll => policy::History::KeepAll,
711      HistoryKind::KeepLast => policy::History::KeepLast { depth: h.depth },
712    });
713
714    let liveliness: Option<policy::Liveliness> = get_option!(PID_LIVELINESS);
715    let time_based_filter: Option<policy::TimeBasedFilter> = get_option!(PID_TIME_BASED_FILTER);
716
717    let resource_limits: Option<policy::ResourceLimits> = get_option!(PID_RESOURCE_LIMITS);
718    let lifespan: Option<policy::Lifespan> = get_option!(PID_LIFESPAN);
719    let data_representation: Option<policy::DataRepresentation> =
720      get_option!(PID_DATA_REPRESENTATION);
721
722    #[cfg(feature = "security")]
723    let property: Option<policy::Property> = None; // TODO: Should also properties be read?
724
725    // We construct using the struct syntax directly rather than the builder,
726    // so we cannot forget any field.
727    Ok(QosPolicies {
728      durability,
729      presentation,
730      deadline,
731      latency_budget,
732      ownership,
733      liveliness,
734      time_based_filter,
735      reliability,
736      destination_order,
737      history,
738      resource_limits,
739      lifespan,
740      data_representation,
741      #[cfg(feature = "security")]
742      property,
743    })
744  }
745}
746
747#[derive(Writable, Readable, Clone)]
748//#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
749enum HistoryKind {
750  KeepLast,
751  KeepAll,
752}
753
754#[derive(Writable, Readable, Clone)]
755struct HistorySerialization {
756  pub kind: HistoryKind,
757  pub depth: i32,
758}
759
760#[derive(Writable, Readable)]
761//#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
762enum OwnershipKind {
763  Shared,
764  Exclusive,
765}
766
767#[derive(Writable, Readable, Clone)]
768struct ReliabilitySerialization {
769  pub reliability_kind: ReliabilityKind,
770  pub max_blocking_time: Duration,
771}
772
773// DDS spec v1.4 p.139
774// TODO: Replace this with Option construct so that
775// None means no limit and Some(limit) gives the limit when defined.
776// Use is in resource_limits.
777pub const LENGTH_UNLIMITED: i32 = -1;
778
779// put these into a submodule to avoid repeating the word "policy" or
780// "qospolicy"
781/// Contains all available QoSPolicies
782pub mod policy {
783  use std::cmp::Ordering;
784
785  use speedy::{Readable, Writable};
786  use serde::{Deserialize, Serialize};
787  #[allow(unused_imports)]
788  use log::{debug, error, info, trace, warn};
789  #[cfg(feature = "security")]
790  use speedy::{Context, IsEof, Reader, Writer};
791
792  use crate::structure::duration::Duration;
793  #[cfg(feature = "security")]
794  use crate::serialization::speedy_pl_cdr_helpers::*;
795
796  /*
797  pub struct UserData {
798    pub value: Vec<u8>,
799  }
800
801  pub struct TopicData {
802    pub value: Vec<u8>,
803  }
804
805  pub struct GroupData {
806    pub value: Vec<u8>,
807  }
808
809  pub struct TransportPriority {
810    pub value: i32,
811  }
812  */
813
814  /// DDS 2.2.3.16 LIFESPAN
815  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Readable, Writable, Serialize, Deserialize)]
816  pub struct Lifespan {
817    pub duration: Duration,
818  }
819
820  /// DDS 2.2.3.4 DURABILITY
821  ///
822  /// DDS Spec 1.4:
823  ///
824  /// "This QoS policy controls whether the Service will actually make data
825  /// available to late-joining readers. Note that although related, this does
826  /// not strictly control what data the Service will maintain internally. That
827  /// is, the Service may choose to maintain some data for its own purposes
828  /// (e.g., flow control) and yet not make it available to late-joining readers
829  /// if the DURABILITY QoS policy is set to VOLATILE."
830  #[derive(
831    Copy,
832    Clone,
833    Debug,
834    PartialEq,
835    Eq,
836    PartialOrd,
837    Ord,
838    Hash,
839    Readable,
840    Writable,
841    Serialize,
842    Deserialize,
843  )]
844  pub enum Durability {
845    Volatile,
846    TransientLocal,
847    Transient,
848    Persistent,
849  }
850
851  /// DDS 2.2.3.6 PRESENTATION
852  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Readable, Writable, Serialize, Deserialize)]
853  pub struct Presentation {
854    pub access_scope: PresentationAccessScope,
855    pub coherent_access: bool,
856    pub ordered_access: bool,
857  }
858
859  /// Access scope that is part of DDS 2.2.3.6 PRESENTATION
860  #[derive(
861    Copy,
862    Clone,
863    Debug,
864    PartialEq,
865    Eq,
866    PartialOrd,
867    Ord,
868    Hash,
869    Readable,
870    Writable,
871    Serialize,
872    Deserialize,
873  )]
874  pub enum PresentationAccessScope {
875    Instance,
876    Topic,
877    Group,
878  }
879
880  /// DDS 2.2.3.7 DEADLINE
881  #[derive(
882    Copy,
883    Clone,
884    Debug,
885    PartialEq,
886    Eq,
887    Ord,
888    PartialOrd,
889    Hash,
890    Readable,
891    Writable,
892    Serialize,
893    Deserialize,
894  )]
895  pub struct Deadline(pub Duration);
896
897  /// DDS 2.2.3.8 LATENCY_BUDGET
898  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Readable, Writable, Serialize, Deserialize)]
899  pub struct LatencyBudget {
900    pub duration: Duration,
901  }
902
903  /// DDS 2.2.3.9 OWNERSHIP
904  ///
905  /// # Support status / known limitation
906  ///
907  /// RustDDS uses OWNERSHIP only for **matching**: a `Shared` endpoint and an
908  /// `Exclusive` endpoint are incompatible (`INCOMPATIBLE_QOS`), while the
909  /// `strength` value does *not* affect matching (it is a writer-only policy,
910  /// DDS spec v1.4 ยง2.2.3.10).
911  ///
912  /// RustDDS does **not** implement EXCLUSIVE-ownership *delivery filtering*.
913  /// When several EXCLUSIVE writers publish to the **same instance**, a correct
914  /// implementation would deliver only the samples of the highest-strength
915  /// live writer (with owner hand-off on liveliness loss / unregister). RustDDS
916  /// instead delivers samples from all matched writers. Consequently a reader
917  /// sees data from every EXCLUSIVE writer regardless of `strength`.
918  ///
919  /// This surfaces in the dds-rtps interoperability suite as the single failing
920  /// ownership case `Test_Ownership_3` (two same-instance EXCLUSIVE writers,
921  /// expected `RECEIVING_FROM_ONE`, RustDDS yields `RECEIVING_FROM_BOTH`). All
922  /// other ownership cases pass. Implementing per-instance owner tracking would
923  /// remove this limitation.
924  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
925  pub enum Ownership {
926    Shared,
927    Exclusive { strength: i32 }, // This also implements OwnershipStrength
928  }
929
930  /// Identifier of a data representation, per DDS-XTypes v1.3 Section 7.6.3.1.
931  pub type DataRepresentationId = i16;
932
933  /// Extensible CDR encoding version 1 (the DDS default).
934  pub const XCDR_DATA_REPRESENTATION: DataRepresentationId = 0;
935  /// XML data representation (not supported by RustDDS).
936  pub const XML_DATA_REPRESENTATION: DataRepresentationId = 1;
937  /// Extensible CDR encoding version 2 (not supported by RustDDS).
938  pub const XCDR2_DATA_REPRESENTATION: DataRepresentationId = 2;
939
940  /// DDS-XTypes v1.3 Section 7.6.3.1 DATA_REPRESENTATION QoS policy.
941  ///
942  /// A DataWriter offers a single data representation (the first element of the
943  /// list, or XCDR1 if the list is empty). A DataReader requests one or more
944  /// accepted representations. The policies are compatible when the writer's
945  /// offered representation is contained in the reader's requested list.
946  ///
947  /// On the wire this is `PID_DATA_REPRESENTATION` (0x0073), a CDR
948  /// `sequence<int16>`.
949  #[derive(Clone, Debug, PartialEq, Eq, Hash, Readable, Writable, Serialize, Deserialize)]
950  pub struct DataRepresentation {
951    pub value: Vec<DataRepresentationId>,
952  }
953
954  impl DataRepresentation {
955    /// The single representation a DataWriter with this (optional) policy uses:
956    /// the first list element, or XCDR1 when absent/empty (DDS-XTypes
957    /// 7.6.3.1.1).
958    pub fn offered_representation(maybe: Option<&DataRepresentation>) -> DataRepresentationId {
959      maybe
960        .and_then(|dr| dr.value.first().copied())
961        .unwrap_or(XCDR_DATA_REPRESENTATION)
962    }
963
964    /// The representations a DataReader with this (optional) policy accepts:
965    /// the list, or `[XCDR1]` when absent/empty (DDS-XTypes 7.6.3.1.1).
966    pub fn accepted_representations(
967      maybe: Option<&DataRepresentation>,
968    ) -> Vec<DataRepresentationId> {
969      match maybe {
970        Some(dr) if !dr.value.is_empty() => dr.value.clone(),
971        _ => vec![XCDR_DATA_REPRESENTATION],
972      }
973    }
974  }
975
976  /// DDS 2.2.3.11 LIVELINESS
977  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Readable, Writable, Serialize, Deserialize)]
978  pub enum Liveliness {
979    Automatic { lease_duration: Duration },
980    ManualByParticipant { lease_duration: Duration },
981    ManualByTopic { lease_duration: Duration },
982  }
983
984  impl Liveliness {
985    fn kind_num(&self) -> i32 {
986      match self {
987        Self::Automatic { .. } => 0,
988        Self::ManualByParticipant { .. } => 1,
989        Self::ManualByTopic { .. } => 2,
990      }
991    }
992
993    pub fn duration(&self) -> Duration {
994      match self {
995        Self::Automatic { lease_duration }
996        | Self::ManualByParticipant { lease_duration }
997        | Self::ManualByTopic { lease_duration } => *lease_duration,
998      }
999    }
1000  }
1001
1002  impl Ord for Liveliness {
1003    fn cmp(&self, other: &Self) -> Ordering {
1004      // Manual liveliness is greater than automatic, but
1005      // duration compares in reverse
1006      other
1007        .kind_num()
1008        .cmp(&other.kind_num())
1009        .then_with(|| self.duration().cmp(&other.duration()).reverse())
1010    }
1011  }
1012
1013  impl PartialOrd for Liveliness {
1014    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1015      Some(self.cmp(other))
1016    }
1017  }
1018
1019  /// DDS 2.2.3.12 TIME_BASED_FILTER
1020  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Readable, Writable, Serialize, Deserialize)]
1021  pub struct TimeBasedFilter {
1022    pub minimum_separation: Duration,
1023  }
1024
1025  /*
1026  pub struct Partition {
1027    pub name: Vec<Vec<u8>>,
1028  }
1029  */
1030
1031  /// DDS 2.2.3.14 RELIABILITY
1032  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
1033  pub enum Reliability {
1034    BestEffort,
1035    Reliable { max_blocking_time: Duration },
1036  }
1037
1038  impl Ord for Reliability {
1039    // max_blocking_time is not compared.
1040    // TODO: This is kind of bad, because now Eq and Ord are inconsistent:
1041    // If we have A and B both Reliability::Reliable, but with different
1042    // max_blocking_time, then Ord will say they are Ordering::Equal,
1043    // but Eq will say they are not equal.
1044    fn cmp(&self, other: &Self) -> Ordering {
1045      match (self, other) {
1046        (Self::BestEffort, Self::BestEffort) | (Self::Reliable { .. }, Self::Reliable { .. }) => {
1047          Ordering::Equal
1048        }
1049        (Self::BestEffort, Self::Reliable { .. }) => Ordering::Less,
1050        (Self::Reliable { .. }, Self::BestEffort) => Ordering::Greater,
1051      }
1052    }
1053  }
1054
1055  impl PartialOrd for Reliability {
1056    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1057      Some(self.cmp(other))
1058    }
1059  }
1060
1061  /// DDS 2.2.3.17 DESTINATION_ORDER
1062  #[derive(
1063    Copy,
1064    Clone,
1065    Debug,
1066    PartialEq,
1067    Eq,
1068    Ord,
1069    PartialOrd,
1070    Hash,
1071    Readable,
1072    Writable,
1073    Serialize,
1074    Deserialize,
1075  )]
1076  pub enum DestinationOrder {
1077    ByReceptionTimestamp,
1078    BySourceTimeStamp,
1079  }
1080
1081  /// DDS 2.2.3.18 HISTORY
1082  #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
1083  pub enum History {
1084    // Variants must be in this order ot derive Ord correctly.
1085    KeepLast { depth: i32 },
1086    KeepAll,
1087  }
1088
1089  /// DDS Spec v1.4 Section 2.2.3.19 RESOURCE_LIMITS
1090  ///
1091  /// DDS Spec v1.4 p.147 "struct ResourceLimitsQosPolicy" defines the
1092  /// fields as "long". The "long" type of OMG IDL is defined to have
1093  /// 32-bit (signed, 2's complement) range in the OMG IDL spec v4.2, Table
1094  /// 7-13: Integer Types.
1095  ///
1096  /// But it does not make sense to have negative limits, so these should be
1097  /// unsigned.
1098  ///
1099  /// Negative values are needed, because DDS spec defines the special value
1100  /// const long LENGTH_UNLIMITED = -1;
1101  #[derive(Copy, Clone, Debug, PartialEq, Eq, Writable, Readable, Serialize, Deserialize)]
1102  pub struct ResourceLimits {
1103    pub max_samples: i32,
1104    pub max_instances: i32,
1105    pub max_samples_per_instance: i32,
1106  }
1107
1108  #[cfg(feature = "security")]
1109  use crate::security;
1110  // DDS Security spec v1.1
1111  // Section 7.2.5 PropertyQosPolicy, DomainParticipantQos, DataWriterQos, and
1112  // DataReaderQos
1113  #[cfg(feature = "security")]
1114  #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
1115  pub struct Property {
1116    pub value: Vec<security::types::Property>,
1117    pub binary_value: Vec<security::types::BinaryProperty>,
1118  }
1119
1120  #[cfg(feature = "security")]
1121  impl<'a, C: Context> Readable<'a, C> for Property {
1122    fn minimum_bytes_needed() -> usize {
1123      4
1124    }
1125
1126    fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
1127      let count = reader.read_u32()?;
1128      let mut value = Vec::new();
1129
1130      let mut prev_len = 0;
1131      for _ in 0..count {
1132        read_pad(reader, prev_len, 4)?;
1133        let s: security::types::Property = reader.read_value()?;
1134        prev_len = s.serialized_len();
1135        value.push(s);
1136      }
1137
1138      // Depending on the RTPS version used by writer, PropertyQoSPolicy may end here,
1139      // i.e. there is no "binary_value". Pad should still always exist.
1140      read_pad(reader, prev_len, 4)?;
1141      let mut binary_value = Vec::new();
1142
1143      match reader.read_u32() {
1144        Ok(count) => {
1145          prev_len = 0;
1146          for _ in 0..count {
1147            read_pad(reader, prev_len, 4)?;
1148            let s: security::types::BinaryProperty = reader.read_value()?;
1149            prev_len = s.serialized_len();
1150            binary_value.push(s);
1151          }
1152        }
1153        Err(e) => {
1154          if e.is_eof() {
1155            // This is ok. Only String properties, no binary.
1156            debug!("Non-security PropertyQosPolicy");
1157          } else {
1158            return Err(e);
1159          }
1160        }
1161      }
1162
1163      Ok(Property {
1164        value,
1165        binary_value,
1166      })
1167    }
1168  }
1169
1170  // Writing several strings is a bit complicated, because
1171  // we have to keep track of alignment.
1172  // Again, alignment comes BEFORE string length, or vector item count, not after
1173  // string.
1174  #[cfg(feature = "security")]
1175  impl<C: Context> Writable<C> for Property {
1176    fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
1177      // First self.value
1178      // Only those properties with propagate=true are written
1179      let propagate_value: Vec<&security::Property> =
1180        self.value.iter().filter(|p| p.propagate).collect();
1181
1182      // propagate_value vector length
1183      writer.write_u32(propagate_value.len() as u32)?;
1184
1185      let mut prev_len = 0;
1186      for prop in propagate_value {
1187        write_pad(writer, prev_len, 4)?;
1188        writer.write_value(prop)?;
1189        prev_len = prop.serialized_len();
1190      }
1191
1192      // Then self.bin_value
1193      // Only those binary properties with propagate=true are written
1194      let propagate_bin_value: Vec<&security::BinaryProperty> =
1195        self.binary_value.iter().filter(|p| p.propagate).collect();
1196
1197      // propagate_bin_value vector length
1198      write_pad(writer, prev_len, 4)?;
1199      writer.write_u32(propagate_bin_value.len() as u32)?;
1200      // and the elements
1201      let mut prev_len = 0;
1202      for prop in propagate_bin_value {
1203        write_pad(writer, prev_len, 4)?;
1204        writer.write_value(prop)?;
1205        prev_len = prop.serialized_len();
1206      }
1207
1208      Ok(())
1209    }
1210  }
1211
1212  // DDS Security spec v1.1
1213  // Section 7.2.5 PropertyQosPolicy, DomainParticipantQos, DataWriterQos, and
1214  // DataReaderQos
1215  //
1216  // so this is DataTagQosPolicy, which is an alias for "DataTags"
1217  // We call it qos::policy::DataTag
1218  #[derive(Clone, Debug, PartialEq, Eq, Default)]
1219  #[cfg(feature = "security")]
1220  pub struct DataTag {
1221    pub tags: Vec<security::types::Tag>,
1222  }
1223
1224  #[cfg(feature = "security")]
1225  impl<'a, C: Context> Readable<'a, C> for DataTag {
1226    fn minimum_bytes_needed() -> usize {
1227      4
1228    }
1229
1230    fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
1231      let count = reader.read_u32()?;
1232      let mut tags = Vec::new();
1233
1234      let mut prev_len = 0;
1235      for _ in 0..count {
1236        read_pad(reader, prev_len, 4)?;
1237        let s: security::types::Tag = reader.read_value()?;
1238        prev_len = s.serialized_len();
1239        tags.push(s);
1240      }
1241      Ok(DataTag { tags })
1242    }
1243  }
1244
1245  // Writing several strings is a bit complicated, because
1246  // we have to keep track of alignment.
1247  // Again, alignment comes BEFORE string length, or vector item count, not after
1248  // string.
1249  #[cfg(feature = "security")]
1250  impl<C: Context> Writable<C> for DataTag {
1251    fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
1252      writer.write_u32(self.tags.len() as u32)?;
1253
1254      let mut prev_len = 0;
1255      for tag in &self.tags {
1256        write_pad(writer, prev_len, 4)?;
1257        writer.write_value(tag)?;
1258        prev_len = tag.serialized_len();
1259      }
1260      Ok(())
1261    }
1262  }
1263} // mod policy