use alloc::boxed::Box;
use alloc::vec::Vec;
use core::ffi::c_int;
use core::ptr;
use core::slice;
use std::time::Duration;
use crate::ZeroDdsStatus;
use crate::entities::{
ZeroDdsDataReader, ZeroDdsDataWriter, ZeroDdsDomainParticipant, ZeroDdsPublisher,
ZeroDdsSubscriber,
};
use crate::qos_ffi::{
ZeroDdsDataReaderQos, ZeroDdsDataWriterQos, ZeroDdsDomainParticipantQos, ZeroDdsPublisherQos,
ZeroDdsSubscriberQos, ZeroDdsTopicQos, dr_qos_from_c, dw_qos_from_c, pub_qos_from_c,
sub_qos_from_c, topic_qos_from_c,
};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_lookup_topicdescription(
p: *mut ZeroDdsDomainParticipant,
name: *const core::ffi::c_char,
) -> *mut crate::entities::ZeroDdsTopic {
if p.is_null() || name.is_null() {
return ptr::null_mut();
}
let pp = unsafe { &*p };
let cs = unsafe { std::ffi::CStr::from_ptr(name) };
let name_str = match cs.to_str() {
Ok(s) => s,
Err(_) => return ptr::null_mut(),
};
if let Ok(list) = pp.topics.lock() {
for &t in list.iter() {
if t.is_null() {
continue;
}
let tt = unsafe { &*t };
if tt.name == name_str {
return t;
}
}
}
ptr::null_mut()
}
pub struct ZeroDdsBuiltinSubscriber {
pub participant: *mut ZeroDdsDomainParticipant,
pub inner: alloc::sync::Arc<zerodds_dcps::builtin_subscriber::BuiltinSubscriber>,
}
unsafe impl Send for ZeroDdsBuiltinSubscriber {}
unsafe impl Sync for ZeroDdsBuiltinSubscriber {}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_get_builtin_subscriber(
p: *mut ZeroDdsDomainParticipant,
) -> *mut ZeroDdsBuiltinSubscriber {
if p.is_null() {
return ptr::null_mut();
}
let pp = unsafe { &*p };
let inner = pp.dp.get_builtin_subscriber();
Box::into_raw(Box::new(ZeroDdsBuiltinSubscriber {
participant: p,
inner,
}))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_builtin_subscriber_destroy(bs: *mut ZeroDdsBuiltinSubscriber) {
if !bs.is_null() {
let _ = unsafe { Box::from_raw(bs) };
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_set_qos(
p: *mut ZeroDdsDomainParticipant,
qos: *const ZeroDdsDomainParticipantQos,
) -> c_int {
if p.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let pp = unsafe { &*p };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::DomainParticipantQos::default()
} else {
unsafe { crate::qos_ffi::dp_qos_from_c(qos) }
};
match pp.dp.set_qos(new_qos) {
Ok(()) => ZeroDdsStatus::Ok as c_int,
Err(_) => ZeroDdsStatus::Error as c_int,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_get_qos(
p: *mut ZeroDdsDomainParticipant,
out: *mut ZeroDdsDomainParticipantQos,
) -> c_int {
if p.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*p };
let qos = pp.dp.qos();
unsafe { crate::qos_ffi::dp_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_set_default_topic_qos(
p: *mut ZeroDdsDomainParticipant,
qos: *const ZeroDdsTopicQos,
) -> c_int {
if p.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let pp = unsafe { &*p };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::TopicQos::default()
} else {
unsafe { topic_qos_from_c(qos) }
};
if let Ok(mut g) = pp.default_topic_qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_get_default_topic_qos(
p: *mut ZeroDdsDomainParticipant,
out: *mut ZeroDdsTopicQos,
) -> c_int {
if p.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*p };
let qos = pp
.default_topic_qos
.lock()
.map(|g| g.clone())
.unwrap_or_default();
unsafe { crate::qos_ffi::topic_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_set_default_publisher_qos(
p: *mut ZeroDdsDomainParticipant,
qos: *const ZeroDdsPublisherQos,
) -> c_int {
if p.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let pp = unsafe { &*p };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::PublisherQos::default()
} else {
unsafe { pub_qos_from_c(qos) }
};
if let Ok(mut g) = pp.default_publisher_qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_get_default_publisher_qos(
p: *mut ZeroDdsDomainParticipant,
out: *mut ZeroDdsPublisherQos,
) -> c_int {
if p.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*p };
let qos = pp
.default_publisher_qos
.lock()
.map(|g| g.clone())
.unwrap_or_default();
unsafe { crate::qos_ffi::pub_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_set_default_subscriber_qos(
p: *mut ZeroDdsDomainParticipant,
qos: *const ZeroDdsSubscriberQos,
) -> c_int {
if p.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let pp = unsafe { &*p };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::SubscriberQos::default()
} else {
unsafe { sub_qos_from_c(qos) }
};
if let Ok(mut g) = pp.default_subscriber_qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_get_default_subscriber_qos(
p: *mut ZeroDdsDomainParticipant,
out: *mut ZeroDdsSubscriberQos,
) -> c_int {
if p.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*p };
let qos = pp
.default_subscriber_qos
.lock()
.map(|g| g.clone())
.unwrap_or_default();
unsafe { crate::qos_ffi::sub_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_pub_set_qos(
pub_: *mut ZeroDdsPublisher,
qos: *const ZeroDdsPublisherQos,
) -> c_int {
if pub_.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let pp = unsafe { &*pub_ };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::PublisherQos::default()
} else {
unsafe { pub_qos_from_c(qos) }
};
if let Ok(mut g) = pp.qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_pub_get_qos(
pub_: *mut ZeroDdsPublisher,
out: *mut ZeroDdsPublisherQos,
) -> c_int {
if pub_.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*pub_ };
let qos = pp.qos.lock().map(|g| g.clone()).unwrap_or_default();
unsafe { crate::qos_ffi::pub_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_pub_set_default_datawriter_qos(
pub_: *mut ZeroDdsPublisher,
qos: *const ZeroDdsDataWriterQos,
) -> c_int {
if pub_.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let pp = unsafe { &*pub_ };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::DataWriterQos::default()
} else {
unsafe { dw_qos_from_c(qos) }
};
if let Ok(mut g) = pp.default_dw_qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_pub_get_default_datawriter_qos(
pub_: *mut ZeroDdsPublisher,
out: *mut ZeroDdsDataWriterQos,
) -> c_int {
if pub_.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*pub_ };
let qos = pp
.default_dw_qos
.lock()
.map(|g| g.clone())
.unwrap_or_default();
unsafe { crate::qos_ffi::dw_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_pub_copy_from_topic_qos(
_pub: *mut ZeroDdsPublisher,
dwqos_inout: *mut ZeroDdsDataWriterQos,
tqos: *const ZeroDdsTopicQos,
) -> c_int {
if dwqos_inout.is_null() || tqos.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
unsafe {
(*dwqos_inout).durability = (*tqos).durability;
(*dwqos_inout).deadline = (*tqos).deadline;
(*dwqos_inout).latency_budget = (*tqos).latency_budget;
(*dwqos_inout).liveliness = (*tqos).liveliness;
(*dwqos_inout).reliability = (*tqos).reliability;
(*dwqos_inout).destination_order = (*tqos).destination_order;
(*dwqos_inout).history = (*tqos).history;
(*dwqos_inout).resource_limits = (*tqos).resource_limits;
(*dwqos_inout).transport_priority = (*tqos).transport_priority;
(*dwqos_inout).lifespan = (*tqos).lifespan;
(*dwqos_inout).ownership = (*tqos).ownership;
(*dwqos_inout).topic_data = (*tqos).topic_data;
(*dwqos_inout).durability_service = (*tqos).durability_service;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_sub_set_qos(
sub: *mut ZeroDdsSubscriber,
qos: *const ZeroDdsSubscriberQos,
) -> c_int {
if sub.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let sb = unsafe { &*sub };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::SubscriberQos::default()
} else {
unsafe { sub_qos_from_c(qos) }
};
if let Ok(mut g) = sb.qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_sub_get_qos(
sub: *mut ZeroDdsSubscriber,
out: *mut ZeroDdsSubscriberQos,
) -> c_int {
if sub.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let sb = unsafe { &*sub };
let qos = sb.qos.lock().map(|g| g.clone()).unwrap_or_default();
unsafe { crate::qos_ffi::sub_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_sub_set_default_datareader_qos(
sub: *mut ZeroDdsSubscriber,
qos: *const ZeroDdsDataReaderQos,
) -> c_int {
if sub.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let sb = unsafe { &*sub };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::DataReaderQos::default()
} else {
unsafe { dr_qos_from_c(qos) }
};
if let Ok(mut g) = sb.default_dr_qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_sub_get_default_datareader_qos(
sub: *mut ZeroDdsSubscriber,
out: *mut ZeroDdsDataReaderQos,
) -> c_int {
if sub.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let sb = unsafe { &*sub };
let qos = sb
.default_dr_qos
.lock()
.map(|g| g.clone())
.unwrap_or_default();
unsafe { crate::qos_ffi::dr_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_sub_copy_from_topic_qos(
_sub: *mut ZeroDdsSubscriber,
drqos_inout: *mut ZeroDdsDataReaderQos,
tqos: *const ZeroDdsTopicQos,
) -> c_int {
if drqos_inout.is_null() || tqos.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
unsafe {
(*drqos_inout).durability = (*tqos).durability;
(*drqos_inout).deadline = (*tqos).deadline;
(*drqos_inout).latency_budget = (*tqos).latency_budget;
(*drqos_inout).liveliness = (*tqos).liveliness;
(*drqos_inout).reliability = (*tqos).reliability;
(*drqos_inout).destination_order = (*tqos).destination_order;
(*drqos_inout).history = (*tqos).history;
(*drqos_inout).resource_limits = (*tqos).resource_limits;
(*drqos_inout).ownership = (*tqos).ownership;
(*drqos_inout).topic_data = (*tqos).topic_data;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_set_qos(
dw: *mut ZeroDdsDataWriter,
qos: *const ZeroDdsDataWriterQos,
) -> c_int {
if dw.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let dwr = unsafe { &*dw };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::DataWriterQos::default()
} else {
unsafe { dw_qos_from_c(qos) }
};
if let Ok(mut g) = dwr.qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_get_qos(
dw: *mut ZeroDdsDataWriter,
out: *mut ZeroDdsDataWriterQos,
) -> c_int {
if dw.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let dwr = unsafe { &*dw };
let qos = dwr.qos.lock().map(|g| g.clone()).unwrap_or_default();
unsafe { crate::qos_ffi::dw_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_set_qos(
dr: *mut ZeroDdsDataReader,
qos: *const ZeroDdsDataReaderQos,
) -> c_int {
if dr.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let drr = unsafe { &*dr };
let new_qos = if qos.is_null() {
zerodds_dcps::qos::DataReaderQos::default()
} else {
unsafe { dr_qos_from_c(qos) }
};
if let Ok(mut g) = drr.qos.lock() {
*g = new_qos;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_get_qos(
dr: *mut ZeroDdsDataReader,
out: *mut ZeroDdsDataReaderQos,
) -> c_int {
if dr.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let drr = unsafe { &*dr };
let qos = drr.qos.lock().map(|g| g.clone()).unwrap_or_default();
unsafe { crate::qos_ffi::dr_qos_to_c(&qos, out) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_register_instance(
dw: *mut ZeroDdsDataWriter,
key: *const u8,
key_len: usize,
out_handle: *mut u64,
) -> c_int {
if dw.is_null() || key.is_null() || key_len != 16 || out_handle.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let raw = unsafe { slice::from_raw_parts(key, 16) };
let mut h = [0u8; 8];
h.copy_from_slice(&raw[..8]);
unsafe { *out_handle = u64::from_le_bytes(h) };
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_register_instance_w_timestamp(
dw: *mut ZeroDdsDataWriter,
key: *const u8,
key_len: usize,
_ts_sec: i32,
_ts_nanosec: u32,
out_handle: *mut u64,
) -> c_int {
unsafe { zerodds_dw_register_instance(dw, key, key_len, out_handle) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_unregister_instance(
dw: *mut ZeroDdsDataWriter,
handle: u64,
) -> c_int {
if dw.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let dwr = unsafe { &*dw };
let mut k = [0u8; 16];
k[..8].copy_from_slice(&handle.to_le_bytes());
const STATUS_UNREGISTERED: u32 = 0x0000_0002;
match dwr.rt.write_user_lifecycle(dwr.eid, k, STATUS_UNREGISTERED) {
Ok(()) => ZeroDdsStatus::Ok as c_int,
Err(_) => ZeroDdsStatus::Error as c_int,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_unregister_instance_w_timestamp(
dw: *mut ZeroDdsDataWriter,
handle: u64,
_ts_sec: i32,
_ts_nanosec: u32,
) -> c_int {
unsafe { zerodds_dw_unregister_instance(dw, handle) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_lookup_instance(
_dw: *mut ZeroDdsDataWriter,
key: *const u8,
key_len: usize,
out_handle: *mut u64,
) -> c_int {
if key.is_null() || key_len != 16 || out_handle.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let raw = unsafe { slice::from_raw_parts(key, 16) };
let mut h = [0u8; 8];
h.copy_from_slice(&raw[..8]);
unsafe { *out_handle = u64::from_le_bytes(h) };
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_get_key_value(
_dw: *mut ZeroDdsDataWriter,
handle: u64,
out_buf: *mut u8,
inout_len: *mut usize,
) -> c_int {
if out_buf.is_null() || inout_len.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
unsafe {
if *inout_len < 8 {
*inout_len = 8;
return ZeroDdsStatus::OutOfResources as c_int;
}
ptr::copy_nonoverlapping(handle.to_le_bytes().as_ptr(), out_buf, 8);
*inout_len = 8;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_dispose_w_timestamp(
dw: *mut ZeroDdsDataWriter,
key_hash: *const u8,
handle: u64,
_ts_sec: i32,
_ts_nanosec: u32,
) -> c_int {
unsafe { crate::publisher_ffi::zerodds_dw_dispose(dw, key_hash, handle) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_get_matched_subscriptions(
dw: *mut ZeroDdsDataWriter,
out_handles: *mut u64,
out_count: *mut usize,
cap: usize,
) -> c_int {
if dw.is_null() || out_count.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let dwr = unsafe { &*dw };
let handles = dwr.rt.user_writer_matched_subscription_handles(dwr.eid);
let n = handles.len().min(cap);
if !out_handles.is_null() && n > 0 {
let dst = unsafe { slice::from_raw_parts_mut(out_handles, n) };
for (i, h) in handles.iter().take(n).enumerate() {
dst[i] = h.as_raw();
}
}
unsafe { *out_count = n };
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_get_matched_subscription_data(
dw: *mut ZeroDdsDataWriter,
handle: u64,
out: *mut crate::builtin_ffi::ZeroDdsSubscriptionBuiltinTopicData,
) -> c_int {
if dw.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let dwr = unsafe { &*dw };
if dwr.publisher.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let pub_ = unsafe { &*dwr.publisher };
if pub_.participant.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let dp_wrapper = unsafe { &*pub_.participant };
let bs = dp_wrapper.dp.get_builtin_subscriber();
let sub_reader = bs.subscription_reader();
let samples: Vec<zerodds_dcps::builtin_topics::SubscriptionBuiltinTopicData> =
sub_reader.read().unwrap_or_default();
for s in samples {
let h = zerodds_dcps::instance_handle::InstanceHandle::from_guid(s.key).as_raw();
if h == handle {
return write_subscription_data(out, &s);
}
}
ZeroDdsStatus::NoData as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_loan_message(
dw: *mut ZeroDdsDataWriter,
len: usize,
out_ptr: *mut *mut u8,
out_len: *mut usize,
) -> c_int {
if dw.is_null() || out_ptr.is_null() || out_len.is_null() || len == 0 {
return ZeroDdsStatus::BadParameter as c_int;
}
let buf: Box<[u8]> = vec![0u8; len].into_boxed_slice();
let raw = Box::into_raw(buf) as *mut u8;
unsafe {
*out_ptr = raw;
*out_len = len;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_commit_loan(
dw: *mut ZeroDdsDataWriter,
ptr: *mut u8,
len: usize,
) -> c_int {
if dw.is_null() || ptr.is_null() || len == 0 {
return ZeroDdsStatus::BadParameter as c_int;
}
let dwr = unsafe { &*dw };
let boxed: Box<[u8]> = unsafe { Box::from_raw(core::slice::from_raw_parts_mut(ptr, len)) };
let payload: Vec<u8> = boxed.into_vec();
match dwr.rt.write_user_sample(dwr.eid, payload) {
Ok(()) => ZeroDdsStatus::Ok as c_int,
Err(_) => ZeroDdsStatus::Error as c_int,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dw_discard_loan(
_dw: *mut ZeroDdsDataWriter,
ptr: *mut u8,
len: usize,
) -> c_int {
if ptr.is_null() || len == 0 {
return ZeroDdsStatus::BadParameter as c_int;
}
let _: Box<[u8]> = unsafe { Box::from_raw(core::slice::from_raw_parts_mut(ptr, len)) };
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_read_instance(
dr: *mut ZeroDdsDataReader,
handle: u64,
out: *mut crate::subscriber_ffi::ZeroDdsSampleArray,
max: usize,
s: u32,
v: u32,
i: u32,
) -> c_int {
let rc = unsafe { crate::subscriber_ffi::zerodds_dr_read(dr, out, max, s, v, i) };
if rc != ZeroDdsStatus::Ok as c_int {
return rc;
}
crate::subscriber_ffi::sample_array_filter_instance(out, handle)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_take_instance(
dr: *mut ZeroDdsDataReader,
handle: u64,
out: *mut crate::subscriber_ffi::ZeroDdsSampleArray,
max: usize,
s: u32,
v: u32,
i: u32,
) -> c_int {
let rc = unsafe { crate::subscriber_ffi::zerodds_dr_take(dr, out, max, s, v, i) };
if rc != ZeroDdsStatus::Ok as c_int {
return rc;
}
crate::subscriber_ffi::sample_array_filter_instance(out, handle)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_read_next_instance(
dr: *mut ZeroDdsDataReader,
prev_handle: u64,
out: *mut crate::subscriber_ffi::ZeroDdsSampleArray,
max: usize,
s: u32,
v: u32,
i: u32,
) -> c_int {
let rc = unsafe { crate::subscriber_ffi::zerodds_dr_read(dr, out, max, s, v, i) };
if rc != ZeroDdsStatus::Ok as c_int {
return rc;
}
crate::subscriber_ffi::sample_array_filter_next_instance(out, prev_handle)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_take_next_instance(
dr: *mut ZeroDdsDataReader,
prev_handle: u64,
out: *mut crate::subscriber_ffi::ZeroDdsSampleArray,
max: usize,
s: u32,
v: u32,
i: u32,
) -> c_int {
let rc = unsafe { crate::subscriber_ffi::zerodds_dr_take(dr, out, max, s, v, i) };
if rc != ZeroDdsStatus::Ok as c_int {
return rc;
}
crate::subscriber_ffi::sample_array_filter_next_instance(out, prev_handle)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_read_w_condition(
dr: *mut ZeroDdsDataReader,
out: *mut crate::subscriber_ffi::ZeroDdsSampleArray,
max: usize,
cond: *mut core::ffi::c_void,
) -> c_int {
let masks = match unsafe { crate::condition_ffi::condition_state_masks(cond) } {
Some(m) => m,
None => return ZeroDdsStatus::BadParameter as c_int,
};
let rc =
unsafe { crate::subscriber_ffi::zerodds_dr_read(dr, out, max, masks.0, masks.1, masks.2) };
if rc != ZeroDdsStatus::Ok as c_int {
return rc;
}
crate::subscriber_ffi::sample_array_filter_states(out, masks.0, masks.1, masks.2)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_take_w_condition(
dr: *mut ZeroDdsDataReader,
out: *mut crate::subscriber_ffi::ZeroDdsSampleArray,
max: usize,
cond: *mut core::ffi::c_void,
) -> c_int {
let masks = match unsafe { crate::condition_ffi::condition_state_masks(cond) } {
Some(m) => m,
None => return ZeroDdsStatus::BadParameter as c_int,
};
let rc =
unsafe { crate::subscriber_ffi::zerodds_dr_take(dr, out, max, masks.0, masks.1, masks.2) };
if rc != ZeroDdsStatus::Ok as c_int {
return rc;
}
crate::subscriber_ffi::sample_array_filter_states(out, masks.0, masks.1, masks.2)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_lookup_instance(
_dr: *mut ZeroDdsDataReader,
key: *const u8,
key_len: usize,
out_handle: *mut u64,
) -> c_int {
if key.is_null() || key_len != 16 || out_handle.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let raw = unsafe { slice::from_raw_parts(key, 16) };
let mut h = [0u8; 8];
h.copy_from_slice(&raw[..8]);
unsafe { *out_handle = u64::from_le_bytes(h) };
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_get_key_value(
_dr: *mut ZeroDdsDataReader,
handle: u64,
out_buf: *mut u8,
inout_len: *mut usize,
) -> c_int {
if out_buf.is_null() || inout_len.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
unsafe {
if *inout_len < 8 {
*inout_len = 8;
return ZeroDdsStatus::OutOfResources as c_int;
}
ptr::copy_nonoverlapping(handle.to_le_bytes().as_ptr(), out_buf, 8);
*inout_len = 8;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_wait_for_historical_data(
dr: *mut ZeroDdsDataReader,
_timeout_sec: i32,
_timeout_nanosec: u32,
) -> c_int {
if dr.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_get_matched_publications(
dr: *mut ZeroDdsDataReader,
out_handles: *mut u64,
out_count: *mut usize,
cap: usize,
) -> c_int {
if dr.is_null() || out_count.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let drr = unsafe { &*dr };
let handles = drr.rt.user_reader_matched_publication_handles(drr.eid);
let n = handles.len().min(cap);
if !out_handles.is_null() && n > 0 {
let dst = unsafe { slice::from_raw_parts_mut(out_handles, n) };
for (i, h) in handles.iter().take(n).enumerate() {
dst[i] = h.as_raw();
}
}
unsafe { *out_count = n };
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dr_get_matched_publication_data(
dr: *mut ZeroDdsDataReader,
handle: u64,
out: *mut crate::builtin_ffi::ZeroDdsPublicationBuiltinTopicData,
) -> c_int {
if dr.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let drr = unsafe { &*dr };
if drr.subscriber.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let sub_ = unsafe { &*drr.subscriber };
if sub_.participant.is_null() {
return ZeroDdsStatus::BadHandle as c_int;
}
let dp_wrapper = unsafe { &*sub_.participant };
let bs = dp_wrapper.dp.get_builtin_subscriber();
let pub_reader = bs.publication_reader();
let samples: Vec<zerodds_dcps::builtin_topics::PublicationBuiltinTopicData> =
pub_reader.read().unwrap_or_default();
for s in samples {
let h = zerodds_dcps::instance_handle::InstanceHandle::from_guid(s.key).as_raw();
if h == handle {
return write_publication_data(out, &s);
}
}
ZeroDdsStatus::NoData as c_int
}
fn write_subscription_data(
out: *mut crate::builtin_ffi::ZeroDdsSubscriptionBuiltinTopicData,
s: &zerodds_dcps::builtin_topics::SubscriptionBuiltinTopicData,
) -> c_int {
use alloc::ffi::CString;
let topic_name = CString::new(s.topic_name.as_bytes())
.unwrap_or_default()
.into_raw();
let type_name = CString::new(s.type_name.as_bytes())
.unwrap_or_default()
.into_raw();
unsafe {
(*out).key = s.key.to_bytes();
(*out).participant_key = s.participant_key.to_bytes();
(*out).topic_name = topic_name;
(*out).type_name = type_name;
(*out).durability_kind = s.durability as u32;
(*out).reliability_kind = s.reliability as u32;
(*out).ownership_kind = s.ownership as u32;
(*out).liveliness_lease_seconds = s.liveliness_lease_seconds;
(*out).deadline_seconds = s.deadline_seconds;
}
ZeroDdsStatus::Ok as c_int
}
fn write_publication_data(
out: *mut crate::builtin_ffi::ZeroDdsPublicationBuiltinTopicData,
s: &zerodds_dcps::builtin_topics::PublicationBuiltinTopicData,
) -> c_int {
use alloc::ffi::CString;
let topic_name = CString::new(s.topic_name.as_bytes())
.unwrap_or_default()
.into_raw();
let type_name = CString::new(s.type_name.as_bytes())
.unwrap_or_default()
.into_raw();
unsafe {
(*out).key = s.key.to_bytes();
(*out).participant_key = s.participant_key.to_bytes();
(*out).topic_name = topic_name;
(*out).type_name = type_name;
(*out).durability_kind = s.durability as u32;
(*out).reliability_kind = s.reliability as u32;
(*out).ownership_kind = s.ownership as u32;
(*out).ownership_strength = s.ownership_strength;
(*out).liveliness_lease_seconds = s.liveliness_lease_seconds;
(*out).deadline_seconds = s.deadline_seconds;
(*out).lifespan_seconds = s.lifespan_seconds;
}
ZeroDdsStatus::Ok as c_int
}
#[allow(dead_code)]
fn _suppress(_: Duration, _: Vec<u8>, _: Box<u8>) {}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
use crate::factory_ffi::{
zerodds_dpf_create_participant, zerodds_dpf_delete_participant, zerodds_dpf_get_instance,
};
use crate::participant_ffi::{
zerodds_dp_create_publisher, zerodds_dp_create_subscriber, zerodds_dp_create_topic,
zerodds_dp_delete_contained_entities,
};
use crate::publisher_ffi::zerodds_pub_create_datawriter;
use crate::subscriber_ffi::zerodds_sub_create_datareader;
fn mk(domain: u32) -> *mut ZeroDdsDomainParticipant {
let f = zerodds_dpf_get_instance();
unsafe { zerodds_dpf_create_participant(f, domain, ptr::null()) }
}
fn cleanup(p: *mut ZeroDdsDomainParticipant) {
let f = zerodds_dpf_get_instance();
unsafe {
zerodds_dp_delete_contained_entities(p);
zerodds_dpf_delete_participant(f, p);
}
}
#[test]
fn dp_get_set_qos_roundtrip_default() {
let p = mk(70);
let mut qos = ZeroDdsDomainParticipantQos {
user_data: crate::qos_ffi::ZeroDdsUserDataQosPolicy {
value: ptr::null(),
value_len: 0,
},
entity_factory: crate::qos_ffi::ZeroDdsEntityFactoryQosPolicy {
autoenable_created_entities: true,
},
};
assert_eq!(
unsafe { zerodds_dp_set_qos(p, &qos) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(
unsafe { zerodds_dp_get_qos(p, &mut qos) },
ZeroDdsStatus::Ok as c_int
);
cleanup(p);
}
#[test]
fn dp_default_topic_qos_roundtrip() {
let p = mk(71);
let mut tqos: ZeroDdsTopicQos = unsafe { core::mem::zeroed() };
assert_eq!(
unsafe { zerodds_dp_set_default_topic_qos(p, &tqos) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(
unsafe { zerodds_dp_get_default_topic_qos(p, &mut tqos) },
ZeroDdsStatus::Ok as c_int
);
cleanup(p);
}
#[test]
fn dw_register_unregister_lookup_instance() {
let p = mk(72);
let n = c"T";
let tn = c"TT";
let t = unsafe { zerodds_dp_create_topic(p, n.as_ptr(), tn.as_ptr(), ptr::null()) };
let pubh = unsafe { zerodds_dp_create_publisher(p, ptr::null()) };
let dw = unsafe { zerodds_pub_create_datawriter(pubh, t, ptr::null()) };
let key = [0xABu8; 16];
let mut handle = 0u64;
assert_eq!(
unsafe { zerodds_dw_register_instance(dw, key.as_ptr(), 16, &mut handle) },
ZeroDdsStatus::Ok as c_int
);
assert!(handle != 0);
let mut h2 = 0u64;
assert_eq!(
unsafe { zerodds_dw_lookup_instance(dw, key.as_ptr(), 16, &mut h2) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(handle, h2, "lookup must match register");
let rc = unsafe { zerodds_dw_unregister_instance(dw, handle) };
assert!(rc == ZeroDdsStatus::Ok as c_int || rc == ZeroDdsStatus::Error as c_int);
cleanup(p);
}
#[test]
fn dw_get_key_value_buffer_too_small() {
let p = mk(73);
let n = c"T";
let tn = c"TT";
let t = unsafe { zerodds_dp_create_topic(p, n.as_ptr(), tn.as_ptr(), ptr::null()) };
let pubh = unsafe { zerodds_dp_create_publisher(p, ptr::null()) };
let dw = unsafe { zerodds_pub_create_datawriter(pubh, t, ptr::null()) };
let mut buf = [0u8; 4];
let mut len: usize = 4;
assert_eq!(
unsafe { zerodds_dw_get_key_value(dw, 0xDEAD, buf.as_mut_ptr(), &mut len) },
ZeroDdsStatus::OutOfResources as c_int
);
assert_eq!(len, 8, "must report needed buffer size");
cleanup(p);
}
#[test]
fn dw_loan_message_then_commit_or_discard() {
let p = mk(74);
let n = c"T";
let tn = c"TT";
let t = unsafe { zerodds_dp_create_topic(p, n.as_ptr(), tn.as_ptr(), ptr::null()) };
let pubh = unsafe { zerodds_dp_create_publisher(p, ptr::null()) };
let dw = unsafe { zerodds_pub_create_datawriter(pubh, t, ptr::null()) };
let mut p_buf: *mut u8 = ptr::null_mut();
let mut len_buf: usize = 0;
assert_eq!(
unsafe { zerodds_dw_loan_message(dw, 16, &mut p_buf, &mut len_buf) },
ZeroDdsStatus::Ok as c_int
);
assert!(!p_buf.is_null() && len_buf == 16);
unsafe {
for i in 0..16 {
*p_buf.add(i) = i as u8;
}
}
let rc_commit = unsafe { zerodds_dw_commit_loan(dw, p_buf, len_buf) };
assert!(
rc_commit == ZeroDdsStatus::Ok as c_int || rc_commit == ZeroDdsStatus::Error as c_int,
"commit returns Ok/Error"
);
let mut p2: *mut u8 = ptr::null_mut();
let mut l2: usize = 0;
let _ = unsafe { zerodds_dw_loan_message(dw, 8, &mut p2, &mut l2) };
assert_eq!(
unsafe { zerodds_dw_discard_loan(dw, p2, l2) },
ZeroDdsStatus::Ok as c_int
);
cleanup(p);
}
#[test]
fn dr_get_matched_publications_empty() {
let p = mk(75);
let n = c"T";
let tn = c"TT";
let t = unsafe { zerodds_dp_create_topic(p, n.as_ptr(), tn.as_ptr(), ptr::null()) };
let sub = unsafe { zerodds_dp_create_subscriber(p, ptr::null()) };
let dr = unsafe { zerodds_sub_create_datareader(sub, t, ptr::null()) };
let mut buf = [0u64; 16];
let mut count = 0usize;
assert_eq!(
unsafe { zerodds_dr_get_matched_publications(dr, buf.as_mut_ptr(), &mut count, 16) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(count, 0);
cleanup(p);
}
#[test]
fn dr_wait_for_historical_data_volatile_returns_ok() {
let p = mk(76);
let n = c"T";
let tn = c"TT";
let t = unsafe { zerodds_dp_create_topic(p, n.as_ptr(), tn.as_ptr(), ptr::null()) };
let sub = unsafe { zerodds_dp_create_subscriber(p, ptr::null()) };
let dr = unsafe { zerodds_sub_create_datareader(sub, t, ptr::null()) };
assert_eq!(
unsafe { zerodds_dr_wait_for_historical_data(dr, 0, 100_000_000) },
ZeroDdsStatus::Ok as c_int
);
cleanup(p);
}
#[test]
fn dw_get_matched_subscriptions_initially_empty() {
let p = mk(78);
let n = c"T";
let tn = c"TT";
let t = unsafe { zerodds_dp_create_topic(p, n.as_ptr(), tn.as_ptr(), ptr::null()) };
let pubh = unsafe { zerodds_dp_create_publisher(p, ptr::null()) };
let dw = unsafe { zerodds_pub_create_datawriter(pubh, t, ptr::null()) };
let mut buf = [0u64; 16];
let mut count = 0usize;
assert_eq!(
unsafe { zerodds_dw_get_matched_subscriptions(dw, buf.as_mut_ptr(), &mut count, 16) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(count, 0);
cleanup(p);
}
#[test]
fn dr_get_matched_publications_initially_empty() {
let p = mk(79);
let n = c"T";
let tn = c"TT";
let t = unsafe { zerodds_dp_create_topic(p, n.as_ptr(), tn.as_ptr(), ptr::null()) };
let sub = unsafe { zerodds_dp_create_subscriber(p, ptr::null()) };
let dr = unsafe { zerodds_sub_create_datareader(sub, t, ptr::null()) };
let mut buf = [0u64; 16];
let mut count = 0usize;
assert_eq!(
unsafe { zerodds_dr_get_matched_publications(dr, buf.as_mut_ptr(), &mut count, 16) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(count, 0);
cleanup(p);
}
#[test]
fn dp_set_get_qos_userdata_roundtrip() {
let p = mk(80);
let bytes = b"my_user_data";
let qos_in = ZeroDdsDomainParticipantQos {
user_data: crate::qos_ffi::ZeroDdsUserDataQosPolicy {
value: bytes.as_ptr(),
value_len: bytes.len(),
},
entity_factory: crate::qos_ffi::ZeroDdsEntityFactoryQosPolicy {
autoenable_created_entities: false,
},
};
assert_eq!(
unsafe { zerodds_dp_set_qos(p, &qos_in) },
ZeroDdsStatus::Ok as c_int
);
let mut out_buf = vec![0u8; 32];
let mut qos_out = ZeroDdsDomainParticipantQos {
user_data: crate::qos_ffi::ZeroDdsUserDataQosPolicy {
value: out_buf.as_mut_ptr(),
value_len: out_buf.len(),
},
entity_factory: crate::qos_ffi::ZeroDdsEntityFactoryQosPolicy {
autoenable_created_entities: true,
},
};
assert_eq!(
unsafe { zerodds_dp_get_qos(p, &mut qos_out) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(qos_out.user_data.value_len, bytes.len());
assert!(!qos_out.entity_factory.autoenable_created_entities);
cleanup(p);
}
#[test]
fn pub_copy_from_topic_qos_propagates_policies() {
let p = mk(77);
let pubh = unsafe { zerodds_dp_create_publisher(p, ptr::null()) };
let mut tqos: ZeroDdsTopicQos = unsafe { core::mem::zeroed() };
tqos.history.kind = 0;
tqos.history.depth = 42;
tqos.reliability.kind = 2; let mut dwqos: ZeroDdsDataWriterQos = unsafe { core::mem::zeroed() };
assert_eq!(
unsafe { zerodds_pub_copy_from_topic_qos(pubh, &mut dwqos, &tqos) },
ZeroDdsStatus::Ok as c_int
);
assert_eq!(dwqos.history.depth, 42);
assert_eq!(dwqos.reliability.kind, 2);
cleanup(p);
}
}