use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::ffi::{c_char, c_int};
use core::ptr;
use core::slice;
use std::ffi::CStr;
use zerodds_dcps::factory::DomainParticipantFactoryQos;
use zerodds_dcps::qos::{
DataReaderQos, DataWriterQos, DomainParticipantQos, PublisherQos, SubscriberQos, TopicQos,
};
use zerodds_qos::{
DeadlineQosPolicy, DestinationOrderKind, DestinationOrderQosPolicy, DurabilityKind,
DurabilityQosPolicy, DurabilityServiceQosPolicy, Duration, EntityFactoryQosPolicy,
GroupDataQosPolicy, HistoryKind, HistoryQosPolicy, LatencyBudgetQosPolicy, LifespanQosPolicy,
LivelinessKind, LivelinessQosPolicy, OwnershipKind, OwnershipQosPolicy,
OwnershipStrengthQosPolicy, PartitionQosPolicy, PresentationAccessScope, PresentationQosPolicy,
ReaderDataLifecycleQosPolicy, ReliabilityKind, ReliabilityQosPolicy, ResourceLimitsQosPolicy,
TimeBasedFilterQosPolicy, TopicDataQosPolicy, TransportPriorityQosPolicy, UserDataQosPolicy,
WriterDataLifecycleQosPolicy,
};
use crate::ZeroDdsStatus;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDuration {
pub sec: i32,
pub nanosec: u32,
}
impl ZeroDdsDuration {
pub const INFINITE: Self = Self {
sec: i32::MAX,
nanosec: u32::MAX,
};
}
impl From<Duration> for ZeroDdsDuration {
fn from(d: Duration) -> Self {
if d.is_infinite() {
return Self::INFINITE;
}
let nanosec = ((d.fraction as u64 * 1_000_000_000) >> 32) as u32;
Self {
sec: d.seconds,
nanosec,
}
}
}
impl From<ZeroDdsDuration> for Duration {
fn from(d: ZeroDdsDuration) -> Self {
if d.sec == i32::MAX && d.nanosec == u32::MAX {
return Duration::INFINITE;
}
let fraction = ((d.nanosec as u64) << 32) / 1_000_000_000;
Duration {
seconds: d.sec,
fraction: fraction as u32,
}
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ZeroDdsReliabilityKind {
BestEffort = 1,
Reliable = 2,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ZeroDdsDurabilityKind {
Volatile = 0,
TransientLocal = 1,
Transient = 2,
Persistent = 3,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ZeroDdsLivelinessKind {
Automatic = 0,
ManualByParticipant = 1,
ManualByTopic = 2,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ZeroDdsHistoryKind {
KeepLast = 0,
KeepAll = 1,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ZeroDdsOwnershipKind {
Shared = 0,
Exclusive = 1,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ZeroDdsDestinationOrderKind {
ByReceptionTimestamp = 0,
BySourceTimestamp = 1,
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ZeroDdsPresentationAccessScope {
Instance = 0,
Topic = 1,
Group = 2,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsReliabilityQosPolicy {
pub kind: u32,
pub max_blocking_time: ZeroDdsDuration,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDurabilityQosPolicy {
pub kind: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsHistoryQosPolicy {
pub kind: u32,
pub depth: i32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDeadlineQosPolicy {
pub period: ZeroDdsDuration,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsLifespanQosPolicy {
pub duration: ZeroDdsDuration,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsLatencyBudgetQosPolicy {
pub duration: ZeroDdsDuration,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsTimeBasedFilterQosPolicy {
pub minimum_separation: ZeroDdsDuration,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsLivelinessQosPolicy {
pub kind: u32,
pub lease_duration: ZeroDdsDuration,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsOwnershipQosPolicy {
pub kind: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsOwnershipStrengthQosPolicy {
pub value: i32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDestinationOrderQosPolicy {
pub kind: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsPresentationQosPolicy {
pub access_scope: u32,
pub coherent_access: bool,
pub ordered_access: bool,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsResourceLimitsQosPolicy {
pub max_samples: i32,
pub max_instances: i32,
pub max_samples_per_instance: i32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsTransportPriorityQosPolicy {
pub value: i32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsEntityFactoryQosPolicy {
pub autoenable_created_entities: bool,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsWriterDataLifecycleQosPolicy {
pub autodispose_unregistered_instances: bool,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsReaderDataLifecycleQosPolicy {
pub autopurge_nowriter_samples_delay: ZeroDdsDuration,
pub autopurge_disposed_samples_delay: ZeroDdsDuration,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDurabilityServiceQosPolicy {
pub service_cleanup_delay: ZeroDdsDuration,
pub history_kind: u32,
pub history_depth: i32,
pub max_samples: i32,
pub max_instances: i32,
pub max_samples_per_instance: i32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsUserDataQosPolicy {
pub value: *const u8,
pub value_len: usize,
}
pub type ZeroDdsTopicDataQosPolicy = ZeroDdsUserDataQosPolicy;
pub type ZeroDdsGroupDataQosPolicy = ZeroDdsUserDataQosPolicy;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsPartitionQosPolicy {
pub names: *const *const c_char,
pub names_len: usize,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDomainParticipantFactoryQos {
pub entity_factory: ZeroDdsEntityFactoryQosPolicy,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDomainParticipantQos {
pub user_data: ZeroDdsUserDataQosPolicy,
pub entity_factory: ZeroDdsEntityFactoryQosPolicy,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsTopicQos {
pub durability: ZeroDdsDurabilityQosPolicy,
pub durability_service: ZeroDdsDurabilityServiceQosPolicy,
pub deadline: ZeroDdsDeadlineQosPolicy,
pub latency_budget: ZeroDdsLatencyBudgetQosPolicy,
pub liveliness: ZeroDdsLivelinessQosPolicy,
pub reliability: ZeroDdsReliabilityQosPolicy,
pub destination_order: ZeroDdsDestinationOrderQosPolicy,
pub history: ZeroDdsHistoryQosPolicy,
pub resource_limits: ZeroDdsResourceLimitsQosPolicy,
pub transport_priority: ZeroDdsTransportPriorityQosPolicy,
pub lifespan: ZeroDdsLifespanQosPolicy,
pub ownership: ZeroDdsOwnershipQosPolicy,
pub topic_data: ZeroDdsTopicDataQosPolicy,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsPublisherQos {
pub presentation: ZeroDdsPresentationQosPolicy,
pub partition: ZeroDdsPartitionQosPolicy,
pub group_data: ZeroDdsGroupDataQosPolicy,
pub entity_factory: ZeroDdsEntityFactoryQosPolicy,
}
pub type ZeroDdsSubscriberQos = ZeroDdsPublisherQos;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDataWriterQos {
pub reliability: ZeroDdsReliabilityQosPolicy,
pub durability: ZeroDdsDurabilityQosPolicy,
pub durability_service: ZeroDdsDurabilityServiceQosPolicy,
pub deadline: ZeroDdsDeadlineQosPolicy,
pub latency_budget: ZeroDdsLatencyBudgetQosPolicy,
pub liveliness: ZeroDdsLivelinessQosPolicy,
pub destination_order: ZeroDdsDestinationOrderQosPolicy,
pub lifespan: ZeroDdsLifespanQosPolicy,
pub ownership: ZeroDdsOwnershipQosPolicy,
pub ownership_strength: ZeroDdsOwnershipStrengthQosPolicy,
pub partition: ZeroDdsPartitionQosPolicy,
pub presentation: ZeroDdsPresentationQosPolicy,
pub history: ZeroDdsHistoryQosPolicy,
pub resource_limits: ZeroDdsResourceLimitsQosPolicy,
pub transport_priority: ZeroDdsTransportPriorityQosPolicy,
pub writer_data_lifecycle: ZeroDdsWriterDataLifecycleQosPolicy,
pub user_data: ZeroDdsUserDataQosPolicy,
pub topic_data: ZeroDdsTopicDataQosPolicy,
pub group_data: ZeroDdsGroupDataQosPolicy,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsDataReaderQos {
pub reliability: ZeroDdsReliabilityQosPolicy,
pub durability: ZeroDdsDurabilityQosPolicy,
pub deadline: ZeroDdsDeadlineQosPolicy,
pub latency_budget: ZeroDdsLatencyBudgetQosPolicy,
pub liveliness: ZeroDdsLivelinessQosPolicy,
pub destination_order: ZeroDdsDestinationOrderQosPolicy,
pub ownership: ZeroDdsOwnershipQosPolicy,
pub partition: ZeroDdsPartitionQosPolicy,
pub presentation: ZeroDdsPresentationQosPolicy,
pub history: ZeroDdsHistoryQosPolicy,
pub resource_limits: ZeroDdsResourceLimitsQosPolicy,
pub time_based_filter: ZeroDdsTimeBasedFilterQosPolicy,
pub reader_data_lifecycle: ZeroDdsReaderDataLifecycleQosPolicy,
pub user_data: ZeroDdsUserDataQosPolicy,
pub topic_data: ZeroDdsTopicDataQosPolicy,
pub group_data: ZeroDdsGroupDataQosPolicy,
}
unsafe fn slice_or_empty<'a>(p: *const u8, n: usize) -> &'a [u8] {
if p.is_null() || n == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(p, n) }
}
}
unsafe fn cstr_vec(arr: *const *const c_char, n: usize) -> Vec<String> {
if arr.is_null() || n == 0 {
return Vec::new();
}
let slc = unsafe { slice::from_raw_parts(arr, n) };
let mut out = Vec::with_capacity(n);
for &p in slc {
if p.is_null() {
continue;
}
let cs = unsafe { CStr::from_ptr(p) };
if let Ok(s) = cs.to_str() {
out.push(s.to_string());
}
}
out
}
impl From<ZeroDdsReliabilityQosPolicy> for ReliabilityQosPolicy {
fn from(c: ZeroDdsReliabilityQosPolicy) -> Self {
Self {
kind: ReliabilityKind::from_u32(c.kind),
max_blocking_time: c.max_blocking_time.into(),
}
}
}
impl From<ReliabilityQosPolicy> for ZeroDdsReliabilityQosPolicy {
fn from(r: ReliabilityQosPolicy) -> Self {
Self {
kind: r.kind as u32,
max_blocking_time: r.max_blocking_time.into(),
}
}
}
impl From<ZeroDdsDurabilityQosPolicy> for DurabilityQosPolicy {
fn from(c: ZeroDdsDurabilityQosPolicy) -> Self {
Self {
kind: DurabilityKind::from_u32(c.kind),
}
}
}
impl From<DurabilityQosPolicy> for ZeroDdsDurabilityQosPolicy {
fn from(r: DurabilityQosPolicy) -> Self {
Self {
kind: r.kind as u32,
}
}
}
impl From<ZeroDdsHistoryQosPolicy> for HistoryQosPolicy {
fn from(c: ZeroDdsHistoryQosPolicy) -> Self {
Self {
kind: HistoryKind::from_u32(c.kind),
depth: c.depth,
}
}
}
impl From<HistoryQosPolicy> for ZeroDdsHistoryQosPolicy {
fn from(r: HistoryQosPolicy) -> Self {
Self {
kind: r.kind as u32,
depth: r.depth,
}
}
}
impl From<ZeroDdsDeadlineQosPolicy> for DeadlineQosPolicy {
fn from(c: ZeroDdsDeadlineQosPolicy) -> Self {
Self {
period: c.period.into(),
}
}
}
impl From<DeadlineQosPolicy> for ZeroDdsDeadlineQosPolicy {
fn from(r: DeadlineQosPolicy) -> Self {
Self {
period: r.period.into(),
}
}
}
impl From<ZeroDdsLifespanQosPolicy> for LifespanQosPolicy {
fn from(c: ZeroDdsLifespanQosPolicy) -> Self {
Self {
duration: c.duration.into(),
}
}
}
impl From<LifespanQosPolicy> for ZeroDdsLifespanQosPolicy {
fn from(r: LifespanQosPolicy) -> Self {
Self {
duration: r.duration.into(),
}
}
}
impl From<ZeroDdsLatencyBudgetQosPolicy> for LatencyBudgetQosPolicy {
fn from(c: ZeroDdsLatencyBudgetQosPolicy) -> Self {
Self {
duration: c.duration.into(),
}
}
}
impl From<LatencyBudgetQosPolicy> for ZeroDdsLatencyBudgetQosPolicy {
fn from(r: LatencyBudgetQosPolicy) -> Self {
Self {
duration: r.duration.into(),
}
}
}
impl From<ZeroDdsTimeBasedFilterQosPolicy> for TimeBasedFilterQosPolicy {
fn from(c: ZeroDdsTimeBasedFilterQosPolicy) -> Self {
Self {
minimum_separation: c.minimum_separation.into(),
}
}
}
impl From<TimeBasedFilterQosPolicy> for ZeroDdsTimeBasedFilterQosPolicy {
fn from(r: TimeBasedFilterQosPolicy) -> Self {
Self {
minimum_separation: r.minimum_separation.into(),
}
}
}
impl From<ZeroDdsLivelinessQosPolicy> for LivelinessQosPolicy {
fn from(c: ZeroDdsLivelinessQosPolicy) -> Self {
Self {
kind: LivelinessKind::from_u32(c.kind),
lease_duration: c.lease_duration.into(),
}
}
}
impl From<LivelinessQosPolicy> for ZeroDdsLivelinessQosPolicy {
fn from(r: LivelinessQosPolicy) -> Self {
Self {
kind: r.kind as u32,
lease_duration: r.lease_duration.into(),
}
}
}
impl From<ZeroDdsOwnershipQosPolicy> for OwnershipQosPolicy {
fn from(c: ZeroDdsOwnershipQosPolicy) -> Self {
Self {
kind: OwnershipKind::from_u32(c.kind),
}
}
}
impl From<OwnershipQosPolicy> for ZeroDdsOwnershipQosPolicy {
fn from(r: OwnershipQosPolicy) -> Self {
Self {
kind: r.kind as u32,
}
}
}
impl From<ZeroDdsOwnershipStrengthQosPolicy> for OwnershipStrengthQosPolicy {
fn from(c: ZeroDdsOwnershipStrengthQosPolicy) -> Self {
Self { value: c.value }
}
}
impl From<OwnershipStrengthQosPolicy> for ZeroDdsOwnershipStrengthQosPolicy {
fn from(r: OwnershipStrengthQosPolicy) -> Self {
Self { value: r.value }
}
}
impl From<ZeroDdsDestinationOrderQosPolicy> for DestinationOrderQosPolicy {
fn from(c: ZeroDdsDestinationOrderQosPolicy) -> Self {
Self {
kind: DestinationOrderKind::from_u32(c.kind),
}
}
}
impl From<DestinationOrderQosPolicy> for ZeroDdsDestinationOrderQosPolicy {
fn from(r: DestinationOrderQosPolicy) -> Self {
Self {
kind: r.kind as u32,
}
}
}
impl From<ZeroDdsPresentationQosPolicy> for PresentationQosPolicy {
fn from(c: ZeroDdsPresentationQosPolicy) -> Self {
Self {
access_scope: PresentationAccessScope::from_u32(c.access_scope),
coherent_access: c.coherent_access,
ordered_access: c.ordered_access,
}
}
}
impl From<PresentationQosPolicy> for ZeroDdsPresentationQosPolicy {
fn from(r: PresentationQosPolicy) -> Self {
Self {
access_scope: r.access_scope as u32,
coherent_access: r.coherent_access,
ordered_access: r.ordered_access,
}
}
}
impl From<ZeroDdsResourceLimitsQosPolicy> for ResourceLimitsQosPolicy {
fn from(c: ZeroDdsResourceLimitsQosPolicy) -> Self {
Self {
max_samples: c.max_samples,
max_instances: c.max_instances,
max_samples_per_instance: c.max_samples_per_instance,
}
}
}
impl From<ResourceLimitsQosPolicy> for ZeroDdsResourceLimitsQosPolicy {
fn from(r: ResourceLimitsQosPolicy) -> Self {
Self {
max_samples: r.max_samples,
max_instances: r.max_instances,
max_samples_per_instance: r.max_samples_per_instance,
}
}
}
impl From<ZeroDdsTransportPriorityQosPolicy> for TransportPriorityQosPolicy {
fn from(c: ZeroDdsTransportPriorityQosPolicy) -> Self {
Self { value: c.value }
}
}
impl From<TransportPriorityQosPolicy> for ZeroDdsTransportPriorityQosPolicy {
fn from(r: TransportPriorityQosPolicy) -> Self {
Self { value: r.value }
}
}
impl From<ZeroDdsEntityFactoryQosPolicy> for EntityFactoryQosPolicy {
fn from(c: ZeroDdsEntityFactoryQosPolicy) -> Self {
Self {
autoenable_created_entities: c.autoenable_created_entities,
}
}
}
impl From<EntityFactoryQosPolicy> for ZeroDdsEntityFactoryQosPolicy {
fn from(r: EntityFactoryQosPolicy) -> Self {
Self {
autoenable_created_entities: r.autoenable_created_entities,
}
}
}
impl From<ZeroDdsWriterDataLifecycleQosPolicy> for WriterDataLifecycleQosPolicy {
fn from(c: ZeroDdsWriterDataLifecycleQosPolicy) -> Self {
let mut p = WriterDataLifecycleQosPolicy::default();
p.autodispose_unregistered_instances = c.autodispose_unregistered_instances;
p
}
}
impl From<WriterDataLifecycleQosPolicy> for ZeroDdsWriterDataLifecycleQosPolicy {
fn from(r: WriterDataLifecycleQosPolicy) -> Self {
Self {
autodispose_unregistered_instances: r.autodispose_unregistered_instances,
}
}
}
impl From<ZeroDdsReaderDataLifecycleQosPolicy> for ReaderDataLifecycleQosPolicy {
fn from(c: ZeroDdsReaderDataLifecycleQosPolicy) -> Self {
let mut p = ReaderDataLifecycleQosPolicy::default();
p.autopurge_nowriter_samples_delay = c.autopurge_nowriter_samples_delay.into();
p.autopurge_disposed_samples_delay = c.autopurge_disposed_samples_delay.into();
p
}
}
impl From<ReaderDataLifecycleQosPolicy> for ZeroDdsReaderDataLifecycleQosPolicy {
fn from(r: ReaderDataLifecycleQosPolicy) -> Self {
Self {
autopurge_nowriter_samples_delay: r.autopurge_nowriter_samples_delay.into(),
autopurge_disposed_samples_delay: r.autopurge_disposed_samples_delay.into(),
}
}
}
impl From<ZeroDdsDurabilityServiceQosPolicy> for DurabilityServiceQosPolicy {
fn from(c: ZeroDdsDurabilityServiceQosPolicy) -> Self {
Self {
service_cleanup_delay: c.service_cleanup_delay.into(),
history_kind: HistoryKind::from_u32(c.history_kind),
history_depth: c.history_depth,
max_samples: c.max_samples,
max_instances: c.max_instances,
max_samples_per_instance: c.max_samples_per_instance,
}
}
}
impl From<DurabilityServiceQosPolicy> for ZeroDdsDurabilityServiceQosPolicy {
fn from(r: DurabilityServiceQosPolicy) -> Self {
Self {
service_cleanup_delay: r.service_cleanup_delay.into(),
history_kind: r.history_kind as u32,
history_depth: r.history_depth,
max_samples: r.max_samples,
max_instances: r.max_instances,
max_samples_per_instance: r.max_samples_per_instance,
}
}
}
pub unsafe fn dw_qos_from_c(c: *const ZeroDdsDataWriterQos) -> DataWriterQos {
if c.is_null() {
return DataWriterQos::default();
}
let q = unsafe { &*c };
DataWriterQos {
reliability: q.reliability.into(),
durability: q.durability.into(),
durability_service: q.durability_service.into(),
deadline: q.deadline.into(),
latency_budget: q.latency_budget.into(),
liveliness: q.liveliness.into(),
destination_order: q.destination_order.into(),
lifespan: q.lifespan.into(),
ownership: q.ownership.into(),
ownership_strength: q.ownership_strength.into(),
partition: PartitionQosPolicy {
names: unsafe { cstr_vec(q.partition.names, q.partition.names_len) },
},
presentation: q.presentation.into(),
history: q.history.into(),
resource_limits: q.resource_limits.into(),
transport_priority: q.transport_priority.into(),
writer_data_lifecycle: q.writer_data_lifecycle.into(),
user_data: UserDataQosPolicy {
value: unsafe { slice_or_empty(q.user_data.value, q.user_data.value_len) }.to_vec(),
},
topic_data: TopicDataQosPolicy {
value: unsafe { slice_or_empty(q.topic_data.value, q.topic_data.value_len) }.to_vec(),
},
group_data: GroupDataQosPolicy {
value: unsafe { slice_or_empty(q.group_data.value, q.group_data.value_len) }.to_vec(),
},
}
}
pub unsafe fn dr_qos_from_c(c: *const ZeroDdsDataReaderQos) -> DataReaderQos {
if c.is_null() {
return DataReaderQos::default();
}
let q = unsafe { &*c };
DataReaderQos {
reliability: q.reliability.into(),
durability: q.durability.into(),
deadline: q.deadline.into(),
latency_budget: q.latency_budget.into(),
liveliness: q.liveliness.into(),
destination_order: q.destination_order.into(),
ownership: q.ownership.into(),
partition: PartitionQosPolicy {
names: unsafe { cstr_vec(q.partition.names, q.partition.names_len) },
},
presentation: q.presentation.into(),
history: q.history.into(),
resource_limits: q.resource_limits.into(),
time_based_filter: q.time_based_filter.into(),
reader_data_lifecycle: q.reader_data_lifecycle.into(),
user_data: UserDataQosPolicy {
value: unsafe { slice_or_empty(q.user_data.value, q.user_data.value_len) }.to_vec(),
},
topic_data: TopicDataQosPolicy {
value: unsafe { slice_or_empty(q.topic_data.value, q.topic_data.value_len) }.to_vec(),
},
group_data: GroupDataQosPolicy {
value: unsafe { slice_or_empty(q.group_data.value, q.group_data.value_len) }.to_vec(),
},
}
}
pub unsafe fn topic_qos_from_c(c: *const ZeroDdsTopicQos) -> TopicQos {
if c.is_null() {
return TopicQos::default();
}
let q = unsafe { &*c };
TopicQos {
durability: q.durability.into(),
durability_service: q.durability_service.into(),
deadline: q.deadline.into(),
latency_budget: q.latency_budget.into(),
liveliness: q.liveliness.into(),
reliability: q.reliability.into(),
destination_order: q.destination_order.into(),
history: q.history.into(),
resource_limits: q.resource_limits.into(),
transport_priority: q.transport_priority.into(),
lifespan: q.lifespan.into(),
ownership: q.ownership.into(),
topic_data: TopicDataQosPolicy {
value: unsafe { slice_or_empty(q.topic_data.value, q.topic_data.value_len) }.to_vec(),
},
}
}
pub unsafe fn pub_qos_from_c(c: *const ZeroDdsPublisherQos) -> PublisherQos {
if c.is_null() {
return PublisherQos::default();
}
let q = unsafe { &*c };
PublisherQos {
presentation: q.presentation.into(),
partition: PartitionQosPolicy {
names: unsafe { cstr_vec(q.partition.names, q.partition.names_len) },
},
group_data: GroupDataQosPolicy {
value: unsafe { slice_or_empty(q.group_data.value, q.group_data.value_len) }.to_vec(),
},
entity_factory: q.entity_factory.into(),
}
}
pub unsafe fn sub_qos_from_c(c: *const ZeroDdsSubscriberQos) -> SubscriberQos {
if c.is_null() {
return SubscriberQos::default();
}
let q = unsafe { &*c };
SubscriberQos {
presentation: q.presentation.into(),
partition: PartitionQosPolicy {
names: unsafe { cstr_vec(q.partition.names, q.partition.names_len) },
},
group_data: GroupDataQosPolicy {
value: unsafe { slice_or_empty(q.group_data.value, q.group_data.value_len) }.to_vec(),
},
entity_factory: q.entity_factory.into(),
}
}
pub unsafe fn dp_qos_from_c(c: *const ZeroDdsDomainParticipantQos) -> DomainParticipantQos {
if c.is_null() {
return DomainParticipantQos::default();
}
let q = unsafe { &*c };
DomainParticipantQos {
user_data: UserDataQosPolicy {
value: unsafe { slice_or_empty(q.user_data.value, q.user_data.value_len) }.to_vec(),
},
entity_factory: q.entity_factory.into(),
}
}
pub unsafe fn dpf_qos_from_c(
c: *const ZeroDdsDomainParticipantFactoryQos,
) -> DomainParticipantFactoryQos {
if c.is_null() {
return DomainParticipantFactoryQos::default();
}
let q = unsafe { &*c };
DomainParticipantFactoryQos {
autoenable_created_entities: q.entity_factory.autoenable_created_entities,
}
}
pub unsafe fn dp_qos_to_c(
r: &DomainParticipantQos,
out: *mut ZeroDdsDomainParticipantQos,
) -> c_int {
if out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let needed = r.user_data.value.len();
let cap = unsafe { (*out).user_data.value_len };
let dst_ptr = unsafe { (*out).user_data.value as *mut u8 };
if needed > 0 {
if dst_ptr.is_null() || cap < needed {
unsafe { (*out).user_data.value_len = needed };
return ZeroDdsStatus::OutOfResources as c_int;
}
unsafe {
ptr::copy_nonoverlapping(r.user_data.value.as_ptr(), dst_ptr, needed);
}
}
unsafe {
(*out).user_data.value_len = needed;
(*out).entity_factory = r.entity_factory.into();
}
ZeroDdsStatus::Ok as c_int
}
pub unsafe fn topic_qos_to_c(r: &TopicQos, out: *mut ZeroDdsTopicQos) -> c_int {
if out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let needed = r.topic_data.value.len();
let cap = unsafe { (*out).topic_data.value_len };
let dst_ptr = unsafe { (*out).topic_data.value as *mut u8 };
if needed > 0 {
if dst_ptr.is_null() || cap < needed {
unsafe { (*out).topic_data.value_len = needed };
return ZeroDdsStatus::OutOfResources as c_int;
}
unsafe { ptr::copy_nonoverlapping(r.topic_data.value.as_ptr(), dst_ptr, needed) };
}
unsafe {
(*out).topic_data.value_len = needed;
(*out).durability = r.durability.into();
(*out).durability_service = r.durability_service.into();
(*out).deadline = r.deadline.into();
(*out).latency_budget = r.latency_budget.into();
(*out).liveliness = r.liveliness.into();
(*out).reliability = r.reliability.into();
(*out).destination_order = r.destination_order.into();
(*out).history = r.history.into();
(*out).resource_limits = r.resource_limits.into();
(*out).transport_priority = r.transport_priority.into();
(*out).lifespan = r.lifespan.into();
(*out).ownership = r.ownership.into();
}
ZeroDdsStatus::Ok as c_int
}
pub unsafe fn dw_qos_to_c(r: &DataWriterQos, out: *mut ZeroDdsDataWriterQos) -> c_int {
if out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
macro_rules! copy_bytes {
($field:ident) => {{
let needed = r.$field.value.len();
let cap = unsafe { (*out).$field.value_len };
let dst = unsafe { (*out).$field.value as *mut u8 };
if needed > 0 {
if dst.is_null() || cap < needed {
unsafe { (*out).$field.value_len = needed };
return ZeroDdsStatus::OutOfResources as c_int;
}
unsafe { ptr::copy_nonoverlapping(r.$field.value.as_ptr(), dst, needed) };
}
unsafe { (*out).$field.value_len = needed };
}};
}
copy_bytes!(user_data);
copy_bytes!(topic_data);
copy_bytes!(group_data);
unsafe {
(*out).reliability = r.reliability.into();
(*out).durability = r.durability.into();
(*out).durability_service = r.durability_service.into();
(*out).deadline = r.deadline.into();
(*out).latency_budget = r.latency_budget.into();
(*out).liveliness = r.liveliness.into();
(*out).destination_order = r.destination_order.into();
(*out).lifespan = r.lifespan.into();
(*out).ownership = r.ownership.into();
(*out).ownership_strength = r.ownership_strength.into();
(*out).presentation = r.presentation.into();
(*out).history = r.history.into();
(*out).resource_limits = r.resource_limits.into();
(*out).transport_priority = r.transport_priority.into();
(*out).writer_data_lifecycle = r.writer_data_lifecycle.into();
(*out).partition.names = ptr::null();
(*out).partition.names_len = 0;
}
ZeroDdsStatus::Ok as c_int
}
pub unsafe fn dr_qos_to_c(r: &DataReaderQos, out: *mut ZeroDdsDataReaderQos) -> c_int {
if out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
macro_rules! copy_bytes {
($field:ident) => {{
let needed = r.$field.value.len();
let cap = unsafe { (*out).$field.value_len };
let dst = unsafe { (*out).$field.value as *mut u8 };
if needed > 0 {
if dst.is_null() || cap < needed {
unsafe { (*out).$field.value_len = needed };
return ZeroDdsStatus::OutOfResources as c_int;
}
unsafe { ptr::copy_nonoverlapping(r.$field.value.as_ptr(), dst, needed) };
}
unsafe { (*out).$field.value_len = needed };
}};
}
copy_bytes!(user_data);
copy_bytes!(topic_data);
copy_bytes!(group_data);
unsafe {
(*out).reliability = r.reliability.into();
(*out).durability = r.durability.into();
(*out).deadline = r.deadline.into();
(*out).latency_budget = r.latency_budget.into();
(*out).liveliness = r.liveliness.into();
(*out).destination_order = r.destination_order.into();
(*out).ownership = r.ownership.into();
(*out).presentation = r.presentation.into();
(*out).history = r.history.into();
(*out).resource_limits = r.resource_limits.into();
(*out).time_based_filter = r.time_based_filter.into();
(*out).reader_data_lifecycle = r.reader_data_lifecycle.into();
(*out).partition.names = ptr::null();
(*out).partition.names_len = 0;
}
ZeroDdsStatus::Ok as c_int
}
pub unsafe fn pub_qos_to_c(r: &PublisherQos, out: *mut ZeroDdsPublisherQos) -> c_int {
if out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let needed = r.group_data.value.len();
let cap = unsafe { (*out).group_data.value_len };
let dst = unsafe { (*out).group_data.value as *mut u8 };
if needed > 0 {
if dst.is_null() || cap < needed {
unsafe { (*out).group_data.value_len = needed };
return ZeroDdsStatus::OutOfResources as c_int;
}
unsafe { ptr::copy_nonoverlapping(r.group_data.value.as_ptr(), dst, needed) };
}
unsafe {
(*out).group_data.value_len = needed;
(*out).presentation = r.presentation.into();
(*out).entity_factory = r.entity_factory.into();
(*out).partition.names = ptr::null();
(*out).partition.names_len = 0;
}
ZeroDdsStatus::Ok as c_int
}
pub unsafe fn sub_qos_to_c(r: &SubscriberQos, out: *mut ZeroDdsSubscriberQos) -> c_int {
if out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let needed = r.group_data.value.len();
let cap = unsafe { (*out).group_data.value_len };
let dst = unsafe { (*out).group_data.value as *mut u8 };
if needed > 0 {
if dst.is_null() || cap < needed {
unsafe { (*out).group_data.value_len = needed };
return ZeroDdsStatus::OutOfResources as c_int;
}
unsafe { ptr::copy_nonoverlapping(r.group_data.value.as_ptr(), dst, needed) };
}
unsafe {
(*out).group_data.value_len = needed;
(*out).presentation = r.presentation.into();
(*out).entity_factory = r.entity_factory.into();
(*out).partition.names = ptr::null();
(*out).partition.names_len = 0;
}
ZeroDdsStatus::Ok as c_int
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn duration_roundtrip() {
let r = Duration::from_millis(250);
let c: ZeroDdsDuration = r.into();
let back: Duration = c.into();
assert_eq!(back.seconds, r.seconds);
assert!((back.fraction as i64 - r.fraction as i64).abs() < 1024);
}
#[test]
fn duration_infinite_roundtrip() {
let r = Duration::INFINITE;
let c: ZeroDdsDuration = r.into();
assert_eq!(c.sec, i32::MAX);
assert_eq!(c.nanosec, u32::MAX);
let back: Duration = c.into();
assert!(back.is_infinite());
}
#[test]
fn dw_qos_default_from_null() {
let q = unsafe { dw_qos_from_c(ptr::null()) };
assert_eq!(q, DataWriterQos::default());
}
#[test]
fn dw_qos_reliability_roundtrip() {
let mut c: ZeroDdsDataWriterQos = unsafe { core::mem::zeroed() };
c.reliability = ZeroDdsReliabilityQosPolicy {
kind: 1, max_blocking_time: ZeroDdsDuration { sec: 1, nanosec: 0 },
};
c.history.kind = 0;
c.history.depth = 1;
c.resource_limits.max_samples = 1000;
c.resource_limits.max_instances = 10;
c.resource_limits.max_samples_per_instance = 100;
let q = unsafe { dw_qos_from_c(&c) };
assert!(matches!(q.reliability.kind, ReliabilityKind::BestEffort));
}
#[test]
fn dr_qos_default_from_null() {
let q = unsafe { dr_qos_from_c(ptr::null()) };
assert_eq!(q, DataReaderQos::default());
}
#[test]
fn topic_qos_default_from_null() {
let q = unsafe { topic_qos_from_c(ptr::null()) };
assert_eq!(q, TopicQos::default());
}
#[test]
fn pub_qos_default_from_null() {
let q = unsafe { pub_qos_from_c(ptr::null()) };
assert_eq!(q, PublisherQos::default());
}
#[test]
fn sub_qos_default_from_null() {
let q = unsafe { sub_qos_from_c(ptr::null()) };
assert_eq!(q, SubscriberQos::default());
}
#[test]
fn dp_qos_default_from_null() {
let q = unsafe { dp_qos_from_c(ptr::null()) };
assert_eq!(q, DomainParticipantQos::default());
}
#[test]
fn dp_qos_userdata_passthrough() {
let bytes = b"hello world";
let c = ZeroDdsDomainParticipantQos {
user_data: ZeroDdsUserDataQosPolicy {
value: bytes.as_ptr(),
value_len: bytes.len(),
},
entity_factory: ZeroDdsEntityFactoryQosPolicy {
autoenable_created_entities: false,
},
};
let q = unsafe { dp_qos_from_c(&c) };
assert_eq!(q.user_data.value, bytes.to_vec());
assert!(!q.entity_factory.autoenable_created_entities);
}
#[test]
fn partition_cstring_array_passthrough() {
let p1 = c"alpha";
let p2 = c"beta";
let arr: [*const c_char; 2] = [p1.as_ptr(), p2.as_ptr()];
let mut c: ZeroDdsDataWriterQos = unsafe { core::mem::zeroed() };
c.partition.names = arr.as_ptr();
c.partition.names_len = 2;
let q = unsafe { dw_qos_from_c(&c) };
assert_eq!(
q.partition.names,
alloc::vec!["alpha".to_string(), "beta".to_string()]
);
}
}