eclipse-cyclonedds 0.0.1

Rust binding for Eclipse Cyclone DDS
docs.rs failed to build eclipse-cyclonedds-0.0.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: eclipse-cyclonedds-0.0.2

Rust Binding for Eclipse Cyclone DDS

License License Latest Version Documentation Build Status Website Dependency Status Community

The official Rust binding for Eclipse Cyclone DDS.

Quick Start

Install the C library and headers to your system path or use the bundled-sources via the vendored feature. Then add the package to your Cargo.toml via:

[dependencies]
# This expects you to have an installation of the Cyclone DDS C library available
# which allows you to tailor the underlying C library as you wish.
#
# NOTE: you can also point to Cyclone DDS using the `CYCLONEDDS_HOME` variable if
# performing a full installation is undesirable.
eclipse-cyclonedds = "0.0.1"

# Using the `vendored` feature will result in us compiling and linking in a version
# of Cyclone DDS for you.
eclipse-cyclonedds = { version = "0.0.1", features = ["vendored"] }

Then see the example and the docs to get started.

Overview of DDS

The Data Distribution Service (DDS) is a publish-subscribe middleware standard for real-time, data-centric communication. It is used in a variety of mission critical applications in domains such as aerospace, defense, autonomous systems (e.g. vehicles, robotics), industrial control, smart energy grids, transportation, simulation, and medical devices.

Participants within a specific Domain discover each other automatically via the DDSI/RTPS discovery protocol. Once two endpoints sharing the same topic name, type information, and compatible Quality of Service (QoS) discover each other, the middleware establishes a connection between them. Publishers and Subscribers allow you to group Writers and Readers respectively to allow you to set their collective behavior. These Writers and Readers exchange typed samples via Topics.

                            DOMAIN
                               │
            ┌──────────────────┴──────────────────┐
            │                                     │
       PARTICIPANT                           PARTICIPANT
            │      T ≡ struct Position {x, y}     │
       ┌────┴────┐                           ┌────┴────┐
       │         │                           │         │
  PUBLISHER   TOPIC<T> ═══════════════════ TOPIC<T>  SUBSCRIBER
       │         ║                           ║         │
       │     "Position"                 "Position"     │
       │         ║                           ║         │
    WRITER<T> ═══╝                           ╚═══ READER<T>
         ╰───────── matched via Topic<T> ─────────╯
         Node 01                               Node 02
        ─────────                             ─────────

Data delivery characteristics, such as how samples are buffered, retransmitted, and received, are controlled via Quality of Service, a collection of QoS policies that configure characteristics such as:

  • durability (whether late-joining readers receive historical samples)
  • reliability (best-effort vs reliable delivery)
  • history depth (the number of samples to store in history)
  • deadline (whether a signal should be generated when a sample is not received within a specified period) Policies are set independently on the writer and reader side, and compatibility is checked at discovery time. A writer's offered QoS must be compatible with a reader's requested QoS for the two endpoints to match.

There are a variety of other elements to the DDS API such as:

See the DDS Specification and the OMG DDS Wiki for these other elements and see the Rust Documentation for what is supported by this API.

Example

use cyclonedds::QoS;
use cyclonedds::qos::policy;
use cyclonedds::sample::View;
use cyclonedds::{Domain, Duration, Participant, Reader, Topic, Writer, Topicable};

#[derive(Topicable, serde::Serialize, serde::Deserialize, Clone, Default, Debug)]
struct Sensor {
    #[dds(key)]
    id: u32,
    temperature: f32,
}

fn main() -> cyclonedds::Result<()> {
    let domain = Domain::default();
    let participant = Participant::new(&domain)?;
    let topic = Topic::<Sensor>::new(&participant, "Sensor")?;

    let qos = QoS::new()
        .with_durability(policy::Durability::TransientLocal)
        .with_history(policy::History::KeepLast { depth: 10 })
        .with_reliability(policy::Reliability::Reliable {
            max_blocking_time: Duration::from_millis(100),
        });

    let reader = Reader::builder(&topic).with_qos(&qos).build()?;
    let writer = Writer::builder(&topic).with_qos(&qos).build()?;

    writer.write(&Sensor {
        id: 1,
        temperature: 21.5,
    })?;

    writer.write(&Sensor {
        id: 2,
        temperature: 35.5,
    })?;

    // Get available samples from the reader history (draining them from the
    // reader).
    //
    // NOTE: use reader.read() to leave them in place for future reads.
    for sample in reader.take()? {
        // `sample` is a SampleOrKey<Sensor> which allows you to:
        //    - distinguish between the sample and key-only cases
        //    - access fields directly (with non-key fields default-initialized
        //      for key-only samples)
        //    - access sample info via `.info()`

        // You can precisely match on the result of `.view()` to handle
        // either case explicitly. This replaces checking the sample info for the
        // `valid_data` field (which does not exist in the Rust API).
        match sample.view() {
            View::Sample(sample) if sample.temperature > 30.0 => {
                println!("sample[{}] is hot: {}°C", sample.id, sample.temperature)
            }
            View::Sample(sample) => {
                println!("sample[{}] is cool: {}°C", sample.id, sample.temperature)
            }
            View::Key(key) => println!(
                "received a key-only sample due to an unregister or dispose: {key:?}"
            ),
        }

        // Alternatively, you can directly access the fields with key-only samples
        // having their non-key fields default-initialized via
        // `Topicable::from_key`.
        if sample.temperature > 30.0 {
            println!("sample[{}] is hot: {}°C", sample.id, sample.temperature);
        }

        // Access the sample info.
        println!(
            "sample[{}] was produced at: {:?}",
            sample.id,
            sample.info().source_timestamp
        );
    }
    Ok(())
}

Minimum supported Rust version (MSRV)

For now, the MSRV is the latest stable Rust version at the time of release.

References