Rust — in 5 Minuten zum ersten Sample
Primärpfad — der ganze ZeroDDS-Stack ist Pure-Rust. zerodds-dcps als einzige Dependency, alles andere wird transitiv gezogen. Async-friendly (Streams + Futures), #[derive]-Codegen für IDL-Typen, no_std-tauglich (Layer 1).
5-Minuten-Quickstart
Ein cargo new, eine Dep, ~15 Zeilen Rust.
1 · Projekt + Dep
cargo new zerodds-hello --bin
cd zerodds-hello
cargo add zerodds-dcps
2 · Pub/Sub-Roundtrip (src/main.rs)
use std::time::Duration;
use zerodds_dcps::*;
fn main() -> Result<()> {
let factory = DomainParticipantFactory::instance();
let p = factory.create_participant(0, DomainParticipantQos::default())?;
let topic = p.create_topic::<RawBytes>("Chatter", TopicQos::default())?;
let writer = p.create_publisher(PublisherQos::default())
.create_datawriter::<RawBytes>(&topic, DataWriterQos::default())?;
let reader = p.create_subscriber(SubscriberQos::default())
.create_datareader::<RawBytes>(&topic, DataReaderQos::default())?;
writer.wait_for_matched_subscription(1, Duration::from_secs(5))?;
reader.wait_for_matched_publication(1, Duration::from_secs(5))?;
writer.write(&RawBytes::new(b"hello".to_vec()))?;
reader.wait_for_data(Duration::from_secs(3))?;
for sample in reader.take()? {
println!("got: {:?}", sample.data);
}
Ok(())
}
▶ Runnable example: bindings-rust-main
3 · Laufen
cargo run --release
# got: [104, 101, 108, 108, 111]
Installation
Cargo (Standard)
[dependencies]
zerodds-dcps = "1.0.0-rc.3"
Zieht alle 9 Layer-Crates transitiv (foundation, cdr, qos, types, rtps, discovery, transport, transport-udp, dcps).
Direct Layer-Crate Pulls
Für no_std-Embedded brauchst du nur Layer 1:
[dependencies]
zerodds-foundation = "1.0.0-rc.3"
zerodds-cdr = "1.0.0-rc.3"
zerodds-qos = "1.0.0-rc.3"
zerodds-types = "1.0.0-rc.3"
Aus dem Source
Siehe Dev-Install — From Source.
Typisierte Topics — DdsType
Variante A — #[derive(DdsType)]
use zerodds_cdr_derive::DdsType; // derive macro
use zerodds_dcps::DdsType; // trait
#[derive(DdsType, Debug, Clone)]
#[dds(type_name = "sensor_msgs::msg::Temperature")]
pub struct Temperature {
pub celsius: i32,
pub sensor_id: String,
}
// Use it
let topic = p.create_topic::<Temperature>("Temp", TopicQos::default())?;
let writer = p.create_publisher(PublisherQos::default())
.create_datawriter::<Temperature>(&topic, DataWriterQos::default())?;
writer.write(&Temperature { celsius: 23, sensor_id: "A7".into() })?;
▶ Runnable example: rust-typed
Variante B — IDL via zerodds-idlc --rust
# IDL
echo 'struct Temperature { long celsius; string sensor_id; };' > temperature.idl
zerodds-idlc --rust temperature.idl -o gen/
# build.rs
fn main() {
println!("cargo:rerun-if-changed=temperature.idl");
// zerodds-idlc --rust temperature.idl -o $OUT_DIR/gen
}
Variante A ist idiomatischer (Derive-Macro), B ist wenn du IDL als Quelle of truth nutzt (Cross-Sprach-Konsistenz).
async / Streams
ZeroDDS hat einen separaten Async-Adapter-Crate (zerodds-dcps-async) — wraps die sync-API mit Tokio-Tasks.
use std::time::Duration;
use zerodds_dcps_async::*;
use zerodds_dcps::RawBytes;
#[tokio::main]
async fn main() -> Result<()> {
let factory = AsyncDomainParticipantFactory::instance();
let p = factory.create_participant(0)?;
let topic = p.create_topic::<RawBytes>("Chatter", TopicQos::default())?;
let writer = p.create_publisher(PublisherQos::default())
.create_datawriter::<RawBytes>(&topic, DataWriterQos::default())?;
let reader = p.create_subscriber(SubscriberQos::default())
.create_datareader::<RawBytes>(&topic, DataReaderQos::default())?;
writer.wait_for_matched_subscription(1, Duration::from_secs(5)).await?;
reader.wait_for_matched_publication(1, Duration::from_secs(5)).await?;
writer.write(&RawBytes::new(b"hello".to_vec())).await?;
for sample in reader.take(Duration::from_secs(3)).await? {
println!("got: {:?}", sample.data);
}
Ok(())
}
no_std + alloc
Layer 1 (foundation, cdr, qos, types) ist no_std-tauglich mit opt-in alloc-Feature:
[dependencies]
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false, features = ["alloc"] }
zerodds-cdr = { version = "1.0.0-rc.3", default-features = false, features = ["alloc"] }
Strict no_std (kein Heap):
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false }
Details: Dev-Install — Feature-Flags.
Rust — first sample in 5 minutes
The primary path — the whole ZeroDDS stack is pure Rust. zerodds-dcps as the single dependency, everything else pulled in transitively. Async-friendly (streams + futures), #[derive] codegen for IDL types, no_std-capable (layer 1).
5-minute quickstart
One cargo new, one dep, ~15 lines of Rust.
1 · Project + dep
cargo new zerodds-hello --bin
cd zerodds-hello
cargo add zerodds-dcps
2 · Pub/sub roundtrip (src/main.rs)
use std::time::Duration;
use zerodds_dcps::*;
fn main() -> Result<()> {
let factory = DomainParticipantFactory::instance();
let p = factory.create_participant(0, DomainParticipantQos::default())?;
let topic = p.create_topic::<RawBytes>("Chatter", TopicQos::default())?;
let writer = p.create_publisher(PublisherQos::default())
.create_datawriter::<RawBytes>(&topic, DataWriterQos::default())?;
let reader = p.create_subscriber(SubscriberQos::default())
.create_datareader::<RawBytes>(&topic, DataReaderQos::default())?;
writer.wait_for_matched_subscription(1, Duration::from_secs(5))?;
reader.wait_for_matched_publication(1, Duration::from_secs(5))?;
writer.write(&RawBytes::new(b"hello".to_vec()))?;
reader.wait_for_data(Duration::from_secs(3))?;
for sample in reader.take()? {
println!("got: {:?}", sample.data);
}
Ok(())
}
▶ Runnable example: bindings-rust-main
3 · Run
cargo run --release
# got: [104, 101, 108, 108, 111]
Installation
Cargo (standard)
[dependencies]
zerodds-dcps = "1.0.0-rc.3"
Pulls in all 9 layer crates transitively (foundation, cdr, qos, types, rtps, discovery, transport, transport-udp, dcps).
Direct layer-crate pulls
For no_std embedded you only need layer 1:
[dependencies]
zerodds-foundation = "1.0.0-rc.3"
zerodds-cdr = "1.0.0-rc.3"
zerodds-qos = "1.0.0-rc.3"
zerodds-types = "1.0.0-rc.3"
From source
Typed topics — DdsType
Variant A — #[derive(DdsType)]
use zerodds_cdr_derive::DdsType; // derive macro
use zerodds_dcps::DdsType; // trait
#[derive(DdsType, Debug, Clone)]
#[dds(type_name = "sensor_msgs::msg::Temperature")]
pub struct Temperature {
pub celsius: i32,
pub sensor_id: String,
}
// use it
let topic = p.create_topic::<Temperature>("Temp", TopicQos::default())?;
let writer = pub.create_datawriter::<Temperature>(&topic, DataWriterQos::default())?;
writer.write(&Temperature { celsius: 23, sensor_id: "A7".into() })?;
▶ Runnable example: rust-typed
Variant B — IDL via zerodds-idlc --rust
# IDL
echo 'struct Temperature { long celsius; string sensor_id; };' > temperature.idl
zerodds-idlc --rust temperature.idl -o gen/
# build.rs
fn main() {
println!("cargo:rerun-if-changed=temperature.idl");
// zerodds-idlc --rust temperature.idl -o $OUT_DIR/gen
}
Variant A is more idiomatic (a derive macro), B is for when you use IDL as the source of truth (cross-language consistency).
async / streams
ZeroDDS has a separate async adapter crate (zerodds-dcps-async) — it wraps the sync API with Tokio tasks.
use std::time::Duration;
use zerodds_dcps_async::*;
use zerodds_dcps::RawBytes;
#[tokio::main]
async fn main() -> Result<()> {
let factory = AsyncDomainParticipantFactory::instance();
let p = factory.create_participant(0)?;
let topic = p.create_topic::<RawBytes>("Chatter", TopicQos::default())?;
let writer = p.create_publisher(PublisherQos::default())
.create_datawriter::<RawBytes>(&topic, DataWriterQos::default())?;
let reader = p.create_subscriber(SubscriberQos::default())
.create_datareader::<RawBytes>(&topic, DataReaderQos::default())?;
writer.wait_for_matched_subscription(1, Duration::from_secs(5)).await?;
reader.wait_for_matched_publication(1, Duration::from_secs(5)).await?;
writer.write(&RawBytes::new(b"hello".to_vec())).await?;
for sample in reader.take(Duration::from_secs(3)).await? {
println!("got: {:?}", sample.data);
}
Ok(())
}
no_std + alloc
Layer 1 (foundation, cdr, qos, types) is no_std-capable with the opt-in alloc feature:
[dependencies]
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false, features = ["alloc"] }
zerodds-cdr = { version = "1.0.0-rc.3", default-features = false, features = ["alloc"] }
Strict no_std (no heap):
zerodds-foundation = { version = "1.0.0-rc.3", default-features = false }
Details: Dev Install — feature flags.