rustdds/lib.rs
1//! A pure Rust implementation of Data Distribution Service (DDS).
2//!
3//! DDS is an object-oriented API [specified](https://www.omg.org/spec/DDS/) by
4//! the Object Management Group.
5//!
6//! DDS communicates over the network using the [RTPS](https://www.omg.org/spec/DDSI-RTPS/)
7//! protocol, which by default runs over UDP/IP.
8//!
9//! This implementation does not attempt to make an accurate implementation of
10//! the DDS object API, as it would be quite unnatural to use in Rust as such.
11//! However, we aim for functional compatibility, while at the same time using
12//! Rust techniques and conventions.
13//!
14//! Additionally, there is a [ROS2](https://index.ros.org/doc/ros2/) interface, that is simpler to use than DDS
15//! when communicating to ROS2 components. See package [ros2-client](https://crates.io/crates/ros2-client).
16//! Note: Do not use module [`ros2`] contained within RustDDS. It is no longer
17//! being developed.
18//!
19//! # DDS usage summary
20//!
21//! * Create a [`DomainParticipant`]. You have to choose a domain id. The
22//! default value is zero.
23//! * Create or find a [`Topic`] from the [`DomainParticipant`]. Topics have a
24//! name and a type.
25//! * Create a [`Publisher`] and/or [`Subscriber`] from the
26//! [`DomainParticipant`].
27//! * To receive data, create a [`DataReader`](with_key::DataReader) from
28//! [`Subscriber`] and [`Topic`].
29//! * To send data, create a [`DataWriter`](with_key::DataWriter) from
30//! [`Publisher`] and [`Topic`].
31//! * Data from `DataReader` can be read or taken. Taking removes the data
32//! samples from the DataReader, whereas reading only marks them as read.
33//!
34//! # Concepts
35//!
36//! * Data is sent and received in consecutive *samples*. When read, a sample is
37//! accompanied with [`SampleInfo`], which contains DDS-generated metadata.
38//! * Topics are either With_Key or No_Key.
39//! * With_Key topics are like map data structures, containing multiple
40//! *instances* (map entries), identified by a *key*. The key must be
41//! something that can be extracted from the data samples. Instances can be
42//! created (published) and deleted (disposed).
43//! * No_Key topics have always only one instance, which cannot be disposed.
44//! * Many types and traits in RustDDS have both with_key and no_key versions.
45//! This is because with_key communication must be able to access keys from
46//! data samples, so it is required in type signatures. Such requirement
47//! makes no sense for no_key communication, so signature must be different.
48//!
49//!
50//! # Interfacing Rust data types to DDS
51//!
52//! * DDS, as specified, takes care of data serialization and deserialization.
53//! In order for RustDDS to do this, the payload data must be [Serde](https://serde.rs/)
54//! serializable/deserializable.
55//! * If your data is to be communicated over a WithKey topic, the payload data
56//! type must implement [`Keyed`] trait from this crate.
57//! * If you are using [CDR serialization](https://en.wikipedia.org/wiki/Common_Data_Representation)
58//! ([specification, Section 15.3](https://www.omg.org/cgi-bin/doc?formal/02-06-51)) , which
59//! is the DDS default, then use [`CDRSerializerAdapter`] and
60//! [`CDRDeserializerAdapter`]
61//! when such adapters are required. If you need to use another serialization format, then you should find or write
62//! a [Serde data format](https://serde.rs/data-format.html) implementation and wrap it as a (De)SerializerAdapter.
63//!
64//! # Polling multiple DataReaders
65//!
66//! There are three alternative methods to poll DataReaders (and DataWriters):
67//! mio-0.6, mio-0.8, and async. Use only one of these!
68//!
69//! ## `mio-0.6`
70//!
71//! RustDDS is designed to used with [mio](mio_06) version 0.6.x. DataReaders
72//! implement [`Evented`](mio_06::event::Evented) so that they can be directly
73//! registered to a [`poll`](mio_06::Poll). See example `shapes_demo`.
74//!
75//! ## `mio-0.8`
76//!
77//! RustDDS DataReaders implement [`mio_08::event::Source`] for registering with
78//! mio-0.8. See example `shapes_demo_mio_08`
79//!
80//!
81//! ## `async`
82//!
83//! DataReader and DataWriter can do Rust async I/O by converting themselves to
84//! [`futures::stream::Stream`]s.
85//! * [`crate::dds::with_key::DataReader::async_sample_stream`] to get data
86//! * [`crate::dds::with_key::DataReader::async_bare_sample_stream`] to get bare
87//! data
88//! * [`crate::dds::with_key::BareDataReaderStream::async_event_stream`] or
89//! [`crate::dds::with_key::DataReaderStream::async_event_stream`] to get data
90//! status events
91//!
92//! See exampe `async_shapes_demo`.
93//!
94//! # Usage Example
95//!
96//! ```
97//! use rustdds::*;
98//! use rustdds::no_key::{DataReader, DataWriter, DataSample}; // We use a NO_KEY topic here
99//! use serde::{Serialize, Deserialize};
100//!
101//! // DomainParticipant is always necessary
102//! let domain_participant = DomainParticipant::new(0).unwrap();
103//!
104//! let qos = QosPolicyBuilder::new()
105//! .reliability(policy::Reliability::Reliable { max_blocking_time: rustdds::Duration::ZERO })
106//! .build();
107//!
108//! // DDS Subscriber, only one is necessary for each thread (slight difference to
109//! // DDS specification)
110//! let subscriber = domain_participant.create_subscriber(&qos).unwrap();
111//!
112//! // DDS Publisher, only one is necessary for each thread (slight difference to
113//! // DDS specification)
114//! let publisher = domain_participant.create_publisher(&qos).unwrap();
115//!
116//! // Some DDS Topic that we can write and read from (basically only binds readers
117//! // and writers together)
118//! let some_topic = domain_participant.create_topic("some_topic".to_string(), "SomeType".to_string(), &qos, TopicKind::NoKey).unwrap();
119//!
120//! // Used type needs Serialize for writers and Deserialize for readers
121//! #[derive(Serialize, Deserialize, Debug)]
122//! struct SomeType {
123//! a: i32
124//! }
125//!
126//! // Creating DataReader requires type and deserializer adapter (which is recommended to be CDR).
127//! // Reader needs to be mutable if any operations are used.
128//! let mut reader = subscriber
129//! .create_datareader_no_key::<SomeType, CDRDeserializerAdapter<SomeType>>(
130//! &some_topic,
131//! None)
132//! .unwrap();
133//!
134//! // Creating DataWriter required type and serializer adapter (which is recommended to be CDR).
135//! let writer = publisher
136//! .create_datawriter_no_key::<SomeType, CDRSerializerAdapter<SomeType>>(
137//! &some_topic,
138//! None)
139//! .unwrap();
140//!
141//! // Readers implement mio Evented trait and thus function the same way as
142//! // std::sync::mpcs and can be handled the same way for reading the data
143//!
144//! let some_data = SomeType { a: 1 };
145//!
146//! // This should send the data to all who listen "some_topic" topic.
147//! writer.write(some_data, None).unwrap();
148//!
149//! // ... Some data has arrived at some point for the reader
150//! let data_sample = if let Ok(Some(value)) = reader.take_next_sample() {
151//! value
152//! } else {
153//! // no data has arrived
154//! return;
155//! };
156//!
157//! // Getting reference to actual data from the data sample
158//! let actual_data = data_sample.value();
159//! ```
160#![warn(clippy::needless_pass_by_value, clippy::semicolon_if_nothing_returned)]
161#![allow(
162 // option_map_unit_fn suggests changing option.map( ) with () return value to if let -construct,
163 // but that may break code flow.
164 clippy::option_map_unit_fn,
165)]
166
167mod polling;
168#[macro_use]
169mod serialization_test;
170#[macro_use]
171mod checked_impl;
172#[doc(hidden)]
173pub mod discovery; // to access some Discovered data in e.g. ros2-client crate
174mod messages;
175mod network;
176mod rtps;
177
178#[cfg(feature = "security")]
179mod security;
180#[cfg(feature = "security")]
181pub use security::config::DomainParticipantSecurityConfigFiles;
182
183#[cfg(not(feature = "security"))]
184mod no_security;
185
186pub(crate) mod structure;
187
188#[cfg(test)]
189mod test;
190
191mod mio_source;
192
193// Public modules
194pub mod dds; // this is public, but not advertised
195
196#[deprecated(since = "0.8.5", note = "Use crate ros2-client instead.")]
197pub mod ros2;
198/// Helpers for (De)serialization and definitions of (De)serializer adapters
199pub mod serialization;
200
201// Re-exports from crate root to simplify usage
202#[doc(inline)]
203pub use dds::{
204 key::{Key, Keyed},
205 participant::{DomainParticipant, DomainParticipantBuilder},
206 pubsub::{Publisher, Subscriber},
207 qos,
208 qos::{policy, QosPolicies, QosPolicyBuilder},
209 readcondition::ReadCondition,
210 sampleinfo::{InstanceState, NotAliveGenerationCounts, SampleInfo, SampleState, ViewState},
211 statusevents::{
212 DataReaderStatus, DataWriterStatus, DomainParticipantStatusEvent, EndpointDescription,
213 LostReason, ParticipantDescription, StatusEvented,
214 },
215 topic::{Topic, TopicDescription, TopicKind},
216 typedesc::TypeDesc,
217 with_key::{datareader::SelectByKey, WriteOptions, WriteOptionsBuilder},
218};
219/// Needed to specify serialized data representation in case it is other than
220/// CDR.
221pub use serialization::RepresentationIdentifier;
222#[doc(inline)]
223pub use serialization::{
224 CDRDeserializerAdapter, CDRSerializerAdapter, CdrDeserializer, CdrSerializer,
225};
226pub use structure::{
227 duration::Duration, entity::RTPSEntity, guid::GUID, sequence_number::SequenceNumber,
228 time::Timestamp,
229};
230// re-export from a helper crate
231/// Helper trait to compute the CDR-serialized size of data
232pub use cdr_encoding_size::CdrEncodingSize;
233
234/// Components used to access NO_KEY Topics
235pub mod no_key {
236 pub use crate::dds::{adapters::no_key::*, no_key::*};
237}
238
239/// Components used to access WITH_KEY Topics
240pub mod with_key {
241 pub use crate::dds::{adapters::with_key::*, with_key::*};
242}
243
244pub mod rpc {
245 pub use crate::structure::rpc::*;
246}