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    // TODO How can sample not rejected be a valid status for the sample
308    // rejected status? should this be modeled as an Option in
309    // samplerejected?
310    /// The sample was not rejected.
311    NotRejected,
312    /// Rejected because the maximum number of instances has been reached.
313    RejectedByInstancesLimit,
314    /// Rejected because the maximum number of samples has been reached.
315    RejectedBySamplesLimit,
316    /// Rejected because the maximum number of samples per instance has been
317    /// reached.
318    RejectedBySamplesPerInstanceLimit,
319}
320
321impl From<cyclonedds_sys::dds_sample_rejected_status_kind> for SampleRejectedReason {
322    fn from(reason: cyclonedds_sys::dds_sample_rejected_status_kind) -> Self {
323        match reason {
324            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_NOT_REJECTED => Self::NotRejected,
325            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_INSTANCES_LIMIT => Self::RejectedByInstancesLimit,
326            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_LIMIT => Self::RejectedBySamplesLimit,
327            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT => Self::RejectedBySamplesPerInstanceLimit,
328            value => unreachable!("unsupported value: {value} in conversion to {}", std::any::type_name::<Self>())
329        }
330    }
331}
332
333/// Delivered to the
334/// [`with_sample_rejected`](crate::listener::ReaderListener::with_sample_rejected)
335/// callback.
336#[derive(Clone, Copy, Debug, PartialEq, Eq)]
337pub struct SampleRejected {
338    /// Running count of rejected samples.
339    pub total: Counter,
340    /// The reason the most recent sample was rejected.
341    pub last_reason: SampleRejectedReason,
342    /// Instance handle of the instance whose sample was most recently rejected.
343    pub last_instance_handle: crate::entity::InstanceHandle,
344}
345
346/// Delivered to the
347/// [`with_requested_deadline_missed`](crate::listener::ReaderListener::with_requested_deadline_missed)
348/// callback when a sample is not received within the
349/// [`Deadline`](crate::qos::policy::Deadline) period offered by a matched
350/// writer.
351#[derive(Clone, Copy, Debug, PartialEq, Eq)]
352pub struct RequestedDeadlineMissed {
353    /// Running count of deadline misses across all instances.
354    pub total: Counter,
355    /// Instance handle of the last instance that missed its deadline.
356    pub last_instance_handle: crate::entity::InstanceHandle,
357}
358
359/// Delivered to the
360/// [`with_requested_incompatible_qos`](crate::listener::ReaderListener::with_requested_incompatible_qos)
361/// callback when a writer is discovered whose offered [`QoS`](crate::QoS) is
362/// incompatible with this reader's requested [`QoS`](crate::QoS).
363#[derive(Clone, Copy, Debug, PartialEq, Eq)]
364pub struct RequestedIncompatibleQoS {
365    /// Running count of incompatible [`QoS`](crate::QoS) discoveries.
366    pub total: Counter,
367    /// The policy that caused the most recent incompatibility.
368    pub last_policy_id: QoSPolicyId,
369}
370
371/// Delivered to the
372/// [`with_subscription_matched`](crate::listener::ReaderListener::with_subscription_matched)
373/// callback when a writer matching this reader's topic and [`QoS`](crate::QoS)
374/// is discovered.
375#[derive(Clone, Copy, Debug, PartialEq, Eq)]
376pub struct SubscriptionMatched {
377    /// Running count of writer matches over the lifetime of the reader.
378    pub total: Counter,
379    /// Current number of matched writers.
380    pub current: Counter,
381    /// Instance handle of the last writer that matched or unmatched.
382    pub last_publication_handle: crate::entity::InstanceHandle,
383}
384
385/// Delivered to the
386/// [`with_liveliness_changed`](crate::listener::ReaderListener::with_liveliness_changed)
387/// callback when a matched writer transitions between active and inactive.
388#[derive(Clone, Copy, Debug, PartialEq, Eq)]
389pub struct LivelinessChanged {
390    /// Running count of matched writers that are currently active.
391    pub alive: Counter,
392    /// Running count of matched writers that are currently inactive.
393    pub not_alive: Counter,
394    /// Instance handle of the last writer whose liveliness changed.
395    pub last_publication_handle: crate::entity::InstanceHandle,
396}
397
398impl From<cyclonedds_sys::dds_inconsistent_topic_status> for InconsistentTopic {
399    fn from(status: cyclonedds_sys::dds_inconsistent_topic_status) -> Self {
400        let total = Counter {
401            count: status.total_count,
402            delta: status.total_count_change,
403        };
404
405        Self { total }
406    }
407}
408
409impl From<cyclonedds_sys::dds_liveliness_lost_status_t> for LivelinessLost {
410    fn from(status: cyclonedds_sys::dds_liveliness_lost_status_t) -> Self {
411        let total = Counter {
412            count: status.total_count,
413            delta: status.total_count_change,
414        };
415        Self { total }
416    }
417}
418
419impl From<cyclonedds_sys::dds_offered_deadline_missed_status_t> for OfferedDeadlineMissed {
420    fn from(status: cyclonedds_sys::dds_offered_deadline_missed_status_t) -> Self {
421        let total = Counter {
422            count: status.total_count,
423            delta: status.total_count_change,
424        };
425        let last_instance_handle = crate::entity::InstanceHandle {
426            inner: status.last_instance_handle,
427        };
428
429        Self {
430            total,
431            last_instance_handle,
432        }
433    }
434}
435
436impl From<cyclonedds_sys::dds_offered_incompatible_qos_status_t> for OfferedIncompatibleQoS {
437    fn from(status: cyclonedds_sys::dds_offered_incompatible_qos_status_t) -> Self {
438        let total = Counter {
439            count: status.total_count,
440            delta: status.total_count_change,
441        };
442        let last_policy_id = status.last_policy_id.into();
443
444        Self {
445            total,
446            last_policy_id,
447        }
448    }
449}
450
451impl From<cyclonedds_sys::dds_publication_matched_status_t> for PublicationMatched {
452    fn from(status: cyclonedds_sys::dds_publication_matched_status_t) -> Self {
453        let total = Counter {
454            count: status.total_count,
455            delta: status.total_count_change,
456        };
457        let current = Counter {
458            count: status.current_count,
459            delta: status.current_count_change,
460        };
461        let last_subscription_handle = crate::entity::InstanceHandle {
462            inner: status.last_subscription_handle,
463        };
464        Self {
465            total,
466            current,
467            last_subscription_handle,
468        }
469    }
470}
471
472impl From<cyclonedds_sys::dds_sample_lost_status_t> for SampleLost {
473    fn from(status: cyclonedds_sys::dds_sample_lost_status_t) -> Self {
474        let total = Counter {
475            count: status.total_count,
476            delta: status.total_count_change,
477        };
478        Self { total }
479    }
480}
481
482impl From<cyclonedds_sys::dds_sample_rejected_status_t> for SampleRejected {
483    fn from(status: cyclonedds_sys::dds_sample_rejected_status_t) -> Self {
484        let total = Counter {
485            count: status.total_count,
486            delta: status.total_count_change,
487        };
488        let last_reason = status.last_reason.into();
489        let last_instance_handle = crate::entity::InstanceHandle {
490            inner: status.last_instance_handle,
491        };
492        Self {
493            total,
494            last_reason,
495            last_instance_handle,
496        }
497    }
498}
499
500impl From<cyclonedds_sys::dds_liveliness_changed_status_t> for LivelinessChanged {
501    fn from(status: cyclonedds_sys::dds_liveliness_changed_status_t) -> Self {
502        let alive = Counter {
503            count: status.alive_count,
504            delta: status.alive_count_change,
505        };
506        let not_alive = Counter {
507            count: status.not_alive_count,
508            delta: status.not_alive_count_change,
509        };
510
511        let last_publication_handle = crate::entity::InstanceHandle {
512            inner: status.last_publication_handle,
513        };
514        Self {
515            alive,
516            not_alive,
517            last_publication_handle,
518        }
519    }
520}
521
522impl From<cyclonedds_sys::dds_requested_deadline_missed_status_t> for RequestedDeadlineMissed {
523    fn from(status: cyclonedds_sys::dds_requested_deadline_missed_status_t) -> Self {
524        let total = Counter {
525            count: status.total_count,
526            delta: status.total_count_change,
527        };
528        let last_instance_handle = crate::entity::InstanceHandle {
529            inner: status.last_instance_handle,
530        };
531        Self {
532            total,
533            last_instance_handle,
534        }
535    }
536}
537
538impl From<cyclonedds_sys::dds_requested_incompatible_qos_status_t> for RequestedIncompatibleQoS {
539    fn from(status: cyclonedds_sys::dds_requested_incompatible_qos_status_t) -> Self {
540        let total = Counter {
541            count: status.total_count,
542            delta: status.total_count_change,
543        };
544        let last_policy_id = status.last_policy_id.into();
545        Self {
546            total,
547            last_policy_id,
548        }
549    }
550}
551
552impl From<cyclonedds_sys::dds_subscription_matched_status_t> for SubscriptionMatched {
553    fn from(status: cyclonedds_sys::dds_subscription_matched_status_t) -> Self {
554        let total = Counter {
555            count: status.total_count,
556            delta: status.total_count_change,
557        };
558        let current = Counter {
559            count: status.current_count,
560            delta: status.current_count_change,
561        };
562        let last_publication_handle = crate::entity::InstanceHandle {
563            inner: status.last_publication_handle,
564        };
565
566        Self {
567            total,
568            current,
569            last_publication_handle,
570        }
571    }
572}
573
574#[cfg(test)]
575mod tests {
576    use super::*;
577
578    #[test]
579    fn test_qos_policy_id_conversion() {
580        let result =
581            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_INVALID_QOS_POLICY_ID as u32);
582        assert_eq!(result, QoSPolicyId::Invalid);
583        let result =
584            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_USERDATA_QOS_POLICY_ID as u32);
585        assert_eq!(result, QoSPolicyId::UserData);
586        let result = QoSPolicyId::from(
587            cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITY_QOS_POLICY_ID as u32,
588        );
589        assert_eq!(result, QoSPolicyId::Durability);
590        let result = QoSPolicyId::from(
591            cyclonedds_sys::dds_qos_policy_id_DDS_PRESENTATION_QOS_POLICY_ID as u32,
592        );
593        assert_eq!(result, QoSPolicyId::Presentation);
594        let result =
595            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_DEADLINE_QOS_POLICY_ID as u32);
596        assert_eq!(result, QoSPolicyId::Deadline);
597        let result = QoSPolicyId::from(
598            cyclonedds_sys::dds_qos_policy_id_DDS_LATENCYBUDGET_QOS_POLICY_ID as u32,
599        );
600        assert_eq!(result, QoSPolicyId::LatencyBudget);
601        let result =
602            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_OWNERSHIP_QOS_POLICY_ID as u32);
603        assert_eq!(result, QoSPolicyId::Ownership);
604        let result = QoSPolicyId::from(
605            cyclonedds_sys::dds_qos_policy_id_DDS_OWNERSHIPSTRENGTH_QOS_POLICY_ID as u32,
606        );
607        assert_eq!(result, QoSPolicyId::OwnershipStrength);
608        let result = QoSPolicyId::from(
609            cyclonedds_sys::dds_qos_policy_id_DDS_LIVELINESS_QOS_POLICY_ID as u32,
610        );
611        assert_eq!(result, QoSPolicyId::Liveliness);
612        let result = QoSPolicyId::from(
613            cyclonedds_sys::dds_qos_policy_id_DDS_TIMEBASEDFILTER_QOS_POLICY_ID as u32,
614        );
615        assert_eq!(result, QoSPolicyId::TimeBasedFilter);
616        let result =
617            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_PARTITION_QOS_POLICY_ID as u32);
618        assert_eq!(result, QoSPolicyId::Partition);
619        let result = QoSPolicyId::from(
620            cyclonedds_sys::dds_qos_policy_id_DDS_RELIABILITY_QOS_POLICY_ID as u32,
621        );
622        assert_eq!(result, QoSPolicyId::Reliability);
623        let result = QoSPolicyId::from(
624            cyclonedds_sys::dds_qos_policy_id_DDS_DESTINATIONORDER_QOS_POLICY_ID as u32,
625        );
626        assert_eq!(result, QoSPolicyId::DestinationOrder);
627        let result =
628            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_HISTORY_QOS_POLICY_ID as u32);
629        assert_eq!(result, QoSPolicyId::History);
630        let result = QoSPolicyId::from(
631            cyclonedds_sys::dds_qos_policy_id_DDS_RESOURCELIMITS_QOS_POLICY_ID as u32,
632        );
633        assert_eq!(result, QoSPolicyId::ResourceLimits);
634        let result = QoSPolicyId::from(
635            cyclonedds_sys::dds_qos_policy_id_DDS_ENTITYFACTORY_QOS_POLICY_ID as u32,
636        );
637        assert_eq!(result, QoSPolicyId::EntityFactory);
638        let result = QoSPolicyId::from(
639            cyclonedds_sys::dds_qos_policy_id_DDS_WRITERDATALIFECYCLE_QOS_POLICY_ID as u32,
640        );
641        assert_eq!(result, QoSPolicyId::WriterDataLifecycle);
642        let result = QoSPolicyId::from(
643            cyclonedds_sys::dds_qos_policy_id_DDS_READERDATALIFECYCLE_QOS_POLICY_ID as u32,
644        );
645        assert_eq!(result, QoSPolicyId::ReaderDataLifecycle);
646        let result =
647            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_TOPICDATA_QOS_POLICY_ID as u32);
648        assert_eq!(result, QoSPolicyId::TopicData);
649        let result =
650            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_GROUPDATA_QOS_POLICY_ID as u32);
651        assert_eq!(result, QoSPolicyId::GroupData);
652        let result = QoSPolicyId::from(
653            cyclonedds_sys::dds_qos_policy_id_DDS_TRANSPORTPRIORITY_QOS_POLICY_ID as u32,
654        );
655        assert_eq!(result, QoSPolicyId::TransportPriority);
656        let result =
657            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_LIFESPAN_QOS_POLICY_ID as u32);
658        assert_eq!(result, QoSPolicyId::Lifespan);
659        let result = QoSPolicyId::from(
660            cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITYSERVICE_QOS_POLICY_ID as u32,
661        );
662        assert_eq!(result, QoSPolicyId::DurabilityService);
663        let result =
664            QoSPolicyId::from(cyclonedds_sys::dds_qos_policy_id_DDS_PROPERTY_QOS_POLICY_ID as u32);
665        assert_eq!(result, QoSPolicyId::Property);
666        let result = QoSPolicyId::from(
667            cyclonedds_sys::dds_qos_policy_id_DDS_TYPE_CONSISTENCY_ENFORCEMENT_QOS_POLICY_ID as u32,
668        );
669        assert_eq!(result, QoSPolicyId::TypeConsistencyEnforcement);
670        let result = QoSPolicyId::from(
671            cyclonedds_sys::dds_qos_policy_id_DDS_DATA_REPRESENTATION_QOS_POLICY_ID as u32,
672        );
673        assert_eq!(result, QoSPolicyId::DataRepresentation);
674    }
675
676    #[test]
677    #[should_panic = "internal error: entered unreachable code: unsupported value"]
678    fn test_qos_policy_id_conversion_out_of_range() {
679        let _ = QoSPolicyId::from(u32::MAX);
680    }
681
682    #[test]
683    fn test_sample_rejected_reason_conversion() {
684        let result = SampleRejectedReason::from(
685            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_NOT_REJECTED,
686        );
687        assert_eq!(result, SampleRejectedReason::NotRejected);
688        let result = SampleRejectedReason::from(
689            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_INSTANCES_LIMIT,
690        );
691        assert_eq!(result, SampleRejectedReason::RejectedByInstancesLimit);
692        let result = SampleRejectedReason::from(
693            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_LIMIT,
694        );
695        assert_eq!(result, SampleRejectedReason::RejectedBySamplesLimit);
696        let result = SampleRejectedReason::from(cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT);
697        assert_eq!(
698            result,
699            SampleRejectedReason::RejectedBySamplesPerInstanceLimit
700        );
701    }
702
703    #[test]
704    #[should_panic = "internal error: entered unreachable code: unsupported value"]
705    fn test_sample_rejected_reason_conversion_out_of_range() {
706        let _ = SampleRejectedReason::from(cyclonedds_sys::dds_sample_rejected_status_kind::MAX);
707    }
708
709    #[test]
710    fn test_inconsistent_topic_conversion() {
711        let total_count = 10;
712        let total_count_change = 20;
713
714        let status = InconsistentTopic::from(cyclonedds_sys::dds_inconsistent_topic_status {
715            total_count,
716            total_count_change,
717        });
718
719        assert_eq!(
720            (status.total.count, status.total.delta),
721            (total_count, total_count_change)
722        );
723    }
724
725    #[test]
726    fn test_liveliness_lost_conversion() {
727        let total_count = 10;
728        let total_count_change = 20;
729        let status = LivelinessLost::from(cyclonedds_sys::dds_liveliness_lost_status {
730            total_count,
731            total_count_change,
732        });
733
734        assert_eq!(
735            (status.total.count, status.total.delta),
736            (total_count, total_count_change)
737        );
738    }
739
740    #[test]
741    fn test_offered_deadline_missed_conversion() {
742        let total_count = 10;
743        let total_count_change = 20;
744        let last_instance_handle = 30;
745
746        let status =
747            OfferedDeadlineMissed::from(cyclonedds_sys::dds_offered_deadline_missed_status {
748                total_count,
749                total_count_change,
750                last_instance_handle,
751            });
752
753        assert_eq!(
754            (
755                status.total.count,
756                status.total.delta,
757                status.last_instance_handle.inner
758            ),
759            (total_count, total_count_change, last_instance_handle)
760        );
761    }
762
763    #[test]
764    fn test_offered_incompatible_qos_conversion() {
765        let total_count = 10;
766        let total_count_change = 20;
767        let last_policy_id = cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITY_QOS_POLICY_ID as u32;
768
769        let status =
770            OfferedIncompatibleQoS::from(cyclonedds_sys::dds_offered_incompatible_qos_status {
771                total_count,
772                total_count_change,
773                last_policy_id,
774            });
775
776        assert_eq!(
777            (
778                status.total.count,
779                status.total.delta,
780                status.last_policy_id
781            ),
782            (total_count, total_count_change, last_policy_id.into())
783        );
784    }
785
786    #[test]
787    fn test_publication_matched_conversion() {
788        let total_count = 10;
789        let total_count_change = 20;
790        let current_count = 30;
791        let current_count_change = 40;
792        let last_subscription_handle = 50;
793
794        let status = PublicationMatched::from(cyclonedds_sys::dds_publication_matched_status {
795            total_count,
796            total_count_change,
797            current_count,
798            current_count_change,
799            last_subscription_handle,
800        });
801
802        assert_eq!(
803            (
804                status.total.count,
805                status.total.delta,
806                status.current.count,
807                status.current.delta,
808                status.last_subscription_handle.inner
809            ),
810            (
811                total_count,
812                total_count_change,
813                current_count,
814                current_count_change,
815                last_subscription_handle
816            )
817        );
818    }
819
820    #[test]
821    fn test_sample_lost_conversion() {
822        let total_count = 10;
823        let total_count_change = 20;
824
825        let status = SampleLost::from(cyclonedds_sys::dds_sample_lost_status {
826            total_count,
827            total_count_change,
828        });
829
830        assert_eq!(
831            (status.total.count, status.total.delta),
832            (total_count, total_count_change)
833        );
834    }
835
836    #[test]
837    fn test_sample_rejected_conversion() {
838        let total_count = 10;
839        let total_count_change = 20;
840        let last_reason =
841            cyclonedds_sys::dds_sample_rejected_status_kind_DDS_REJECTED_BY_INSTANCES_LIMIT;
842        let last_instance_handle = 40;
843
844        let status = SampleRejected::from(cyclonedds_sys::dds_sample_rejected_status {
845            total_count,
846            total_count_change,
847            last_reason,
848            last_instance_handle,
849        });
850
851        assert_eq!(
852            (
853                status.total.count,
854                status.total.delta,
855                status.last_reason,
856                status.last_instance_handle.inner
857            ),
858            (
859                total_count,
860                total_count_change,
861                last_reason.into(),
862                last_instance_handle
863            )
864        );
865    }
866
867    #[test]
868    fn test_liveliness_changed_conversion() {
869        let alive_count = 10;
870        let alive_count_change = 20;
871        let not_alive_count = 30;
872        let not_alive_count_change = 40;
873        let last_publication_handle = 50;
874
875        let status = LivelinessChanged::from(cyclonedds_sys::dds_liveliness_changed_status {
876            alive_count,
877            alive_count_change,
878            not_alive_count,
879            not_alive_count_change,
880            last_publication_handle,
881        });
882
883        assert_eq!(
884            (
885                status.alive.count,
886                status.alive.delta,
887                status.not_alive.count,
888                status.not_alive.delta,
889                status.last_publication_handle.inner
890            ),
891            (
892                alive_count,
893                alive_count_change,
894                not_alive_count,
895                not_alive_count_change,
896                last_publication_handle
897            )
898        );
899    }
900
901    #[test]
902    fn test_requested_deadline_missed_conversion() {
903        let total_count = 10;
904        let total_count_change = 20;
905        let last_instance_handle = 30;
906
907        let status =
908            RequestedDeadlineMissed::from(cyclonedds_sys::dds_requested_deadline_missed_status {
909                total_count,
910                total_count_change,
911                last_instance_handle,
912            });
913
914        assert_eq!(
915            (
916                status.total.count,
917                status.total.delta,
918                status.last_instance_handle.inner
919            ),
920            (total_count, total_count_change, last_instance_handle)
921        );
922    }
923
924    #[test]
925    fn test_requested_incompatible_qos_conversion() {
926        let total_count = 10;
927        let total_count_change = 20;
928        let last_policy_id = cyclonedds_sys::dds_qos_policy_id_DDS_DURABILITY_QOS_POLICY_ID as u32;
929
930        let status =
931            RequestedIncompatibleQoS::from(cyclonedds_sys::dds_requested_incompatible_qos_status {
932                total_count,
933                total_count_change,
934                last_policy_id,
935            });
936
937        assert_eq!(
938            (
939                status.total.count,
940                status.total.delta,
941                status.last_policy_id
942            ),
943            (total_count, total_count_change, last_policy_id.into())
944        );
945    }
946
947    #[test]
948    fn test_subscription_matched_conversion() {
949        let total_count = 10;
950        let total_count_change = 20;
951        let current_count = 30;
952        let current_count_change = 40;
953        let last_publication_handle = 50;
954
955        let status = SubscriptionMatched::from(cyclonedds_sys::dds_subscription_matched_status {
956            total_count,
957            total_count_change,
958            current_count,
959            current_count_change,
960            last_publication_handle,
961        });
962
963        assert_eq!(
964            (
965                status.total.count,
966                status.total.delta,
967                status.current.count,
968                status.current.delta,
969                status.last_publication_handle.inner
970            ),
971            (
972                total_count,
973                total_count_change,
974                current_count,
975                current_count_change,
976                last_publication_handle
977            )
978        );
979    }
980}