use std::{marker::PhantomData, mem::MaybeUninit};
cfg_if::cfg_if! {
if #[cfg(windows)] {
#[path = "windows.rs"]
mod sys;
} else if #[cfg(unix)] {
#[path = "unix.rs"]
mod sys;
}
}
pub struct CMsgRef<'a>(sys::CMsgRef<'a>);
impl CMsgRef<'_> {
pub fn level(&self) -> i32 {
self.0.level()
}
pub fn ty(&self) -> i32 {
self.0.ty()
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.0.len() as _
}
pub unsafe fn data<T>(&self) -> &T {
unsafe { self.0.data() }
}
}
pub struct CMsgIter<'a> {
inner: sys::CMsgIter,
_p: PhantomData<&'a ()>,
}
impl<'a> CMsgIter<'a> {
pub unsafe fn new(buffer: &'a [u8]) -> Self {
Self {
inner: sys::CMsgIter::new(buffer.as_ptr(), buffer.len()),
_p: PhantomData,
}
}
}
impl<'a> Iterator for CMsgIter<'a> {
type Item = CMsgRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
let cmsg = self.inner.current();
self.inner.next();
cmsg.map(CMsgRef)
}
}
}
pub struct CMsgBuilder<'a> {
inner: sys::CMsgIter,
len: usize,
_p: PhantomData<&'a mut ()>,
}
impl<'a> CMsgBuilder<'a> {
pub fn new(buffer: &'a mut [MaybeUninit<u8>]) -> Self {
buffer.fill(MaybeUninit::new(0));
Self {
inner: sys::CMsgIter::new(buffer.as_ptr().cast(), buffer.len()),
len: 0,
_p: PhantomData,
}
}
pub fn finish(self) -> usize {
self.len
}
pub fn try_push<T>(&mut self, level: i32, ty: i32, value: T) -> Option<()> {
if !self.inner.is_aligned::<T>() || !self.inner.is_space_enough::<T>() {
return None;
}
unsafe {
let mut cmsg = self.inner.current_mut()?;
cmsg.set_level(level);
cmsg.set_ty(ty);
self.len += cmsg.set_data(value);
self.inner.next();
}
Some(())
}
}