use std::ffi::CString;
use std::time::Duration;
use zenrc_dds::{
dds_durability_kind_DDS_DURABILITY_PERSISTENT, dds_durability_kind_DDS_DURABILITY_TRANSIENT,
dds_durability_kind_DDS_DURABILITY_TRANSIENT_LOCAL,
dds_durability_kind_DDS_DURABILITY_VOLATILE, dds_history_kind_DDS_HISTORY_KEEP_ALL,
dds_history_kind_DDS_HISTORY_KEEP_LAST,
dds_liveliness_kind_DDS_LIVELINESS_AUTOMATIC,
dds_liveliness_kind_DDS_LIVELINESS_MANUAL_BY_PARTICIPANT,
dds_liveliness_kind_DDS_LIVELINESS_MANUAL_BY_TOPIC,
dds_ownership_kind_DDS_OWNERSHIP_EXCLUSIVE, dds_ownership_kind_DDS_OWNERSHIP_SHARED,
dds_reliability_kind_DDS_RELIABILITY_BEST_EFFORT,
dds_reliability_kind_DDS_RELIABILITY_RELIABLE, dds_qos_t,
};
use super::error::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Reliability {
BestEffort,
Reliable,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Durability {
Volatile,
TransientLocal,
Transient,
Persistent,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum History {
KeepLast(i32),
KeepAll,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Liveliness {
Automatic,
ManualByParticipant,
ManualByTopic,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Ownership {
Shared,
Exclusive,
}
pub const DURATION_INFINITE: i64 = i64::MAX;
#[inline]
pub(crate) fn duration_to_nanos(d: Duration) -> i64 {
d.as_nanos().min(i64::MAX as u128) as i64
}
pub struct Qos {
pub(crate) raw: *mut dds_qos_t,
}
unsafe impl Send for Qos {}
unsafe impl Sync for Qos {}
impl Qos {
pub fn new() -> Self {
let raw = unsafe { zenrc_dds::dds_create_qos() };
assert!(!raw.is_null(), "dds_create_qos 返回 null");
Self { raw }
}
pub fn reliability(self, kind: Reliability, max_blocking: Duration) -> Self {
let raw_kind = match kind {
Reliability::BestEffort => dds_reliability_kind_DDS_RELIABILITY_BEST_EFFORT,
Reliability::Reliable => dds_reliability_kind_DDS_RELIABILITY_RELIABLE,
};
unsafe {
zenrc_dds::dds_qset_reliability(self.raw, raw_kind, duration_to_nanos(max_blocking));
}
self
}
pub fn durability(self, kind: Durability) -> Self {
let raw_kind = match kind {
Durability::Volatile => dds_durability_kind_DDS_DURABILITY_VOLATILE,
Durability::TransientLocal => dds_durability_kind_DDS_DURABILITY_TRANSIENT_LOCAL,
Durability::Transient => dds_durability_kind_DDS_DURABILITY_TRANSIENT,
Durability::Persistent => dds_durability_kind_DDS_DURABILITY_PERSISTENT,
};
unsafe {
zenrc_dds::dds_qset_durability(self.raw, raw_kind);
}
self
}
pub fn history(self, kind: History) -> Self {
let (raw_kind, depth) = match kind {
History::KeepLast(n) => (dds_history_kind_DDS_HISTORY_KEEP_LAST, n),
History::KeepAll => (dds_history_kind_DDS_HISTORY_KEEP_ALL, -1),
};
unsafe {
zenrc_dds::dds_qset_history(self.raw, raw_kind, depth);
}
self
}
pub fn deadline(self, period: Duration) -> Self {
unsafe {
zenrc_dds::dds_qset_deadline(self.raw, duration_to_nanos(period));
}
self
}
pub fn lifespan(self, duration: Duration) -> Self {
unsafe {
zenrc_dds::dds_qset_lifespan(self.raw, duration_to_nanos(duration));
}
self
}
pub fn latency_budget(self, duration: Duration) -> Self {
unsafe {
zenrc_dds::dds_qset_latency_budget(self.raw, duration_to_nanos(duration));
}
self
}
pub fn liveliness(self, kind: Liveliness, lease_duration: Duration) -> Self {
let raw_kind = match kind {
Liveliness::Automatic => dds_liveliness_kind_DDS_LIVELINESS_AUTOMATIC,
Liveliness::ManualByParticipant => {
dds_liveliness_kind_DDS_LIVELINESS_MANUAL_BY_PARTICIPANT
}
Liveliness::ManualByTopic => dds_liveliness_kind_DDS_LIVELINESS_MANUAL_BY_TOPIC,
};
unsafe {
zenrc_dds::dds_qset_liveliness(self.raw, raw_kind, duration_to_nanos(lease_duration));
}
self
}
pub fn ownership(self, kind: Ownership) -> Self {
let raw_kind = match kind {
Ownership::Shared => dds_ownership_kind_DDS_OWNERSHIP_SHARED,
Ownership::Exclusive => dds_ownership_kind_DDS_OWNERSHIP_EXCLUSIVE,
};
unsafe {
zenrc_dds::dds_qset_ownership(self.raw, raw_kind);
}
self
}
pub fn ownership_strength(self, value: i32) -> Self {
unsafe {
zenrc_dds::dds_qset_ownership_strength(self.raw, value);
}
self
}
pub fn partition(self, partitions: &[&str]) -> Result<Self> {
let c_strs: Vec<CString> = partitions
.iter()
.map(|s| CString::new(*s))
.collect::<std::result::Result<_, _>>()?;
let mut ptrs: Vec<*const std::os::raw::c_char> =
c_strs.iter().map(|s| s.as_ptr()).collect();
unsafe {
zenrc_dds::dds_qset_partition(self.raw, ptrs.len() as u32, ptrs.as_mut_ptr());
}
Ok(self)
}
pub fn partition1(self, name: &str) -> Result<Self> {
let c_name = CString::new(name)?;
unsafe {
zenrc_dds::dds_qset_partition1(self.raw, c_name.as_ptr());
}
Ok(self)
}
pub fn resource_limits(
self,
max_samples: i32,
max_instances: i32,
max_samples_per_instance: i32,
) -> Self {
unsafe {
zenrc_dds::dds_qset_resource_limits(
self.raw,
max_samples,
max_instances,
max_samples_per_instance,
);
}
self
}
pub fn entity_name(self, name: &str) -> Result<Self> {
let c_name = CString::new(name)?;
unsafe {
zenrc_dds::dds_qset_entity_name(self.raw, c_name.as_ptr());
}
Ok(self)
}
pub fn sensor_data() -> Self {
Self::new()
.reliability(Reliability::BestEffort, Duration::from_millis(100))
.history(History::KeepLast(5))
.durability(Durability::Volatile)
}
pub fn system_default() -> Self {
Self::new()
.reliability(Reliability::Reliable, Duration::from_millis(100))
.history(History::KeepLast(10))
}
pub fn services_default() -> Self {
Self::new()
.reliability(Reliability::Reliable, Duration::from_millis(1000))
.history(History::KeepLast(10))
.durability(Durability::Volatile)
}
pub fn parameters() -> Self {
Self::new()
.reliability(Reliability::Reliable, Duration::from_millis(1000))
.history(History::KeepLast(1000))
.durability(Durability::Volatile)
}
pub fn action_status_default() -> Self {
Self::new()
.reliability(Reliability::Reliable, Duration::from_millis(1000))
.history(History::KeepLast(1))
.durability(Durability::TransientLocal)
}
pub fn clock() -> Self {
Self::new()
.reliability(Reliability::BestEffort, Duration::from_millis(100))
.history(History::KeepLast(1))
}
pub fn transient_local() -> Self {
Self::new()
.reliability(Reliability::Reliable, Duration::from_millis(100))
.history(History::KeepLast(1))
.durability(Durability::TransientLocal)
}
}
impl Default for Qos {
fn default() -> Self {
Self::new()
}
}
impl Drop for Qos {
fn drop(&mut self) {
unsafe { zenrc_dds::dds_delete_qos(self.raw) };
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn duration_to_nanos_zero() {
assert_eq!(duration_to_nanos(Duration::ZERO), 0);
}
#[test]
fn duration_to_nanos_one_second() {
assert_eq!(duration_to_nanos(Duration::from_secs(1)), 1_000_000_000);
}
#[test]
fn duration_to_nanos_100ms() {
assert_eq!(duration_to_nanos(Duration::from_millis(100)), 100_000_000);
}
#[test]
fn duration_to_nanos_1us() {
assert_eq!(duration_to_nanos(Duration::from_micros(1)), 1_000);
}
#[test]
fn duration_to_nanos_saturates_at_i64_max() {
let huge = Duration::from_secs(u64::MAX);
assert_eq!(duration_to_nanos(huge), i64::MAX);
}
}