compio_net\cmsg/
mod.rs

1use std::{marker::PhantomData, mem::MaybeUninit};
2
3cfg_if::cfg_if! {
4    if #[cfg(windows)] {
5        #[path = "windows.rs"]
6        mod sys;
7    } else if #[cfg(unix)] {
8        #[path = "unix.rs"]
9        mod sys;
10    }
11}
12
13/// Reference to a control message.
14pub struct CMsgRef<'a>(sys::CMsgRef<'a>);
15
16impl CMsgRef<'_> {
17    /// Returns the level of the control message.
18    pub fn level(&self) -> i32 {
19        self.0.level()
20    }
21
22    /// Returns the type of the control message.
23    pub fn ty(&self) -> i32 {
24        self.0.ty()
25    }
26
27    /// Returns the length of the control message.
28    #[allow(clippy::len_without_is_empty)]
29    pub fn len(&self) -> usize {
30        self.0.len() as _
31    }
32
33    /// Returns a reference to the data of the control message.
34    ///
35    /// # Safety
36    ///
37    /// The data part must be properly aligned and contains an initialized
38    /// instance of `T`.
39    pub unsafe fn data<T>(&self) -> &T {
40        unsafe { self.0.data() }
41    }
42}
43
44/// An iterator for control messages.
45pub struct CMsgIter<'a> {
46    inner: sys::CMsgIter,
47    _p: PhantomData<&'a ()>,
48}
49
50impl<'a> CMsgIter<'a> {
51    /// Create [`CMsgIter`] with the given buffer.
52    ///
53    /// # Panics
54    ///
55    /// This function will panic if the buffer is too short or not properly
56    /// aligned.
57    ///
58    /// # Safety
59    ///
60    /// The buffer should contain valid control messages.
61    pub unsafe fn new(buffer: &'a [u8]) -> Self {
62        Self {
63            inner: sys::CMsgIter::new(buffer.as_ptr(), buffer.len()),
64            _p: PhantomData,
65        }
66    }
67}
68
69impl<'a> Iterator for CMsgIter<'a> {
70    type Item = CMsgRef<'a>;
71
72    fn next(&mut self) -> Option<Self::Item> {
73        unsafe {
74            let cmsg = self.inner.current();
75            self.inner.next();
76            cmsg.map(CMsgRef)
77        }
78    }
79}
80
81/// Helper to construct control message.
82pub struct CMsgBuilder<'a> {
83    inner: sys::CMsgIter,
84    len: usize,
85    _p: PhantomData<&'a mut ()>,
86}
87
88impl<'a> CMsgBuilder<'a> {
89    /// Create [`CMsgBuilder`] with the given buffer. The buffer will be zeroed
90    /// on creation.
91    ///
92    /// # Panics
93    ///
94    /// This function will panic if the buffer is too short or not properly
95    /// aligned.
96    pub fn new(buffer: &'a mut [MaybeUninit<u8>]) -> Self {
97        // TODO: optimize zeroing
98        buffer.fill(MaybeUninit::new(0));
99        Self {
100            inner: sys::CMsgIter::new(buffer.as_ptr().cast(), buffer.len()),
101            len: 0,
102            _p: PhantomData,
103        }
104    }
105
106    /// Finishes building, returns length of the control message.
107    pub fn finish(self) -> usize {
108        self.len
109    }
110
111    /// Try to append a control message entry into the buffer. If the buffer
112    /// does not have enough space or is not properly aligned with the value
113    /// type, returns `None`.
114    pub fn try_push<T>(&mut self, level: i32, ty: i32, value: T) -> Option<()> {
115        if !self.inner.is_aligned::<T>() || !self.inner.is_space_enough::<T>() {
116            return None;
117        }
118
119        // SAFETY: the buffer is zeroed and the pointer is valid and aligned
120        unsafe {
121            let mut cmsg = self.inner.current_mut()?;
122            cmsg.set_level(level);
123            cmsg.set_ty(ty);
124            self.len += cmsg.set_data(value);
125
126            self.inner.next();
127        }
128
129        Some(())
130    }
131}