use crate::qos_profiles::{Durability, History, QosProfile, Reliability};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum RmwHistory {
SystemDefault = 0,
KeepLast = 1,
KeepAll = 2,
Unknown = 3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum RmwReliability {
SystemDefault = 0,
Reliable = 1,
BestEffort = 2,
Unknown = 3,
BestAvailable = 4,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum RmwDurability {
SystemDefault = 0,
TransientLocal = 1,
Volatile = 2,
Unknown = 3,
BestAvailable = 4,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct RmwQosProfile {
pub history: RmwHistory,
pub depth: usize,
pub reliability: RmwReliability,
pub durability: RmwDurability,
pub avoid_ros_namespace_conventions: bool,
}
impl RmwQosProfile {
#[must_use]
pub const fn default_profile() -> Self {
Self {
history: RmwHistory::KeepLast,
depth: 10,
reliability: RmwReliability::Reliable,
durability: RmwDurability::Volatile,
avoid_ros_namespace_conventions: false,
}
}
#[must_use]
pub const fn sensor_data() -> Self {
Self {
history: RmwHistory::KeepLast,
depth: 5,
reliability: RmwReliability::BestEffort,
durability: RmwDurability::Volatile,
avoid_ros_namespace_conventions: false,
}
}
#[must_use]
pub const fn parameters() -> Self {
Self {
history: RmwHistory::KeepLast,
depth: 1000,
reliability: RmwReliability::Reliable,
durability: RmwDurability::Volatile,
avoid_ros_namespace_conventions: false,
}
}
#[must_use]
pub const fn services_default() -> Self {
Self {
history: RmwHistory::KeepLast,
depth: 10,
reliability: RmwReliability::Reliable,
durability: RmwDurability::Volatile,
avoid_ros_namespace_conventions: false,
}
}
}
#[must_use]
pub fn rmw_to_dds(profile: &RmwQosProfile) -> QosProfile {
let history = match profile.history {
RmwHistory::KeepAll => History::KeepAll,
_ => History::KeepLast(profile.depth as u32),
};
let reliability = match profile.reliability {
RmwReliability::BestEffort => Reliability::BestEffort,
RmwReliability::BestAvailable => Reliability::BestEffort,
_ => Reliability::Reliable,
};
let durability = match profile.durability {
RmwDurability::TransientLocal => Durability::TransientLocal,
_ => Durability::Volatile,
};
QosProfile {
history,
reliability,
durability,
liveliness_lease_secs: None,
deadline_secs: None,
}
}
#[must_use]
pub fn dds_to_rmw(profile: &QosProfile) -> RmwQosProfile {
let (history, depth) = match profile.history {
History::KeepAll => (RmwHistory::KeepAll, 0),
History::KeepLast(d) => (RmwHistory::KeepLast, d as usize),
};
let reliability = match profile.reliability {
Reliability::Reliable => RmwReliability::Reliable,
Reliability::BestEffort => RmwReliability::BestEffort,
};
let durability = match profile.durability {
Durability::TransientLocal => RmwDurability::TransientLocal,
Durability::Volatile => RmwDurability::Volatile,
};
RmwQosProfile {
history,
depth,
reliability,
durability,
avoid_ros_namespace_conventions: false,
}
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn default_profile_matches_rmw_spec() {
let p = RmwQosProfile::default_profile();
assert_eq!(p.history, RmwHistory::KeepLast);
assert_eq!(p.depth, 10);
assert_eq!(p.reliability, RmwReliability::Reliable);
assert_eq!(p.durability, RmwDurability::Volatile);
}
#[test]
fn sensor_data_is_best_effort() {
let p = RmwQosProfile::sensor_data();
assert_eq!(p.reliability, RmwReliability::BestEffort);
assert_eq!(p.depth, 5);
}
#[test]
fn parameters_uses_keep_last_1000() {
let p = RmwQosProfile::parameters();
assert_eq!(p.depth, 1000);
assert_eq!(p.reliability, RmwReliability::Reliable);
}
#[test]
fn rmw_to_dds_round_trip_default() {
let rmw = RmwQosProfile::default_profile();
let dds = rmw_to_dds(&rmw);
let rmw2 = dds_to_rmw(&dds);
assert_eq!(rmw.reliability, rmw2.reliability);
assert_eq!(rmw.durability, rmw2.durability);
assert_eq!(rmw.depth, rmw2.depth);
}
#[test]
fn rmw_to_dds_keep_all_passes_through() {
let rmw = RmwQosProfile {
history: RmwHistory::KeepAll,
depth: 0,
reliability: RmwReliability::Reliable,
durability: RmwDurability::Volatile,
avoid_ros_namespace_conventions: false,
};
let dds = rmw_to_dds(&rmw);
assert!(matches!(dds.history, History::KeepAll));
}
#[test]
fn rmw_best_available_maps_to_best_effort_on_sender() {
let rmw = RmwQosProfile {
history: RmwHistory::KeepLast,
depth: 5,
reliability: RmwReliability::BestAvailable,
durability: RmwDurability::Volatile,
avoid_ros_namespace_conventions: false,
};
let dds = rmw_to_dds(&rmw);
assert_eq!(dds.reliability, Reliability::BestEffort);
}
#[test]
fn rmw_system_default_maps_to_dds_reliable() {
let rmw = RmwQosProfile {
history: RmwHistory::SystemDefault,
depth: 0,
reliability: RmwReliability::SystemDefault,
durability: RmwDurability::SystemDefault,
avoid_ros_namespace_conventions: false,
};
let dds = rmw_to_dds(&rmw);
assert_eq!(dds.reliability, Reliability::Reliable);
assert_eq!(dds.durability, Durability::Volatile);
}
#[test]
fn transient_local_round_trips() {
let rmw = RmwQosProfile {
history: RmwHistory::KeepLast,
depth: 1,
reliability: RmwReliability::Reliable,
durability: RmwDurability::TransientLocal,
avoid_ros_namespace_conventions: false,
};
let dds = rmw_to_dds(&rmw);
assert_eq!(dds.durability, Durability::TransientLocal);
}
#[test]
fn services_default_uses_keep_last_10() {
let p = RmwQosProfile::services_default();
assert_eq!(p.depth, 10);
assert_eq!(p.reliability, RmwReliability::Reliable);
}
#[test]
fn enum_repr_is_c_compatible() {
assert_eq!(RmwHistory::SystemDefault as u32, 0);
assert_eq!(RmwHistory::KeepLast as u32, 1);
assert_eq!(RmwHistory::KeepAll as u32, 2);
assert_eq!(RmwReliability::Reliable as u32, 1);
assert_eq!(RmwReliability::BestEffort as u32, 2);
}
}