Skip to content

Commit

Permalink
Api and doc improvements (#155)
Browse files Browse the repository at this point in the history
* Simplified importing of RustDDS. Doc improvements.
* Remove DDSDuration type alias.
* Deprecate dds::data_types re-export.
  • Loading branch information
jhelovuo authored Dec 15, 2021
1 parent d432f1c commit c4640d3
Show file tree
Hide file tree
Showing 23 changed files with 369 additions and 263 deletions.
4 changes: 2 additions & 2 deletions examples/shapes_demo/logging-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ appenders:
stdout:
kind: console
root:
# level: info
level: warn
level: info
# level: warn
appenders:
- stdout
loggers:
Expand Down
15 changes: 3 additions & 12 deletions examples/shapes_demo/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,7 @@ use log4rs::{
config::{Appender, Root},
Config,
};
use rustdds::dds::{
data_types::DDSDuration,
qos::{
policy::{Deadline, Durability, History, Reliability},
QosPolicyBuilder,
},
statusevents::StatusEvented,
traits::{Keyed, TopicDescription},
DomainParticipant, TopicKind,
};
use rustdds::{self, *};
use serde::{Deserialize, Serialize};
use clap::{App, Arg, ArgMatches}; // command line argument processing
use mio::{Events, Poll, PollOpt, Ready, Token}; // polling
Expand Down Expand Up @@ -73,7 +64,7 @@ fn main() {
let mut qos_b = QosPolicyBuilder::new()
.reliability(if matches.is_present("reliable") {
Reliability::Reliable {
max_blocking_time: DDSDuration::DURATION_ZERO,
max_blocking_time: rustdds::Duration::DURATION_ZERO,
}
} else {
Reliability::BestEffort
Expand All @@ -97,7 +88,7 @@ fn main() {
let deadline_policy = match matches.value_of("deadline") {
None => None,
Some(dl) => match dl.parse::<f64>() {
Ok(d) => Some(Deadline(DDSDuration::from_frac_seconds(d))),
Ok(d) => Some(Deadline(rustdds::Duration::from_frac_seconds(d))),
Err(e) => panic!("Expected numeric value for deadline. {:?}", e),
},
};
Expand Down
5 changes: 2 additions & 3 deletions examples/turtle_teleop/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::channel as mio_channel;
use rustdds::{
dds::{
data_types::DDSDuration,
qos::{
policy::{Durability, History, Liveliness, Reliability},
QosPolicies, QosPolicyBuilder,
Expand Down Expand Up @@ -117,10 +116,10 @@ fn ros2_loop(
QosPolicyBuilder::new()
.durability(Durability::Volatile)
.liveliness(Liveliness::Automatic {
lease_duration: DDSDuration::DURATION_INFINITE,
lease_duration: rustdds::Duration::DURATION_INFINITE,
})
.reliability(Reliability::Reliable {
max_blocking_time: DDSDuration::from_millis(100),
max_blocking_time: rustdds::Duration::from_millis(100),
})
.history(History::KeepLast { depth: 10 })
.build()
Expand Down
118 changes: 10 additions & 108 deletions src/dds/mod.rs
Original file line number Diff line number Diff line change
@@ -1,114 +1,14 @@
//! DDS interface
//!
//! # DDS usage summary
//!
//! * Create a [`DomainParticipant`]. You have to choose a domain id. The
//! default value is zero.
//! * Create or find a [`Topic`] from the [`DomainParticipant`]. Topics have a
//! name and a type.
//! * Create a [`Publisher`] and/or [`Subscriber`] from the
//! [`DomainParticipant`].
//! * To receive data, create a [`DataReader`](with_key::DataReader) from
//! [`Subscriber`] and [`Topic`].
//! * To send data, create a [`DataWriter`](with_key::DataWriter) from
//! [`Publisher`] and [`Topic`].
//! * Data from `DataReader` can be read or taken. Taking removes the data
//! samples from the DataReader, whereas reading only marks them as read.
//! * Topics are either WithKey or NoKey. WithKey topics are like map data
//! structures, containing multiple instances (map items), identified by key.
//! The key must be something that can be extracted from the data samples.
//! Instances can be created (published) and deleted (disposed). NoKey topics
//! have always only one instance of the data.
//! * Data is sent and received in consecutive samples. When read, a smaple is
//! accompanied with metadata (SampleInfo).
//!
//! # Interfacing Rust data types to DDS
//! * DDS takes care of serialization and deserialization.
//! In order to do this, the payload data must be Serde
//! serializable/deserializable.
//! * If your data is to be communicated over a WithKey topic, the payload data
//! type must implement [`Keyed`](traits::Keyed) trait from this crate.
//! * If you are using CDR serialization (DDS default), then use [`CDRSerializerAdapter`](../serialization/CdrSerializerAdapter) and [`CdrDeserializerAdapter`](../serialization/CdrDeserializerAdapter)
//! when such adapters are required. If you need to use another serialization format, then you should find or write
//! a [Serde data format](https://serde.rs/data-format.html) implementation and wrap it as a (De)SerializerAdaper.
//!
//! ```
//! use rustdds::dds::DomainParticipant;
//! use rustdds::dds::{No_Key_DataReader as DataReader, No_Key_DataWriter as DataWriter, no_key::DataSample};
//! use rustdds::dds::qos::QosPolicyBuilder;
//! use rustdds::dds::qos::policy::Reliability;
//! use rustdds::dds::data_types::DDSDuration;
//! use rustdds::dds::data_types::TopicKind;
//! use rustdds::serialization::{CDRSerializerAdapter, CDRDeserializerAdapter};
//! use serde::{Serialize, Deserialize};
//!
//! // DomainParticipant is always necessary
//! let domain_participant = DomainParticipant::new(0).unwrap();
//!
//! let qos = QosPolicyBuilder::new()
//! .reliability(Reliability::Reliable { max_blocking_time: DDSDuration::DURATION_ZERO })
//! .build();
//!
//! // DDS Subscriber, only one is necessary for each thread (slight difference to
//! // DDS specification)
//! let subscriber = domain_participant.create_subscriber(&qos).unwrap();
//!
//! // DDS Publisher, only one is necessary for each thread (slight difference to
//! // DDS specification)
//! let publisher = domain_participant.create_publisher(&qos).unwrap();
//!
//! // Some DDS Topic that we can write and read from (basically only binds readers
//! // and writers together)
//! let some_topic = domain_participant.create_topic("some_topic".to_string(), "SomeType".to_string(), &qos, TopicKind::NoKey).unwrap();
//!
//! // Used type needs Serialize for writers and Deserialize for readers
//! #[derive(Serialize, Deserialize)]
//! struct SomeType {
//! a: i32
//! }
//!
//! // Creating DataReader requires type and deserializer adapter (which is recommended to be CDR).
//! // Reader needs to be mutable if any operations are used.
//! let mut reader = subscriber
//! .create_datareader_no_key::<SomeType, CDRDeserializerAdapter<SomeType>>(
//! &some_topic,
//! None)
//! .unwrap();
//!
//! // Creating DataWriter required type and serializer adapter (which is recommended to be CDR).
//! let writer = publisher
//! .create_datawriter_no_key::<SomeType, CDRSerializerAdapter<SomeType>>(
//! &some_topic,
//! None)
//! .unwrap();
//!
//! // Readers implement mio Evented trait and thus function the same way as
//! // std::sync::mpcs and can be handled the same way for reading the data
//!
//! let some_data = SomeType { a: 1 };
//!
//! // This should send the data to all who listen "some_topic" topic.
//! writer.write(some_data, None).unwrap();
//!
//! // ... Some data has arrived at some point for the reader
//! let data_sample = if let Ok(Some(value)) = reader.read_next_sample() {
//! value
//! } else {
//! // no data has arrived
//! return;
//! };
//!
//! // Getting reference to actual data from the data sample
//! let actual_data = data_sample.value();
//! ```
//! DDS interface - Most commonly needed items should be re-exported directly to
//! crate top level and modules [`no_key`](crate::no_key) and
//! [`with_key`](crate::with_key).
mod datasample_cache;
pub(crate) mod ddsdata;
mod dp_event_loop;
mod fragment_assembler;
mod helpers;
mod message_receiver;
mod sampleinfo;
pub mod sampleinfo;

/// Participating in NoKey topics.
pub mod no_key;
Expand All @@ -135,23 +35,25 @@ pub mod qos;
pub mod statusevents;

/// Datatypes needed for overall operability with this crate
#[deprecated(
since = "0.7.0",
note = "Please use re-exports directly from crate top level instead."
)]
#[doc(hidden)]
pub mod data_types {
pub use crate::{
dds::sampleinfo::SampleInfo,
discovery::data_types::topic_data::{DiscoveredTopicData, SubscriptionBuiltinTopicData},
structure::guid::*,
};
#[doc(inline)]
pub use crate::structure::duration::Duration as DDSDuration;
pub use super::{
readcondition::ReadCondition,
topic::{Topic, TopicKind},
traits::key::BuiltInTopicKey,
};
#[doc(inline)]
pub use super::with_key::datareader::SelectByKey;
#[doc(inline)]
pub use crate::structure::time::Timestamp as DDSTimestamp;
// TODO: move typedesc module somewhere better
pub use crate::dds::typedesc::TypeDesc;
}
Expand Down
10 changes: 7 additions & 3 deletions src/dds/no_key/datasample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ use crate::dds::{
with_key::datasample::DataSample as WithKeyDataSample,
};

/// DDS spec 2.2.2.5.4
/// A data sample and its associated [metadata](`SampleInfo`) received from a
/// NO_KEY Topic.
///
/// Note that no_key::DataSample and with_key::DataSample are two different but
/// similar structs.
/// See DDS spec version 1.4 Section 2.2.2.5.4
///
/// Note that [`no_key::DataSample`](crate::no_key::DataSample) and
/// [`with_key::DataSample`](crate::with_key::DataSample) are two different
/// structs.
#[derive(PartialEq, Debug)]
pub struct DataSample<D> {
pub(crate) sample_info: SampleInfo, // TODO: Can we somehow make this lazily evaluated?
Expand Down
23 changes: 17 additions & 6 deletions src/dds/participant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use log::{debug, error, info, trace, warn};

use crate::{
dds::{
data_types::*, dp_event_loop::DPEventLoop, pubsub::*, qos::*, reader::*, topic::*,
typedesc::TypeDesc, values::result::*, writer::WriterIngredients,
dp_event_loop::DPEventLoop, pubsub::*, qos::*, reader::*, topic::*, typedesc::TypeDesc,
values::result::*, writer::WriterIngredients,
},
discovery::{
data_types::topic_data::DiscoveredTopicData,
Expand All @@ -26,12 +26,23 @@ use crate::{
},
log_and_err_internal,
network::{constant::*, udp_listener::UDPListener},
structure::{dds_cache::DDSCache, entity::RTPSEntity, guid::GUID, locator::Locator},
structure::{dds_cache::DDSCache, entity::RTPSEntity, guid::*, locator::Locator},
};
use super::dp_event_loop::DomainInfo;

/// DDS DomainParticipant generally only one per domain per machine should be
/// active
/// DDS DomainParticipant
///
/// It is recommended that only one DomainParticipant per OS process is created,
/// as it allocates network sockets, creates background threads, and allocates
/// some memory for object caches.
///
/// If you need to communicate to many DDS domains,
/// then you must create a separate DomainParticiapnt for each of them.
/// See DDS Spec v1.4 Section "2.2.1.2.2 Overall Conceptual Model" and
/// "2.2.2.2.1 DomainParticipant Class" for a definition of a (DDS) domain.
/// Domains are identified by a domain identifier, which is, in Rust terms, a
/// `u16`. Domain identifer values are application-specific, but `0` is usually
/// the default.
#[derive(Clone)]
// This is a smart pointer for DomainParticipantInner for easier manipulation.
pub struct DomainParticipant {
Expand All @@ -42,7 +53,7 @@ pub struct DomainParticipant {
impl DomainParticipant {
/// # Examples
/// ```
/// # use rustdds::dds::DomainParticipant;
/// # use rustdds::DomainParticipant;
/// let domain_participant = DomainParticipant::new(0).unwrap();
/// ```
pub fn new(domain_id: u16) -> Result<DomainParticipant> {
Expand Down
16 changes: 16 additions & 0 deletions src/dds/pubsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ use super::{

/// DDS Publisher
///
/// The Publisher and Subscriber structures are collections of DataWriters
/// and, respectively, DataReaders. They can contain DataWriters or DataReaders
/// of different types, and attacehd to different Topics.
///
/// They can act as a domain of sample ordering or atomicity, if such QoS
/// policies are used. For example, DDS participants could agree via QoS
/// policies that data samples must be presented to readers in the same order as
/// writers have written them, and the ordering applies also between several
/// writers/readers, but within one publisher/subscriber. Analogous arrangement
/// can be set up w.r.t. coherency: All the samples in a transaction are
/// delivered to the readers, or none are. The transaction can span several
/// readers, writers, and topics in a single publisher/subscriber.
///
///
/// # Examples
///
/// ```
Expand Down Expand Up @@ -596,6 +610,8 @@ impl Debug for InnerPublisher {

/// DDS Subscriber
///
/// See overview at [`Publisher`].
///
/// # Examples
///
/// ```
Expand Down
35 changes: 22 additions & 13 deletions src/dds/qos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub enum QosPolicyId {
//DurabilityService, // 22
}

/// Utility for building [QosPolicies](struct.QosPolicies.html)
/// Utility for building [QosPolicies]
#[derive(Default)]
pub struct QosPolicyBuilder {
durability: Option<policy::Durability>,
Expand Down Expand Up @@ -161,7 +161,9 @@ impl QosPolicyBuilder {
}
}

/// Describes single RTPS/DDS QoS policy
/// Describes a set of RTPS/DDS QoS policies
///
/// QosPolicies are constructed using a [`QosPolicyBuilder`]
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct QosPolicies {
// pub(crate) beacuse as we want to have some builtin QoS Policies as constant.
Expand Down Expand Up @@ -237,6 +239,10 @@ impl QosPolicies {
self.lifespan
}

/// Merge two QosPolicies
///
/// Constructs a QosPolicy, where each policy is taken from `self`,
/// and overwritten with those policies from `other` that are defined.
pub fn modify_by(&self, other: &QosPolicies) -> QosPolicies {
QosPolicies {
durability: other.durability.or(self.durability),
Expand All @@ -254,16 +260,19 @@ impl QosPolicies {
}
}

// Check if policy self commplies to other.
//
// "self" is the "offered" (publisher) QoS
// "other" is the "requested" (subscriber) QoS
// yes => None (no failure, i.e. are compatible)
// no => Some(policyId) , where policyId is (any) one of the policies
// causing incompliance
// Compliance (comaptibility) is defined in the table in DDS spec v1.4
// Section "2.2.3 Supported QoS"
// This is not symmetric.
/// Check if policy commplies to another policy.
///
/// `self` is the "offered" (publisher) QoS
/// `other` is the "requested" (subscriber) QoS
///
/// * None => Policies are compatible
/// * Some(policyId) => Failure, where policyId is (any) one of the policies
/// causing incompliance
///
/// Compliance (compatibility) is defined in the table in DDS spec v1.4
/// Section "2.2.3 Supported QoS"
///
/// This is not symmetric.
pub fn compliance_failure_wrt(&self, other: &QosPolicies) -> Option<QosPolicyId> {
trace!(
"QoS compatibility check - offered: {:?} - requested {:?}",
Expand All @@ -275,7 +284,7 @@ impl QosPolicies {
result
}

pub fn compliance_failure_wrt_impl(&self, other: &QosPolicies) -> Option<QosPolicyId> {
fn compliance_failure_wrt_impl(&self, other: &QosPolicies) -> Option<QosPolicyId> {
// TODO: Check for cases where policy is requested, but not offered (None)

// check Durability: Offered must be better than or equal to Requested.
Expand Down
10 changes: 6 additions & 4 deletions src/dds/readcondition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use enumflags2::BitFlags;

use crate::dds::sampleinfo::*;

// This is used to specify which samples are to be read or taken.
// To be selected, the current state of the sample must be included in the
// corresponding bitflags.
/// DDS ReadCondition 2.2.2.5.8
/// This is used to specify which samples are to be read or taken from
/// a [`Datareader`](crate::with_key::DataReader)
///
/// To be selected, the current state of the sample must be included in the
/// corresponding bitflags.
/// See DDS Specification 1.4 Section "2.2.2.5.8 ReadCondition"
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct ReadCondition {
sample_state_mask: BitFlags<SampleState>,
Expand Down
Loading

0 comments on commit c4640d3

Please sign in to comment.