use std::{
ffi::{c_int, c_uchar},
ptr,
};
#[cfg(unix)]
#[path = "unix.rs"]
mod imp;
#[cfg(windows)]
#[path = "windows.rs"]
mod imp;
pub(crate) use imp::Aligned;
pub(crate) struct Encoder<'a, M: MsgHdr> {
hdr: &'a mut M,
cmsg: Option<&'a mut M::ControlMessage>,
len: usize,
}
impl<'a, M: MsgHdr> Encoder<'a, M> {
pub(crate) unsafe fn new(hdr: &'a mut M) -> Self {
Self {
cmsg: unsafe { hdr.cmsg_first_hdr().as_mut() },
hdr,
len: 0,
}
}
pub(crate) fn push<T: Copy>(&mut self, level: c_int, ty: c_int, value: T) {
assert!(align_of::<T>() <= align_of::<M::ControlMessage>());
let space = M::ControlMessage::cmsg_space(size_of_val(&value));
assert!(
self.hdr.control_len() >= self.len + space,
"control message buffer too small. Required: {}, Available: {}",
self.len + space,
self.hdr.control_len()
);
let cmsg = self.cmsg.take().expect("no control buffer space remaining");
cmsg.set(level, ty, M::ControlMessage::cmsg_len(size_of_val(&value)));
unsafe {
ptr::write(cmsg.cmsg_data() as *const T as *mut T, value);
}
self.len += space;
self.cmsg = unsafe { self.hdr.cmsg_nxt_hdr(cmsg).as_mut() };
}
pub(crate) fn finish(self) {
}
}
impl<M: MsgHdr> Drop for Encoder<'_, M> {
fn drop(&mut self) {
self.hdr.set_control_len(self.len as _);
}
}
pub(crate) unsafe fn decode<T: Copy, C: CMsgHdr>(cmsg: &impl CMsgHdr) -> T {
assert!(align_of::<T>() <= align_of::<C>());
debug_assert_eq!(cmsg.len(), C::cmsg_len(size_of::<T>()));
unsafe { ptr::read(cmsg.cmsg_data() as *const T) }
}
pub(crate) struct Iter<'a, M: MsgHdr> {
hdr: &'a M,
cmsg: Option<&'a M::ControlMessage>,
}
impl<'a, M: MsgHdr> Iter<'a, M> {
pub(crate) unsafe fn new(hdr: &'a M) -> Self {
Self {
hdr,
cmsg: unsafe { hdr.cmsg_first_hdr().as_ref() },
}
}
}
impl<'a, M: MsgHdr> Iterator for Iter<'a, M> {
type Item = &'a M::ControlMessage;
fn next(&mut self) -> Option<Self::Item> {
let current = self.cmsg.take()?;
self.cmsg = unsafe { self.hdr.cmsg_nxt_hdr(current).as_ref() };
#[cfg(apple_fast)]
{
if current.len() < size_of::<M::ControlMessage>() {
return None;
}
}
Some(current)
}
}
pub(crate) trait MsgHdr {
type ControlMessage: CMsgHdr;
fn cmsg_first_hdr(&self) -> *mut Self::ControlMessage;
fn cmsg_nxt_hdr(&self, cmsg: &Self::ControlMessage) -> *mut Self::ControlMessage;
fn set_control_len(&mut self, len: usize);
fn control_len(&self) -> usize;
}
pub(crate) trait CMsgHdr {
fn cmsg_len(length: usize) -> usize;
fn cmsg_space(length: usize) -> usize;
fn cmsg_data(&self) -> *mut c_uchar;
fn set(&mut self, level: c_int, ty: c_int, len: usize);
fn len(&self) -> usize;
}
#[cfg(unix)]
pub(crate) const LEN: usize = 96;