Skip to main content

cyclonedds/
status.rs

1//! Event metadata types delivered to DDS listener callbacks.
2//!
3//! Each type corresponds to a status condition defined in the DCPS
4//! specification and carries event-specific detail such as counts and instance
5//! handles. See the [`listener`](crate::listener) module for how to register
6//! callbacks that receive these types.
7
8pub(crate) mod bitflags {
9    bitflags::bitflags! {
10        /// Flags for specifying the set of statuses that are of interest.
11        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12        pub struct Status: u32 {
13            /// Another topic exists with the same name but with different
14            /// characteristics. Also see the [`crate::status::InconsistentTopic`] metadata struct.
15            const InconsistentTopic =
16                1 << cyclonedds_sys::dds_status_id_DDS_INCONSISTENT_TOPIC_STATUS_ID;
17            /// The deadline that the writer has committed through its
18            /// [`Deadline`](crate::qos::policy::Deadline) policy was not
19            /// respected for a specific instance. Also see the [`crate::status::OfferedDeadlineMissed`] metadata struct.
20            const OfferedDeadlineMissed =
21                1 << cyclonedds_sys::dds_status_id_DDS_OFFERED_DEADLINE_MISSED_STATUS_ID;
22            /// The deadline that the reader was expecting through its
23            /// [`Deadline`](crate::qos::policy::Deadline) policy was not
24            /// respected for a specific instance. Also see the [`crate::status::RequestedDeadlineMissed`] metadata struct.
25            const RequestedDeadlineMissed =
26                1 << cyclonedds_sys::dds_status_id_DDS_REQUESTED_DEADLINE_MISSED_STATUS_ID;
27            /// A [`QoS`](crate::QoS) policy setting was incompatible with what
28            /// was requested. Also see the [`crate::status::OfferedIncompatibleQoS`] metadata struct.
29            const OfferedIncompatibleQoS =
30                1 << cyclonedds_sys::dds_status_id_DDS_OFFERED_INCOMPATIBLE_QOS_STATUS_ID;
31            /// A [`QoS`](crate::QoS) policy setting was incompatible with what
32            /// is offered. Also see the [`crate::status::RequestedIncompatibleQoS`] metadata struct.
33            const RequestedIncompatibleQoS =
34                1 << cyclonedds_sys::dds_status_id_DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS_ID;
35            /// A sample has been lost (never received). Also see the [`crate::status::SampleLost`] metadata struct.
36            const SampleLost =
37                1 << cyclonedds_sys::dds_status_id_DDS_SAMPLE_LOST_STATUS_ID;
38            /// A received sample has been rejected. Also see the [`crate::status::SampleRejected`] metadata struct.
39            const SampleRejected =
40                1 << cyclonedds_sys::dds_status_id_DDS_SAMPLE_REJECTED_STATUS_ID;
41            /// New information is available in some of the data readers of a
42            /// subscriber.
43            const DataOnReaders =
44                1 << cyclonedds_sys::dds_status_id_DDS_DATA_ON_READERS_STATUS_ID;
45            /// New information is available in a data reader.
46            const DataAvailable =
47                1 << cyclonedds_sys::dds_status_id_DDS_DATA_AVAILABLE_STATUS_ID;
48            /// The liveliness that the writer has committed through its
49            /// [`Liveliness`](crate::qos::policy::Liveliness) policy was not
50            /// respected; thus readers will consider the writer as no longer
51            /// "alive". Also see the [`crate::status::LivelinessLost`] metadata struct.
52            const LivelinessLost =
53                1 << cyclonedds_sys::dds_status_id_DDS_LIVELINESS_LOST_STATUS_ID;
54            /// The liveliness of one or more writers, that were writing instances
55            /// read through the readers has changed. Some writers have become
56            /// "alive" or "not alive". Also see the [`crate::status::LivelinessChanged`] metadata struct.
57            const LivelinessChanged =
58                1 << cyclonedds_sys::dds_status_id_DDS_LIVELINESS_CHANGED_STATUS_ID;
59            /// The writer has found a reader that matches the topic and has a
60            /// compatible [`QoS`](crate::QoS). Also see the [`crate::status::PublicationMatched`] metadata struct.
61            const PublicationMatched =
62                1 << cyclonedds_sys::dds_status_id_DDS_PUBLICATION_MATCHED_STATUS_ID;
63            /// The reader has found a writer that matches the topic and has a
64            /// compatible [`QoS`](crate::QoS). Also see the [`crate::status::SubscriptionMatched`] metadata struct.
65            const SubscriptionMatched =
66                1 << cyclonedds_sys::dds_status_id_DDS_SUBSCRIPTION_MATCHED_STATUS_ID;
67        }
68    }
69}
70
71/// Identifies a DDS [`QoS`](crate::QoS) policy.
72///
73/// Used in incompatible [`QoS`](crate::QoS) status events to report which
74/// policy caused the mismatch between a reader and writer.
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub enum QoSPolicyId {
77    /// No valid policy.
78    Invalid,
79    /// Attaches application-specific data to an entity. See
80    /// [`UserData`](crate::qos::policy::UserData).
81    UserData,
82    /// Controls whether data is stored for late-joining readers. See
83    /// [`Durability`](crate::qos::policy::Durability).
84    Durability,
85    /// Controls the scope and order of data presentation to subscribers. See
86    /// [`Presentation`](crate::qos::policy::Presentation).
87    Presentation,
88    /// The maximum time between successive writes for a given instance. See
89    /// [`Deadline`](crate::qos::policy::Deadline).
90    Deadline,
91    /// The acceptable delay between writing and receiving a sample. See
92    /// [`LatencyBudget`](crate::qos::policy::LatencyBudget).
93    LatencyBudget,
94    /// Controls whether ownership of an instance is shared or exclusive. See
95    /// [`Ownership`](crate::qos::policy::Ownership).
96    Ownership,
97    /// The strength of an exclusive ownership claim.
98    OwnershipStrength,
99    /// How the system determines whether a writer is still alive. See
100    /// [`Liveliness`](crate::qos::policy::Liveliness).
101    Liveliness,
102    /// Filters samples based on the minimum time between delivery to a reader.
103    /// See [`TimeBasedFilter`](crate::qos::policy::TimeBasedFilter).
104    TimeBasedFilter,
105    /// Restricts communication to a named logical channel within a domain. See
106    /// [`Partition`](crate::qos::policy::Partition).
107    Partition,
108    /// Delivery guarantee: best-effort or reliable. See
109    /// [`Reliability`](crate::qos::policy::Reliability).
110    Reliability,
111    /// The order in which samples are delivered to a reader. See
112    /// [`DestinationOrder`](crate::qos::policy::DestinationOrder).
113    DestinationOrder,
114    /// How many samples are stored per instance. See
115    /// [`History`](crate::qos::policy::History).
116    History,
117    /// Caps on the number of instances, samples, and samples-per-instance. See
118    /// [`ResourceLimits`](crate::qos::policy::ResourceLimits).
119    ResourceLimits,
120    /// Controls whether child entities are automatically enabled on creation.
121    /// See [`EntityFactory`](crate::qos::policy::EntityFactory).
122    EntityFactory,
123    /// Controls how a writer handles unregistered instances on deletion. See
124    /// [`WriterDataLifecycle`](crate::qos::policy::WriterDataLifecycle).
125    WriterDataLifecycle,
126    /// Controls how a reader handles instances when matched writers disappear.
127    /// See [`ReaderDataLifecycle`](crate::qos::policy::ReaderDataLifecycle).
128    ReaderDataLifecycle,
129    /// Attaches application-specific data to a topic. See
130    /// [`TopicData`](crate::qos::policy::TopicData).
131    TopicData,
132    /// Attaches application-specific data to a publisher or subscriber. See
133    /// [`GroupData`](crate::qos::policy::GroupData).
134    GroupData,
135    /// A hint to the transport layer about relative priority. See
136    /// [`TransportPriority`](crate::qos::policy::TransportPriority).
137    TransportPriority,
138    /// The maximum duration a sample remains valid. See
139    /// [`Lifespan`](crate::qos::policy::Lifespan).
140    Lifespan,
141    /// Configures the durability service's history and resource limits. See
142    /// [`DurabilityService`](crate::qos::policy::DurabilityService).
143    DurabilityService,
144    /// Attaches key-value properties to an entity.
145    Property,
146    /// Controls type compatibility checking between readers and writers.
147    TypeConsistencyEnforcement,
148    /// The data representation format used for serialization.
149    DataRepresentation,
150}
151
152impl From<u32> for QoSPolicyId {
153    fn from(value: u32) -> Self {
154        // dds_qos_policy_id_t is an enum whose values are signed under Windows
155        // and unsigned otherwise (probably?). This is due to the default value
156        // being used to represented an enum in `clang` and is propagated by
157        // `bindgen`. We want to stabilize these enums to unsigned but need to
158        // cast back to the whatever type is actually being exported based on
159        // the platform.
160        #[allow(clippy::cast_possible_wrap)]
161        match value as cyclonedds_sys::dds_qos_policy_id_t {
162            cyclonedds_sys::dds_qos_policy_id_DDS_INVALID_QOS_POLICY_ID => Self::Invalid,
163            cyclonedds_sys::dds_qos_policy_id_DDS_USERDATA_QOS_POLICY_ID => Self::UserData,
164            cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITY_QOS_POLICY_ID => Self::Durability,
165            cyclonedds_sys::dds_qos_policy_id_DDS_PRESENTATION_QOS_POLICY_ID => Self::Presentation,
166            cyclonedds_sys::dds_qos_policy_id_DDS_DEADLINE_QOS_POLICY_ID => Self::Deadline,
167            cyclonedds_sys::dds_qos_policy_id_DDS_LATENCYBUDGET_QOS_POLICY_ID => {
168                Self::LatencyBudget
169            }
170            cyclonedds_sys::dds_qos_policy_id_DDS_OWNERSHIP_QOS_POLICY_ID => Self::Ownership,
171            cyclonedds_sys::dds_qos_policy_id_DDS_OWNERSHIPSTRENGTH_QOS_POLICY_ID => {
172                Self::OwnershipStrength
173            }
174            cyclonedds_sys::dds_qos_policy_id_DDS_LIVELINESS_QOS_POLICY_ID => Self::Liveliness,
175            cyclonedds_sys::dds_qos_policy_id_DDS_TIMEBASEDFILTER_QOS_POLICY_ID => {
176                Self::TimeBasedFilter
177            }
178            cyclonedds_sys::dds_qos_policy_id_DDS_PARTITION_QOS_POLICY_ID => Self::Partition,
179            cyclonedds_sys::dds_qos_policy_id_DDS_RELIABILITY_QOS_POLICY_ID => Self::Reliability,
180            cyclonedds_sys::dds_qos_policy_id_DDS_DESTINATIONORDER_QOS_POLICY_ID => {
181                Self::DestinationOrder
182            }
183            cyclonedds_sys::dds_qos_policy_id_DDS_HISTORY_QOS_POLICY_ID => Self::History,
184            cyclonedds_sys::dds_qos_policy_id_DDS_RESOURCELIMITS_QOS_POLICY_ID => {
185                Self::ResourceLimits
186            }
187            cyclonedds_sys::dds_qos_policy_id_DDS_ENTITYFACTORY_QOS_POLICY_ID => {
188                Self::EntityFactory
189            }
190            cyclonedds_sys::dds_qos_policy_id_DDS_WRITERDATALIFECYCLE_QOS_POLICY_ID => {
191                Self::WriterDataLifecycle
192            }
193            cyclonedds_sys::dds_qos_policy_id_DDS_READERDATALIFECYCLE_QOS_POLICY_ID => {
194                Self::ReaderDataLifecycle
195            }
196            cyclonedds_sys::dds_qos_policy_id_DDS_TOPICDATA_QOS_POLICY_ID => Self::TopicData,
197            cyclonedds_sys::dds_qos_policy_id_DDS_GROUPDATA_QOS_POLICY_ID => Self::GroupData,
198            cyclonedds_sys::dds_qos_policy_id_DDS_TRANSPORTPRIORITY_QOS_POLICY_ID => {
199                Self::TransportPriority
200            }
201            cyclonedds_sys::dds_qos_policy_id_DDS_LIFESPAN_QOS_POLICY_ID => Self::Lifespan,
202            cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITYSERVICE_QOS_POLICY_ID => {
203                Self::DurabilityService
204            }
205            cyclonedds_sys::dds_qos_policy_id_DDS_PROPERTY_QOS_POLICY_ID => Self::Property,
206            cyclonedds_sys::dds_qos_policy_id_DDS_TYPE_CONSISTENCY_ENFORCEMENT_QOS_POLICY_ID => {
207                Self::TypeConsistencyEnforcement
208            }
209            cyclonedds_sys::dds_qos_policy_id_DDS_DATA_REPRESENTATION_QOS_POLICY_ID => {
210                Self::DataRepresentation
211            }
212            value => unreachable!(
213                "unsupported value: {value} in conversion to {}",
214                std::any::type_name::<Self>()
215            ),
216        }
217    }
218}
219
220/// A cumulative status event counter with a per-notification delta.
221///
222/// Appears in status types to report both the running total of an event and
223/// how many times it occurred since the last time the status was read or taken.
224#[derive(Clone, Copy, Debug, PartialEq, Eq)]
225pub struct Counter {
226    /// Total number of times the event has occurred.
227    pub count: u32,
228    /// Change in `count` since the status was last read or taken.
229    pub delta: i32,
230}
231
232/// Delivered to the
233/// [`with_inconsistent_topic`](crate::listener::TopicListener::with_inconsistent_topic)
234/// callback when a remote topic is discovered with the same name but an
235/// incompatible type or [`QoS`](crate::QoS).
236#[derive(Clone, Copy, Debug, PartialEq, Eq)]
237pub struct InconsistentTopic {
238    /// Running count of inconsistent topic discoveries.
239    pub total: Counter,
240}
241
242/// Delivered to the
243/// [`with_liveliness_lost`](crate::listener::WriterListener::with_liveliness_lost)
244/// callback when the writer fails to meet its
245/// [`Liveliness`](crate::qos::policy::Liveliness) policy and is considered
246/// inactive by matched readers.
247#[derive(Clone, Copy, Debug, PartialEq, Eq)]
248pub struct LivelinessLost {
249    /// Running count of liveliness violations.
250    pub total: Counter,
251}
252
253/// Delivered to the
254/// [`with_offered_deadline_missed`](crate::listener::WriterListener::with_offered_deadline_missed)
255/// callback when the writer fails to write a new sample within its offered
256/// [`Deadline`](crate::qos::policy::Deadline) period for one or more
257/// instances.
258#[derive(Clone, Copy, Debug, PartialEq, Eq)]
259pub struct OfferedDeadlineMissed {
260    /// Running count of deadline violations.
261    pub total: Counter,
262    /// Instance handle of the last instance that missed its deadline.
263    pub last_instance_handle: crate::entity::InstanceHandle,
264}
265
266/// Delivered to the
267/// [`with_offered_incompatible_qos`](crate::listener::WriterListener::with_offered_incompatible_qos)
268/// callback when a reader is discovered whose requested [`QoS`](crate::QoS) is
269/// incompatible with this writer's offered [`QoS`](crate::QoS).
270#[derive(Clone, Copy, Debug, PartialEq, Eq)]
271pub struct OfferedIncompatibleQoS {
272    /// Running count of incompatible [`QoS`](crate::QoS) discoveries.
273    pub total: Counter,
274    /// The policy that caused the most recent incompatibility.
275    pub last_policy_id: QoSPolicyId,
276}
277
278/// Delivered to the
279/// [`with_publication_matched`](crate::listener::WriterListener::with_publication_matched)
280/// callback when a reader matching this writer's topic and [`QoS`](crate::QoS)
281/// is discovered or lost.
282#[derive(Clone, Copy, Debug, PartialEq, Eq)]
283pub struct PublicationMatched {
284    /// Running count of reader matches over the lifetime of the writer.
285    pub total: Counter,
286    /// Current number of matched readers.
287    pub current: Counter,
288    /// Instance handle of the last reader that matched or unmatched.
289    pub last_subscription_handle: crate::entity::InstanceHandle,
290}
291
292/// Delivered to the
293/// [`with_sample_lost`](crate::listener::ReaderListener::with_sample_lost)
294/// callback when a sample is lost before being received by the reader.
295#[derive(Clone, Copy, Debug, PartialEq, Eq)]
296pub struct SampleLost {
297    /// Running count of lost samples.
298    pub total: Counter,
299}
300
301/// Delivered to the
302/// [`with_sample_rejected`](crate::listener::ReaderListener::with_sample_rejected)
303/// callback when an incoming sample is rejected due to [`resource
304/// limits`](crate::qos::policy::ResourceLimits).
305#[derive(Debug, Copy, Clone, PartialEq, Eq)]
306pub enum SampleRejectedReason {
307    /// The sample was not rejected.
308    NotRejected,
309    /// Rejected because the maximum number of instances has been reached.
310    RejectedByInstancesLimit,
311    /// Rejected because the maximum number of samples has been reached.
312    RejectedBySamplesLimit,
313    /// Rejected because the maximum number of samples per instance has been
314    /// reached.
315    RejectedBySamplesPerInstanceLimit,
316}
317
318impl From<cyclonedds_sys::dds_sample_rejected_status_kind> for SampleRejectedReason {
319    fn from(reason: cyclonedds_sys::dds_sample_rejected_status_kind) -> Self {
320        match reason {
321            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_NOT_REJECTED => Self::NotRejected,
322            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_INSTANCES_LIMIT => Self::RejectedByInstancesLimit,
323            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_LIMIT => Self::RejectedBySamplesLimit,
324            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT => Self::RejectedBySamplesPerInstanceLimit,
325            value => unreachable!("unsupported value: {value} in conversion to {}", std::any::type_name::<Self>())
326        }
327    }
328}
329
330/// Delivered to the
331/// [`with_sample_rejected`](crate::listener::ReaderListener::with_sample_rejected)
332/// callback.
333#[derive(Clone, Copy, Debug, PartialEq, Eq)]
334pub struct SampleRejected {
335    /// Running count of rejected samples.
336    pub total: Counter,
337    /// The reason the most recent sample was rejected.
338    pub last_reason: SampleRejectedReason,
339    /// Instance handle of the instance whose sample was most recently rejected.
340    pub last_instance_handle: crate::entity::InstanceHandle,
341}
342
343/// Delivered to the
344/// [`with_requested_deadline_missed`](crate::listener::ReaderListener::with_requested_deadline_missed)
345/// callback when a sample is not received within the
346/// [`Deadline`](crate::qos::policy::Deadline) period offered by a matched
347/// writer.
348#[derive(Clone, Copy, Debug, PartialEq, Eq)]
349pub struct RequestedDeadlineMissed {
350    /// Running count of deadline misses across all instances.
351    pub total: Counter,
352    /// Instance handle of the last instance that missed its deadline.
353    pub last_instance_handle: crate::entity::InstanceHandle,
354}
355
356/// Delivered to the
357/// [`with_requested_incompatible_qos`](crate::listener::ReaderListener::with_requested_incompatible_qos)
358/// callback when a writer is discovered whose offered [`QoS`](crate::QoS) is
359/// incompatible with this reader's requested [`QoS`](crate::QoS).
360#[derive(Clone, Copy, Debug, PartialEq, Eq)]
361pub struct RequestedIncompatibleQoS {
362    /// Running count of incompatible [`QoS`](crate::QoS) discoveries.
363    pub total: Counter,
364    /// The policy that caused the most recent incompatibility.
365    pub last_policy_id: QoSPolicyId,
366}
367
368/// Delivered to the
369/// [`with_subscription_matched`](crate::listener::ReaderListener::with_subscription_matched)
370/// callback when a writer matching this reader's topic and [`QoS`](crate::QoS)
371/// is discovered.
372#[derive(Clone, Copy, Debug, PartialEq, Eq)]
373pub struct SubscriptionMatched {
374    /// Running count of writer matches over the lifetime of the reader.
375    pub total: Counter,
376    /// Current number of matched writers.
377    pub current: Counter,
378    /// Instance handle of the last writer that matched or unmatched.
379    pub last_publication_handle: crate::entity::InstanceHandle,
380}
381
382/// Delivered to the
383/// [`with_liveliness_changed`](crate::listener::ReaderListener::with_liveliness_changed)
384/// callback when a matched writer transitions between active and inactive.
385#[derive(Clone, Copy, Debug, PartialEq, Eq)]
386pub struct LivelinessChanged {
387    /// Running count of matched writers that are currently active.
388    pub alive: Counter,
389    /// Running count of matched writers that are currently inactive.
390    pub not_alive: Counter,
391    /// Instance handle of the last writer whose liveliness changed.
392    pub last_publication_handle: crate::entity::InstanceHandle,
393}
394
395impl From<cyclonedds_sys::dds_inconsistent_topic_status> for InconsistentTopic {
396    fn from(status: cyclonedds_sys::dds_inconsistent_topic_status) -> Self {
397        let total = Counter {
398            count: status.total_count,
399            delta: status.total_count_change,
400        };
401
402        Self { total }
403    }
404}
405
406impl From<cyclonedds_sys::dds_liveliness_lost_status_t> for LivelinessLost {
407    fn from(status: cyclonedds_sys::dds_liveliness_lost_status_t) -> Self {
408        let total = Counter {
409            count: status.total_count,
410            delta: status.total_count_change,
411        };
412        Self { total }
413    }
414}
415
416impl From<cyclonedds_sys::dds_offered_deadline_missed_status_t> for OfferedDeadlineMissed {
417    fn from(status: cyclonedds_sys::dds_offered_deadline_missed_status_t) -> Self {
418        let total = Counter {
419            count: status.total_count,
420            delta: status.total_count_change,
421        };
422        let last_instance_handle = crate::entity::InstanceHandle {
423            inner: status.last_instance_handle,
424        };
425
426        Self {
427            total,
428            last_instance_handle,
429        }
430    }
431}
432
433impl From<cyclonedds_sys::dds_offered_incompatible_qos_status_t> for OfferedIncompatibleQoS {
434    fn from(status: cyclonedds_sys::dds_offered_incompatible_qos_status_t) -> Self {
435        let total = Counter {
436            count: status.total_count,
437            delta: status.total_count_change,
438        };
439        let last_policy_id = status.last_policy_id.into();
440
441        Self {
442            total,
443            last_policy_id,
444        }
445    }
446}
447
448impl From<cyclonedds_sys::dds_publication_matched_status_t> for PublicationMatched {
449    fn from(status: cyclonedds_sys::dds_publication_matched_status_t) -> Self {
450        let total = Counter {
451            count: status.total_count,
452            delta: status.total_count_change,
453        };
454        let current = Counter {
455            count: status.current_count,
456            delta: status.current_count_change,
457        };
458        let last_subscription_handle = crate::entity::InstanceHandle {
459            inner: status.last_subscription_handle,
460        };
461        Self {
462            total,
463            current,
464            last_subscription_handle,
465        }
466    }
467}
468
469impl From<cyclonedds_sys::dds_sample_lost_status_t> for SampleLost {
470    fn from(status: cyclonedds_sys::dds_sample_lost_status_t) -> Self {
471        let total = Counter {
472            count: status.total_count,
473            delta: status.total_count_change,
474        };
475        Self { total }
476    }
477}
478
479impl From<cyclonedds_sys::dds_sample_rejected_status_t> for SampleRejected {
480    fn from(status: cyclonedds_sys::dds_sample_rejected_status_t) -> Self {
481        let total = Counter {
482            count: status.total_count,
483            delta: status.total_count_change,
484        };
485        let last_reason = status.last_reason.into();
486        let last_instance_handle = crate::entity::InstanceHandle {
487            inner: status.last_instance_handle,
488        };
489        Self {
490            total,
491            last_reason,
492            last_instance_handle,
493        }
494    }
495}
496
497impl From<cyclonedds_sys::dds_liveliness_changed_status_t> for LivelinessChanged {
498    fn from(status: cyclonedds_sys::dds_liveliness_changed_status_t) -> Self {
499        let alive = Counter {
500            count: status.alive_count,
501            delta: status.alive_count_change,
502        };
503        let not_alive = Counter {
504            count: status.not_alive_count,
505            delta: status.not_alive_count_change,
506        };
507
508        let last_publication_handle = crate::entity::InstanceHandle {
509            inner: status.last_publication_handle,
510        };
511        Self {
512            alive,
513            not_alive,
514            last_publication_handle,
515        }
516    }
517}
518
519impl From<cyclonedds_sys::dds_requested_deadline_missed_status_t> for RequestedDeadlineMissed {
520    fn from(status: cyclonedds_sys::dds_requested_deadline_missed_status_t) -> Self {
521        let total = Counter {
522            count: status.total_count,
523            delta: status.total_count_change,
524        };
525        let last_instance_handle = crate::entity::InstanceHandle {
526            inner: status.last_instance_handle,
527        };
528        Self {
529            total,
530            last_instance_handle,
531        }
532    }
533}
534
535impl From<cyclonedds_sys::dds_requested_incompatible_qos_status_t> for RequestedIncompatibleQoS {
536    fn from(status: cyclonedds_sys::dds_requested_incompatible_qos_status_t) -> Self {
537        let total = Counter {
538            count: status.total_count,
539            delta: status.total_count_change,
540        };
541        let last_policy_id = status.last_policy_id.into();
542        Self {
543            total,
544            last_policy_id,
545        }
546    }
547}
548
549impl From<cyclonedds_sys::dds_subscription_matched_status_t> for SubscriptionMatched {
550    fn from(status: cyclonedds_sys::dds_subscription_matched_status_t) -> Self {
551        let total = Counter {
552            count: status.total_count,
553            delta: status.total_count_change,
554        };
555        let current = Counter {
556            count: status.current_count,
557            delta: status.current_count_change,
558        };
559        let last_publication_handle = crate::entity::InstanceHandle {
560            inner: status.last_publication_handle,
561        };
562
563        Self {
564            total,
565            current,
566            last_publication_handle,
567        }
568    }
569}
570
571#[cfg(test)]
572mod tests {
573    use super::*;
574
575    #[test]
576    fn test_qos_policy_id_conversion() {
577        let result =
578            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_INVALID_QOS_POLICY_ID as u32);
579        assert_eq!(result, QoSPolicyId::Invalid);
580        let result =
581            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_USERDATA_QOS_POLICY_ID as u32);
582        assert_eq!(result, QoSPolicyId::UserData);
583        let result = QoSPolicyId::from(
584            cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITY_QOS_POLICY_ID as u32,
585        );
586        assert_eq!(result, QoSPolicyId::Durability);
587        let result = QoSPolicyId::from(
588            cyclonedds_sys::dds_qos_policy_id_DDS_PRESENTATION_QOS_POLICY_ID as u32,
589        );
590        assert_eq!(result, QoSPolicyId::Presentation);
591        let result =
592            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_DEADLINE_QOS_POLICY_ID as u32);
593        assert_eq!(result, QoSPolicyId::Deadline);
594        let result = QoSPolicyId::from(
595            cyclonedds_sys::dds_qos_policy_id_DDS_LATENCYBUDGET_QOS_POLICY_ID as u32,
596        );
597        assert_eq!(result, QoSPolicyId::LatencyBudget);
598        let result =
599            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_OWNERSHIP_QOS_POLICY_ID as u32);
600        assert_eq!(result, QoSPolicyId::Ownership);
601        let result = QoSPolicyId::from(
602            cyclonedds_sys::dds_qos_policy_id_DDS_OWNERSHIPSTRENGTH_QOS_POLICY_ID as u32,
603        );
604        assert_eq!(result, QoSPolicyId::OwnershipStrength);
605        let result = QoSPolicyId::from(
606            cyclonedds_sys::dds_qos_policy_id_DDS_LIVELINESS_QOS_POLICY_ID as u32,
607        );
608        assert_eq!(result, QoSPolicyId::Liveliness);
609        let result = QoSPolicyId::from(
610            cyclonedds_sys::dds_qos_policy_id_DDS_TIMEBASEDFILTER_QOS_POLICY_ID as u32,
611        );
612        assert_eq!(result, QoSPolicyId::TimeBasedFilter);
613        let result =
614            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_PARTITION_QOS_POLICY_ID as u32);
615        assert_eq!(result, QoSPolicyId::Partition);
616        let result = QoSPolicyId::from(
617            cyclonedds_sys::dds_qos_policy_id_DDS_RELIABILITY_QOS_POLICY_ID as u32,
618        );
619        assert_eq!(result, QoSPolicyId::Reliability);
620        let result = QoSPolicyId::from(
621            cyclonedds_sys::dds_qos_policy_id_DDS_DESTINATIONORDER_QOS_POLICY_ID as u32,
622        );
623        assert_eq!(result, QoSPolicyId::DestinationOrder);
624        let result =
625            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_HISTORY_QOS_POLICY_ID as u32);
626        assert_eq!(result, QoSPolicyId::History);
627        let result = QoSPolicyId::from(
628            cyclonedds_sys::dds_qos_policy_id_DDS_RESOURCELIMITS_QOS_POLICY_ID as u32,
629        );
630        assert_eq!(result, QoSPolicyId::ResourceLimits);
631        let result = QoSPolicyId::from(
632            cyclonedds_sys::dds_qos_policy_id_DDS_ENTITYFACTORY_QOS_POLICY_ID as u32,
633        );
634        assert_eq!(result, QoSPolicyId::EntityFactory);
635        let result = QoSPolicyId::from(
636            cyclonedds_sys::dds_qos_policy_id_DDS_WRITERDATALIFECYCLE_QOS_POLICY_ID as u32,
637        );
638        assert_eq!(result, QoSPolicyId::WriterDataLifecycle);
639        let result = QoSPolicyId::from(
640            cyclonedds_sys::dds_qos_policy_id_DDS_READERDATALIFECYCLE_QOS_POLICY_ID as u32,
641        );
642        assert_eq!(result, QoSPolicyId::ReaderDataLifecycle);
643        let result =
644            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_TOPICDATA_QOS_POLICY_ID as u32);
645        assert_eq!(result, QoSPolicyId::TopicData);
646        let result =
647            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_GROUPDATA_QOS_POLICY_ID as u32);
648        assert_eq!(result, QoSPolicyId::GroupData);
649        let result = QoSPolicyId::from(
650            cyclonedds_sys::dds_qos_policy_id_DDS_TRANSPORTPRIORITY_QOS_POLICY_ID as u32,
651        );
652        assert_eq!(result, QoSPolicyId::TransportPriority);
653        let result =
654            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_LIFESPAN_QOS_POLICY_ID as u32);
655        assert_eq!(result, QoSPolicyId::Lifespan);
656        let result = QoSPolicyId::from(
657            cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITYSERVICE_QOS_POLICY_ID as u32,
658        );
659        assert_eq!(result, QoSPolicyId::DurabilityService);
660        let result =
661            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_PROPERTY_QOS_POLICY_ID as u32);
662        assert_eq!(result, QoSPolicyId::Property);
663        let result = QoSPolicyId::from(
664            cyclonedds_sys::dds_qos_policy_id_DDS_TYPE_CONSISTENCY_ENFORCEMENT_QOS_POLICY_ID as u32,
665        );
666        assert_eq!(result, QoSPolicyId::TypeConsistencyEnforcement);
667        let result = QoSPolicyId::from(
668            cyclonedds_sys::dds_qos_policy_id_DDS_DATA_REPRESENTATION_QOS_POLICY_ID as u32,
669        );
670        assert_eq!(result, QoSPolicyId::DataRepresentation);
671    }
672
673    #[test]
674    #[should_panic = "internal error: entered unreachable code: unsupported value"]
675    fn test_qos_policy_id_conversion_out_of_range() {
676        let _ = QoSPolicyId::from(u32::MAX);
677    }
678
679    #[test]
680    fn test_sample_rejected_reason_conversion() {
681        let result = SampleRejectedReason::from(
682            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_NOT_REJECTED,
683        );
684        assert_eq!(result, SampleRejectedReason::NotRejected);
685        let result = SampleRejectedReason::from(
686            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_INSTANCES_LIMIT,
687        );
688        assert_eq!(result, SampleRejectedReason::RejectedByInstancesLimit);
689        let result = SampleRejectedReason::from(
690            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_LIMIT,
691        );
692        assert_eq!(result, SampleRejectedReason::RejectedBySamplesLimit);
693        let result = SampleRejectedReason::from(cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT);
694        assert_eq!(
695            result,
696            SampleRejectedReason::RejectedBySamplesPerInstanceLimit
697        );
698    }
699
700    #[test]
701    #[should_panic = "internal error: entered unreachable code: unsupported value"]
702    fn test_sample_rejected_reason_conversion_out_of_range() {
703        let _ = SampleRejectedReason::from(cyclonedds_sys::dds_sample_rejected_status_kind::MAX);
704    }
705
706    #[test]
707    fn test_inconsistent_topic_conversion() {
708        let total_count = 10;
709        let total_count_change = 20;
710
711        let status = InconsistentTopic::from(cyclonedds_sys::dds_inconsistent_topic_status {
712            total_count,
713            total_count_change,
714        });
715
716        assert_eq!(
717            (status.total.count, status.total.delta),
718            (total_count, total_count_change)
719        );
720    }
721
722    #[test]
723    fn test_liveliness_lost_conversion() {
724        let total_count = 10;
725        let total_count_change = 20;
726        let status = LivelinessLost::from(cyclonedds_sys::dds_liveliness_lost_status {
727            total_count,
728            total_count_change,
729        });
730
731        assert_eq!(
732            (status.total.count, status.total.delta),
733            (total_count, total_count_change)
734        );
735    }
736
737    #[test]
738    fn test_offered_deadline_missed_conversion() {
739        let total_count = 10;
740        let total_count_change = 20;
741        let last_instance_handle = 30;
742
743        let status =
744            OfferedDeadlineMissed::from(cyclonedds_sys::dds_offered_deadline_missed_status {
745                total_count,
746                total_count_change,
747                last_instance_handle,
748            });
749
750        assert_eq!(
751            (
752                status.total.count,
753                status.total.delta,
754                status.last_instance_handle.inner
755            ),
756            (total_count, total_count_change, last_instance_handle)
757        );
758    }
759
760    #[test]
761    fn test_offered_incompatible_qos_conversion() {
762        let total_count = 10;
763        let total_count_change = 20;
764        let last_policy_id = cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITY_QOS_POLICY_ID as u32;
765
766        let status =
767            OfferedIncompatibleQoS::from(cyclonedds_sys::dds_offered_incompatible_qos_status {
768                total_count,
769                total_count_change,
770                last_policy_id,
771            });
772
773        assert_eq!(
774            (
775                status.total.count,
776                status.total.delta,
777                status.last_policy_id
778            ),
779            (total_count, total_count_change, last_policy_id.into())
780        );
781    }
782
783    #[test]
784    fn test_publication_matched_conversion() {
785        let total_count = 10;
786        let total_count_change = 20;
787        let current_count = 30;
788        let current_count_change = 40;
789        let last_subscription_handle = 50;
790
791        let status = PublicationMatched::from(cyclonedds_sys::dds_publication_matched_status {
792            total_count,
793            total_count_change,
794            current_count,
795            current_count_change,
796            last_subscription_handle,
797        });
798
799        assert_eq!(
800            (
801                status.total.count,
802                status.total.delta,
803                status.current.count,
804                status.current.delta,
805                status.last_subscription_handle.inner
806            ),
807            (
808                total_count,
809                total_count_change,
810                current_count,
811                current_count_change,
812                last_subscription_handle
813            )
814        );
815    }
816
817    #[test]
818    fn test_sample_lost_conversion() {
819        let total_count = 10;
820        let total_count_change = 20;
821
822        let status = SampleLost::from(cyclonedds_sys::dds_sample_lost_status {
823            total_count,
824            total_count_change,
825        });
826
827        assert_eq!(
828            (status.total.count, status.total.delta),
829            (total_count, total_count_change)
830        );
831    }
832
833    #[test]
834    fn test_sample_rejected_conversion() {
835        let total_count = 10;
836        let total_count_change = 20;
837        let last_reason =
838            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_INSTANCES_LIMIT;
839        let last_instance_handle = 40;
840
841        let status = SampleRejected::from(cyclonedds_sys::dds_sample_rejected_status {
842            total_count,
843            total_count_change,
844            last_reason,
845            last_instance_handle,
846        });
847
848        assert_eq!(
849            (
850                status.total.count,
851                status.total.delta,
852                status.last_reason,
853                status.last_instance_handle.inner
854            ),
855            (
856                total_count,
857                total_count_change,
858                last_reason.into(),
859                last_instance_handle
860            )
861        );
862    }
863
864    #[test]
865    fn test_liveliness_changed_conversion() {
866        let alive_count = 10;
867        let alive_count_change = 20;
868        let not_alive_count = 30;
869        let not_alive_count_change = 40;
870        let last_publication_handle = 50;
871
872        let status = LivelinessChanged::from(cyclonedds_sys::dds_liveliness_changed_status {
873            alive_count,
874            alive_count_change,
875            not_alive_count,
876            not_alive_count_change,
877            last_publication_handle,
878        });
879
880        assert_eq!(
881            (
882                status.alive.count,
883                status.alive.delta,
884                status.not_alive.count,
885                status.not_alive.delta,
886                status.last_publication_handle.inner
887            ),
888            (
889                alive_count,
890                alive_count_change,
891                not_alive_count,
892                not_alive_count_change,
893                last_publication_handle
894            )
895        );
896    }
897
898    #[test]
899    fn test_requested_deadline_missed_conversion() {
900        let total_count = 10;
901        let total_count_change = 20;
902        let last_instance_handle = 30;
903
904        let status =
905            RequestedDeadlineMissed::from(cyclonedds_sys::dds_requested_deadline_missed_status {
906                total_count,
907                total_count_change,
908                last_instance_handle,
909            });
910
911        assert_eq!(
912            (
913                status.total.count,
914                status.total.delta,
915                status.last_instance_handle.inner
916            ),
917            (total_count, total_count_change, last_instance_handle)
918        );
919    }
920
921    #[test]
922    fn test_requested_incompatible_qos_conversion() {
923        let total_count = 10;
924        let total_count_change = 20;
925        let last_policy_id = cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITY_QOS_POLICY_ID as u32;
926
927        let status =
928            RequestedIncompatibleQoS::from(cyclonedds_sys::dds_requested_incompatible_qos_status {
929                total_count,
930                total_count_change,
931                last_policy_id,
932            });
933
934        assert_eq!(
935            (
936                status.total.count,
937                status.total.delta,
938                status.last_policy_id
939            ),
940            (total_count, total_count_change, last_policy_id.into())
941        );
942    }
943
944    #[test]
945    fn test_subscription_matched_conversion() {
946        let total_count = 10;
947        let total_count_change = 20;
948        let current_count = 30;
949        let current_count_change = 40;
950        let last_publication_handle = 50;
951
952        let status = SubscriptionMatched::from(cyclonedds_sys::dds_subscription_matched_status {
953            total_count,
954            total_count_change,
955            current_count,
956            current_count_change,
957            last_publication_handle,
958        });
959
960        assert_eq!(
961            (
962                status.total.count,
963                status.total.delta,
964                status.current.count,
965                status.current.delta,
966                status.last_publication_handle.inner
967            ),
968            (
969                total_count,
970                total_count_change,
971                current_count,
972                current_count_change,
973                last_publication_handle
974            )
975        );
976    }
977}