use alloc::ffi::CString;
use alloc::vec::Vec;
use core::ffi::{c_char, c_int};
use core::ptr;
use core::slice;
use zerodds_dcps::instance_handle::InstanceHandle;
use crate::ZeroDdsStatus;
use crate::entities::ZeroDdsDomainParticipant;
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsParticipantBuiltinTopicData {
pub guid: [u8; 16],
pub user_data: *const u8,
pub user_data_len: usize,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsTopicBuiltinTopicData {
pub key: [u8; 16],
pub name: *mut c_char,
pub type_name: *mut c_char,
pub durability_kind: u32,
pub reliability_kind: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsPublicationBuiltinTopicData {
pub key: [u8; 16],
pub participant_key: [u8; 16],
pub topic_name: *mut c_char,
pub type_name: *mut c_char,
pub durability_kind: u32,
pub reliability_kind: u32,
pub ownership_kind: u32,
pub ownership_strength: i32,
pub liveliness_lease_seconds: i32,
pub deadline_seconds: i32,
pub lifespan_seconds: i32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct ZeroDdsSubscriptionBuiltinTopicData {
pub key: [u8; 16],
pub participant_key: [u8; 16],
pub topic_name: *mut c_char,
pub type_name: *mut c_char,
pub durability_kind: u32,
pub reliability_kind: u32,
pub ownership_kind: u32,
pub liveliness_lease_seconds: i32,
pub deadline_seconds: i32,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_get_discovered_topics(
p: *mut ZeroDdsDomainParticipant,
out: *mut u64,
out_count: *mut usize,
cap: usize,
) -> c_int {
if p.is_null() || out.is_null() || out_count.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*p };
let handles = pp.dp.get_discovered_topics();
let n = handles.len().min(cap);
let dst = unsafe { slice::from_raw_parts_mut(out, 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_dp_get_discovered_participant_data(
p: *mut ZeroDdsDomainParticipant,
handle: u64,
out: *mut ZeroDdsParticipantBuiltinTopicData,
) -> c_int {
if p.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*p };
let data = match pp
.dp
.get_discovered_participant_data(InstanceHandle::from_raw(handle))
{
Ok(d) => d,
Err(_) => return ZeroDdsStatus::BadParameter as c_int,
};
let mut guid = [0u8; 16];
guid.copy_from_slice(&data.key.to_bytes());
let bytes = data.user_data.into_boxed_slice();
let len = bytes.len();
let p_data = if len == 0 {
ptr::null()
} else {
Box::leak(bytes).as_ptr()
};
unsafe {
*out = ZeroDdsParticipantBuiltinTopicData {
guid,
user_data: p_data,
user_data_len: len,
};
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_builtin_userdata_free(p: *const u8, len: usize) {
if p.is_null() || len == 0 {
return;
}
let _ = unsafe { Box::from_raw(slice::from_raw_parts_mut(p as *mut u8, len)) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_get_discovered_topic_data(
p: *mut ZeroDdsDomainParticipant,
handle: u64,
out: *mut ZeroDdsTopicBuiltinTopicData,
) -> c_int {
if p.is_null() || out.is_null() {
return ZeroDdsStatus::BadParameter as c_int;
}
let pp = unsafe { &*p };
let data = match pp
.dp
.get_discovered_topic_data(InstanceHandle::from_raw(handle))
{
Ok(d) => d,
Err(_) => return ZeroDdsStatus::BadParameter as c_int,
};
let mut key = [0u8; 16];
key.copy_from_slice(&data.key.to_bytes());
let name_c = CString::new(data.name.as_bytes())
.unwrap_or_default()
.into_raw();
let type_c = CString::new(data.type_name.as_bytes())
.unwrap_or_default()
.into_raw();
unsafe {
*out = ZeroDdsTopicBuiltinTopicData {
key,
name: name_c,
type_name: type_c,
durability_kind: data.durability as u32,
reliability_kind: data.reliability as u32,
};
}
ZeroDdsStatus::Ok as c_int
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_discovered_publications_count(
p: *mut ZeroDdsDomainParticipant,
) -> usize {
if p.is_null() {
return 0;
}
let pp = unsafe { &*p };
pp.dp.discovered_publications_count()
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn zerodds_dp_discovered_subscriptions_count(
p: *mut ZeroDdsDomainParticipant,
) -> usize {
if p.is_null() {
return 0;
}
let pp = unsafe { &*p };
pp.dp.discovered_subscriptions_count()
}
#[allow(dead_code)]
fn _suppress(_: Vec<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_delete_contained_entities;
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 discovered_topics_empty_initially() {
let p = mk(61);
let mut buf = [0u64; 16];
let mut count = 0usize;
let rc = unsafe { zerodds_dp_get_discovered_topics(p, buf.as_mut_ptr(), &mut count, 16) };
assert_eq!(rc, ZeroDdsStatus::Ok as c_int);
assert_eq!(count, 0);
cleanup(p);
}
#[test]
fn discovered_publications_count_starts_zero() {
let p = mk(62);
assert_eq!(unsafe { zerodds_dp_discovered_publications_count(p) }, 0);
assert_eq!(unsafe { zerodds_dp_discovered_subscriptions_count(p) }, 0);
cleanup(p);
}
#[test]
fn discovered_participant_data_unknown_handle_returns_error() {
let p = mk(63);
let mut data = ZeroDdsParticipantBuiltinTopicData {
guid: [0u8; 16],
user_data: ptr::null(),
user_data_len: 0,
};
let rc = unsafe { zerodds_dp_get_discovered_participant_data(p, 0xDEAD, &mut data) };
assert_eq!(rc, ZeroDdsStatus::BadParameter as c_int);
cleanup(p);
}
}