use std::io::Write;
use crate::cdr_bounds::{CdrBounds, CdrSize};
use crate::internal::ffi::InternalSample;
use crate::internal::key_hash::KeyHash;
use crate::internal::serdata::Serdata;
use crate::internal::sertype::Sertype;
use crate::sample::SampleOrKeyInner as SampleOrKey;
pub const DDSI_RTPS_HEADER_SIZE: usize = 4;
pub(crate) const fn zeroed_serdata_ops() -> cyclonedds_sys::ddsi_serdata_ops {
unsafe { std::mem::MaybeUninit::zeroed().assume_init() }
}
pub unsafe extern "C" fn eqkey<T>(
lhs: *const cyclonedds_sys::ddsi_serdata,
rhs: *const cyclonedds_sys::ddsi_serdata,
) -> bool
where
T: crate::Topicable,
{
let lhs = unsafe { &mut *(lhs as *mut Serdata<T>) };
let rhs = unsafe { &mut *(rhs as *mut Serdata<T>) };
lhs.key() == rhs.key()
}
pub unsafe extern "C" fn get_size<T>(serdata: *const cyclonedds_sys::ddsi_serdata) -> u32
where
T: crate::Topicable,
{
let serdata = unsafe { &mut *(serdata as *mut Serdata<T>) };
u32::try_from(
serdata
.serialized()
.expect("unable to serialize data")
.len(),
)
.expect("serialized data out of bounds")
}
pub(crate) fn from_ser_buffer<T>(
sertype: &crate::internal::sertype::Sertype<T>,
kind: crate::internal::serdata::Kind,
buffer: &[u8],
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
fn deserialize<'a, T: serde::Deserialize<'a>>(
buffer: &[u8],
) -> Result<(T, usize), cdr_encoding::Error> {
match buffer.split_at_checked(DDSI_RTPS_HEADER_SIZE) {
Some((header, bytes)) => match header {
[0x0, 0x0, ..] => cdr_encoding::from_bytes::<T, byteorder::BigEndian>(bytes),
[0x0, 0x1, ..] => cdr_encoding::from_bytes::<T, byteorder::LittleEndian>(bytes),
_ => Err(cdr_encoding::Error::Message(format!(
"could not determine endianness from CDR header: {header:?}"
))),
},
None => Err(cdr_encoding::Error::Message(format!(
"deserialization failed: byteslice too short to contain valid CDR header: \
{buffer:?}"
))),
}
}
match kind {
crate::internal::serdata::Kind::Key => {
if let Ok((key, _)) = deserialize::<T::Key>(buffer) {
let key = SampleOrKey::new_key(key);
let serdata = Box::new(crate::internal::serdata::Serdata::new(sertype, key));
Box::into_raw(serdata).cast()
} else {
std::ptr::null_mut()
}
}
crate::internal::serdata::Kind::Data => {
if let Ok((data, _)) = deserialize::<T>(buffer) {
let sample = SampleOrKey::new_sample(data);
let serdata = Box::new(crate::internal::serdata::Serdata::new(sertype, sample));
Box::into_raw(serdata).cast()
} else {
std::ptr::null_mut()
}
}
}
}
fn copy_from_fragment(fragment_chain: &cyclonedds_sys::ddsi_rdata, size: usize) -> Option<Vec<u8>> {
if fragment_chain.min != 0 {
return None;
}
let mut buffer = vec![0; size];
let mut offset = 0;
let mut fragment = fragment_chain;
loop {
let min = fragment.min as usize;
let maxp1 = fragment.maxp1 as usize;
if offset < min {
return None;
}
if maxp1 > offset {
let number_of_bytes = maxp1 - offset;
let buffer = buffer.get_mut(offset..offset + number_of_bytes)?;
let src = unsafe {
std::slice::from_raw_parts(
(fragment.rmsg as *const u8)
.add(std::mem::size_of::<cyclonedds_sys::ddsi_rmsg>())
.add(fragment.payload_zoff as usize)
.add(offset - min),
number_of_bytes,
)
};
buffer.copy_from_slice(src);
offset = maxp1;
}
if fragment.nextfrag.is_null() {
break;
}
fragment = unsafe { &*fragment.nextfrag }
}
if offset == size { Some(buffer) } else { None }
}
pub unsafe extern "C" fn from_ser<T>(
sertype: *const cyclonedds_sys::ddsi_sertype,
kind: cyclonedds_sys::ddsi_serdata_kind,
fragment_chain: *const cyclonedds_sys::ddsi_rdata,
size: usize,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let sertype = unsafe { &mut *(sertype as *mut Sertype<T>) };
if fragment_chain.is_null() {
return std::ptr::null_mut();
}
crate::internal::serdata::Kind::try_from(kind).map_or(std::ptr::null_mut(), |kind| {
let fragment_chain = unsafe { &*fragment_chain };
copy_from_fragment(fragment_chain, size).map_or(std::ptr::null_mut(), |buffer| {
from_ser_buffer(sertype, kind, &buffer)
})
})
}
pub unsafe extern "C" fn from_ser_iov<T>(
sertype: *const cyclonedds_sys::ddsi_sertype,
kind: cyclonedds_sys::ddsi_serdata_kind,
containers_len: cyclonedds_sys::ddsrt_msg_iovlen_t,
containers: *const cyclonedds_sys::ddsrt_iovec_t,
size: usize,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let sertype = unsafe { &mut *(sertype as *mut Sertype<T>) };
crate::internal::serdata::Kind::try_from(kind).map_or(std::ptr::null_mut(), |kind| {
let mut buffer: Vec<u8> = Vec::with_capacity(size);
#[cfg(not(target_os = "linux"))]
let Ok(containers_len) = usize::try_from(containers_len) else {
return std::ptr::null_mut();
};
let containers = unsafe { std::slice::from_raw_parts(containers, containers_len) };
let mut offset = 0;
for container in containers {
let container_iov_len = container.iov_len;
#[cfg(target_os = "windows")]
let Ok(container_iov_len) = usize::try_from(container_iov_len) else {
return std::ptr::null_mut();
};
let len = if container_iov_len + offset > size {
size - offset
} else {
container_iov_len
};
let container =
unsafe { std::slice::from_raw_parts(container.iov_base as *const u8, len) };
buffer.extend_from_slice(container);
offset += len;
}
from_ser_buffer(sertype, kind, &buffer)
})
}
pub(crate) fn from_keyhash_with_mode<T>(
sertype: &Sertype<T>,
keyhash: &cyclonedds_sys::ddsi_keyhash,
force_md5: bool,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let max_possible_serialized_size = T::Key::max_serialized_cdr_size();
if force_md5 || max_possible_serialized_size > CdrSize::Bounded(16) {
std::ptr::null_mut()
} else {
if let Ok((key, _)) = cdr_encoding::from_bytes::<_, byteorder::BigEndian>(&keyhash.value) {
let serdata = Box::new(Serdata::new(sertype, SampleOrKey::<T>::new_key(key)));
Box::into_raw(serdata).cast()
} else {
std::ptr::null_mut()
}
}
}
pub unsafe extern "C" fn from_keyhash<T>(
sertype: *const cyclonedds_sys::ddsi_sertype,
keyhash: *const cyclonedds_sys::ddsi_keyhash,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let force_md5 = T::FORCE_MD5_KEYHASH;
let sertype = unsafe { &mut *(sertype as *mut Sertype<T>) };
let keyhash = unsafe { &*keyhash };
from_keyhash_with_mode::<T>(sertype, keyhash, force_md5)
}
pub unsafe extern "C" fn from_sample<T>(
sertype: *const cyclonedds_sys::ddsi_sertype,
kind: cyclonedds_sys::ddsi_serdata_kind,
sample: *const std::ffi::c_void,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let sample = unsafe { &*(sample.cast::<InternalSample<'_, T>>()) };
match (crate::internal::serdata::Kind::try_from(kind), sample) {
(Ok(crate::internal::serdata::Kind::Data), InternalSample::SampleRef(sample)) => {
let sertype = unsafe { &mut *(sertype as *mut Sertype<T>) };
let sample = SampleOrKey::new_sample((*sample).clone());
let serdata = Box::new(Serdata::new(sertype, sample));
Box::into_raw(serdata).cast()
}
(Ok(crate::internal::serdata::Kind::Data), InternalSample::Sample(sample)) => {
let sertype = unsafe { &mut *(sertype as *mut Sertype<T>) };
let sample = SampleOrKey::new_sample(sample.clone());
let serdata = Box::new(Serdata::new(sertype, sample));
Box::into_raw(serdata).cast()
}
(Ok(crate::internal::serdata::Kind::Key), InternalSample::KeyRef(key)) => {
let sertype = unsafe { &mut *(sertype as *mut Sertype<T>) };
let key = SampleOrKey::new_key((*key).clone());
let serdata = Box::new(Serdata::new(sertype, key));
Box::into_raw(serdata).cast()
}
(Ok(crate::internal::serdata::Kind::Key), InternalSample::Key(key)) => {
let sertype = unsafe { &mut *(sertype as *mut Sertype<T>) };
let key = SampleOrKey::new_key(key.clone());
let serdata = Box::new(Serdata::new(sertype, key));
Box::into_raw(serdata).cast()
}
_ => std::ptr::null_mut(),
}
}
pub unsafe extern "C" fn to_ser<T>(
serdata: *const cyclonedds_sys::ddsi_serdata,
a: usize,
b: usize,
c: *mut std::ffi::c_void,
) {
let args = (serdata, a, b, c);
eprintln!(
"serdata_ops::to_ser<{}>({args:?})",
std::any::type_name::<T>()
);
}
pub unsafe extern "C" fn to_ser_ref<T>(
serdata: *const cyclonedds_sys::ddsi_serdata,
offset: usize,
size: usize,
container: *mut cyclonedds_sys::ddsrt_iovec_t,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let serdata = unsafe { &mut *(serdata as *mut Serdata<T>) };
let container = unsafe { &mut *container };
serdata
.serialized_with_size_hint(size)
.ok()
.and_then(|serialized| {
let slice = serialized.get(offset..)?;
container.iov_base = slice.as_ptr() as *mut _;
let iov_len = slice.len();
#[cfg(target_os = "windows")]
let iov_len = cyclonedds_sys::ddsrt_iov_len_t::try_from(iov_len).ok()?;
container.iov_len = iov_len;
Some(())
})
.map(|()| unsafe { cyclonedds_sys::ddsi_serdata_ref(&raw const serdata.inner) })
.unwrap_or_default()
}
pub unsafe extern "C" fn to_ser_unref<T>(
serdata: *mut cyclonedds_sys::ddsi_serdata,
_: *const cyclonedds_sys::ddsrt_iovec_t,
) where
T: crate::Topicable,
{
let serdata = unsafe { &mut *(serdata.cast::<Serdata<T>>()) };
crate::internal::ffi::ddsi_serdata_unref(&mut serdata.inner);
}
pub unsafe extern "C" fn to_sample<T>(
serdata: *const cyclonedds_sys::ddsi_serdata,
sample: *mut std::ffi::c_void,
_buffer: *mut *mut std::ffi::c_void,
_buffer_limit: *mut std::ffi::c_void,
) -> bool
where
T: crate::Topicable,
{
if sample.is_null() {
false
} else {
let serdata = unsafe { &mut *(serdata as *mut Serdata<T>) };
let sample = sample.cast::<InternalSample<'_, T>>();
match serdata.kind() {
crate::internal::serdata::Kind::Key => {
let data = InternalSample::Key(serdata.key().clone());
unsafe {
sample.write(data);
}
true
}
crate::internal::serdata::Kind::Data => {
let data = InternalSample::Sample(serdata.sample().clone());
unsafe {
sample.write(data);
}
true
}
}
}
}
pub unsafe extern "C" fn to_untyped<T>(
serdata: *const cyclonedds_sys::ddsi_serdata,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let serdata = unsafe { &mut *(serdata as *mut Serdata<T>) };
let sertype = unsafe { &mut *(serdata.inner.type_ as *mut Sertype<T>) };
let mut untyped_serdata = Box::new(Serdata::new(
sertype,
SampleOrKey::new_key(serdata.sample.as_ref().key().clone()),
));
untyped_serdata.inner.type_ = std::ptr::null_mut();
Box::into_raw(untyped_serdata).cast()
}
pub unsafe extern "C" fn untyped_to_sample<T>(
_sertype: *const cyclonedds_sys::ddsi_sertype,
serdata: *const cyclonedds_sys::ddsi_serdata,
sample: *mut std::ffi::c_void,
_buffer: *mut *mut std::ffi::c_void,
_buffer_limit: *mut std::ffi::c_void,
) -> bool
where
T: crate::Topicable,
{
if sample.is_null() {
false
} else {
let serdata = unsafe { &mut *(serdata as *mut Serdata<T>) };
let sample = sample.cast::<InternalSample<'_, T>>();
match serdata.kind() {
crate::internal::serdata::Kind::Data => unsafe {
sample.write(InternalSample::Sample(serdata.sample().clone()));
},
crate::internal::serdata::Kind::Key => unsafe {
sample.write(InternalSample::Key(serdata.key().clone()));
},
}
true
}
}
pub unsafe extern "C" fn free<T>(serdata: *mut cyclonedds_sys::ddsi_serdata)
where
T: crate::Topicable,
{
let serdata = unsafe { Box::from_raw(serdata.cast::<Serdata<T>>()) };
drop(serdata);
}
pub unsafe extern "C" fn print<T>(
_sertype: *const cyclonedds_sys::ddsi_sertype,
serdata: *const cyclonedds_sys::ddsi_serdata,
buffer: *mut std::ffi::c_char,
length: usize,
) -> usize
where
T: crate::Topicable,
{
let serdata = unsafe { &mut *(serdata as *mut Serdata<T>) };
let buffer = unsafe { std::slice::from_raw_parts_mut(buffer.cast(), length) };
let mut cursor = std::io::Cursor::new(&mut *buffer);
let _ = write!(cursor, "{:#?}", &*serdata);
let written = cursor
.position()
.try_into()
.unwrap_or(length)
.min(length.saturating_sub(1));
#[allow(clippy::indexing_slicing)]
{
buffer[written] = 0;
}
written
}
pub unsafe extern "C" fn get_keyhash<T>(
serdata: *const cyclonedds_sys::ddsi_serdata,
keyhash: *mut cyclonedds_sys::ddsi_keyhash,
force_md5: bool,
) where
T: crate::Topicable,
{
let serdata = unsafe { &mut *(serdata as *mut Serdata<T>) };
let keyhash = unsafe { &mut *keyhash };
KeyHash::from_key::<T>(serdata.key(), force_md5)
.inspect(|serdata_keyhash| keyhash.value.copy_from_slice(&serdata_keyhash.0));
}
pub unsafe extern "C" fn from_loaned_sample<T>(
sertype: *const cyclonedds_sys::ddsi_sertype,
a: cyclonedds_sys::ddsi_serdata_kind,
b: *const std::ffi::c_char,
c: *mut cyclonedds_sys::dds_loaned_sample,
d: bool,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let args = (sertype, a, b, c, d);
eprintln!(
"serdata_ops::from_loaned_sample<{}>({args:?})",
std::any::type_name::<T>()
);
std::ptr::null_mut()
}
pub unsafe extern "C" fn from_psmx<T>(
sertype: *const cyclonedds_sys::ddsi_sertype,
loan: *mut cyclonedds_sys::dds_loaned_sample,
) -> *mut cyclonedds_sys::ddsi_serdata
where
T: crate::Topicable,
{
let args = (sertype, loan);
eprintln!(
"serdata_ops::from_psmx<{}>({args:?})",
std::any::type_name::<T>()
);
std::ptr::null_mut()
}