Skip to main content

zerodds_dcps/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! Crate `zerodds-dcps`. Safety classification: **STANDARD**.
4//!
5//! DCPS Public API (OMG DDS 1.4 §2.2.2): `DomainParticipant`,
6//! `Publisher`, `Subscriber`, `Topic`, `DataWriter`, `DataReader`.
7//!
8//! Spec: OMG DDS 1.4 §2.2 (Data-Centric Publish-Subscribe Module) +
9//! DDSI-RTPS 2.5 §8.5 (Discovery + WLP) + XTypes 1.3 §7.6.3
10//! (TypeLookup-Service Wiring).
11//!
12//! ## Schichten-Position
13//!
14//! Layer 4 — Core Services. Bauend auf Layer 1
15//! (foundation/cdr/qos/types/time-service), Layer 2
16//! (rtps/discovery/transport-*), Layer 3 (idl/idl-rust/xml).
17//!
18//! ## Public API (Stand 1.0.0-rc.1)
19//!
20//! - [`DomainParticipantFactory`] — Singleton-Factory;
21//!   `create_participant` spawnt eine Live-Runtime mit
22//!   UDP/SPDP/SEDP/WLP, `create_participant_offline` baut einen
23//!   in-process-Skeleton ohne Netzwerk fuer Unit-Tests.
24//! - [`DomainParticipant`] — Top-Level-Entity; erzeugt
25//!   Publishers/Subscribers/Topics, fuehrt Built-in-Type-Registry,
26//!   exponiert TypeLookup-Hooks und Ignore-Filter.
27//! - [`Publisher`] / [`DataWriter`] — typed `Writer<T>` mit `DdsType`-
28//!   Bound; integriert RTPS-ReliableWriter (Live) bzw. In-Memory-Queue
29//!   (Offline) plus Durability-Backend (DDS 1.4 §2.2.3.5).
30//! - [`Subscriber`] / [`DataReader`] — typed `Reader<T>` mit
31//!   `take`/`read`/Conditions, Sample-Cache und InstanceState-Tracker
32//!   (DDS 1.4 §2.2.2.5).
33//! - [`Topic`] / [`ContentFilteredTopic`] / [`MultiTopic`] — Topic-
34//!   Hierarchie inkl. SQL-Filter (DDS 1.4 §2.2.2.3).
35//! - Builtin-Topics: [`BuiltinSubscriber`] +
36//!   [`DcpsParticipantBuiltinTopicData`] /
37//!   [`DcpsPublicationBuiltinTopicData`] /
38//!   [`DcpsSubscriptionBuiltinTopicData`] /
39//!   [`DcpsTopicBuiltinTopicData`] (DDS 1.4 §2.2.5).
40//! - Conditions/WaitSet: [`Condition`] / [`ReadCondition`] /
41//!   [`QueryCondition`] / [`GuardCondition`] / [`WaitSet`].
42//! - QoS-Familien: [`DomainParticipantQos`], [`PublisherQos`],
43//!   [`SubscriberQos`], [`TopicQos`], [`DataWriterQos`],
44//!   [`DataReaderQos`].
45//!
46//! ## Beispiel
47//!
48//! ```
49//! use zerodds_dcps::*;
50//! let factory = DomainParticipantFactory::instance();
51//! // Offline-Mode fuer Doctest (kein UDP-Multicast noetig).
52//! let participant = factory.create_participant_offline(0, DomainParticipantQos::default());
53//! let topic = participant
54//!     .create_topic::<RawBytes>("Chatter", TopicQos::default())
55//!     .expect("create_topic");
56//! let publisher = participant.create_publisher(PublisherQos::default());
57//! let writer = publisher
58//!     .create_datawriter::<RawBytes>(&topic, DataWriterQos::default())
59//!     .expect("create_datawriter");
60//! writer.write(&RawBytes::new(vec![1, 2, 3])).expect("write");
61//! ```
62
63#![cfg_attr(not(feature = "std"), no_std)]
64#![deny(unsafe_code)]
65#![warn(missing_docs)]
66
67#[cfg(feature = "alloc")]
68extern crate alloc;
69
70pub mod builtin_subscriber;
71pub mod builtin_topics;
72pub mod coherent_set;
73#[cfg(feature = "std")]
74pub mod condition;
75pub mod dds_type;
76#[cfg(feature = "std")]
77pub mod durability_service;
78pub mod entity;
79pub mod error;
80pub mod factory;
81/// ADR-0005: opt-in Flatdata-Integration.
82#[cfg(all(feature = "std", feature = "flatdata-integration"))]
83pub mod flatdata_integration;
84pub mod instance_handle;
85#[cfg(feature = "std")]
86pub mod instance_tracker;
87#[cfg(feature = "alloc")]
88pub mod interop;
89pub mod listener;
90#[cfg(feature = "std")]
91pub mod listener_dispatch;
92#[cfg(feature = "metrics")]
93pub mod metrics;
94pub mod participant;
95pub mod psm_constants;
96pub mod publisher;
97pub mod qos;
98#[cfg(feature = "std")]
99pub mod runtime;
100pub mod sample;
101pub mod sample_info;
102pub mod status;
103pub mod subscriber;
104pub mod time;
105pub mod topic;
106#[cfg(feature = "std")]
107pub mod wlp;
108
109// Flat-Re-Exports fuer die typische Import-Zeile.
110pub use builtin_subscriber::{BuiltinSinks, BuiltinSubscriber, BuiltinTopic, builtin_reader_qos};
111pub use builtin_topics::{
112    ParticipantBuiltinTopicData as DcpsParticipantBuiltinTopicData,
113    PublicationBuiltinTopicData as DcpsPublicationBuiltinTopicData,
114    SubscriptionBuiltinTopicData as DcpsSubscriptionBuiltinTopicData, TOPIC_NAME_DCPS_PARTICIPANT,
115    TOPIC_NAME_DCPS_PUBLICATION, TOPIC_NAME_DCPS_SUBSCRIPTION, TOPIC_NAME_DCPS_TOPIC,
116    TopicBuiltinTopicData as DcpsTopicBuiltinTopicData,
117};
118pub use dds_type::{
119    DdsType, DdsTypeRow, DecodeError, EncodeError, Extensibility, ExtensibilityKind, RawBytes,
120};
121pub use entity::{Entity, EntityState, StatusCondition, StatusMask, immutable_if_enabled};
122
123pub use coherent_set::{CoherentScope, CoherentSetMarker, GroupAccessScope};
124#[cfg(feature = "std")]
125pub use condition::{Condition, GuardCondition, QueryCondition, ReadCondition, WaitSet};
126pub use error::{DdsError, Result};
127pub use factory::DomainParticipantFactory;
128pub use instance_handle::{HANDLE_NIL, InstanceHandle, InstanceHandleAllocator};
129#[cfg(feature = "std")]
130pub use instance_tracker::{InstanceState, InstanceTracker, KeyHash};
131#[cfg(feature = "std")]
132pub use participant::IgnoreFilter;
133pub use participant::{DomainId, DomainParticipant};
134pub use publisher::{DataWriter, Publisher};
135pub use qos::{
136    DataReaderQos, DataWriterQos, DomainParticipantQos, PublisherQos, SubscriberQos, TopicQos,
137};
138pub use sample::Sample;
139pub use sample_info::{
140    InstanceStateKind, SampleInfo, SampleStateKind, ViewStateKind, instance_state_mask,
141    sample_state_mask, view_state_mask,
142};
143pub use subscriber::{DataReader, Subscriber};
144pub use time::{Duration, Time, get_current_time};
145#[cfg(feature = "std")]
146pub use topic::hash_join_two;
147pub use topic::{
148    ContentFilteredTopic, JoinedRow, MultiTopic, Topic, TopicDescription, TopicDescriptionHandle,
149};
150
151#[cfg(test)]
152#[allow(clippy::expect_used, clippy::unwrap_used)]
153mod tests {
154    use super::*;
155
156    #[test]
157    fn end_to_end_in_process_loopback() {
158        // Loopback smoke: Factory → Offline-Participant → Topic → Writer/Reader.
159        // Schleifen wir einen Sample per __push_raw von DataWriter
160        // in den DataReader. Live-Transport wird in den Runtime-Tests
161        // in crates/dcps/src/runtime.rs abgedeckt.
162        let factory = DomainParticipantFactory::instance();
163        let p = factory.create_participant_offline(0, DomainParticipantQos::default());
164        let topic = p
165            .create_topic::<RawBytes>("Chatter", TopicQos::default())
166            .unwrap();
167
168        let pub_ = p.create_publisher(PublisherQos::default());
169        let w = pub_
170            .create_datawriter::<RawBytes>(&topic, DataWriterQos::default())
171            .unwrap();
172
173        let sub = p.create_subscriber(SubscriberQos::default());
174        let r = sub
175            .create_datareader::<RawBytes>(&topic, DataReaderQos::default())
176            .unwrap();
177
178        w.write(&RawBytes::new(vec![1, 2, 3])).unwrap();
179        w.write(&RawBytes::new(vec![4, 5])).unwrap();
180        // Manuell queue drainen und in den Reader pushen, simuliert
181        // den Live-Transport-Pfad.
182        for bytes in w.__drain_pending() {
183            r.__push_raw(bytes).unwrap();
184        }
185        let samples = r.take().unwrap();
186        assert_eq!(samples.len(), 2);
187        assert_eq!(samples[0].data, vec![1, 2, 3]);
188        assert_eq!(samples[1].data, vec![4, 5]);
189    }
190}