compio_net/cmsg/
mod.rs

1use std::marker::PhantomData;
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        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 [u8]) -> Self {
97        buffer.fill(0);
98        Self {
99            inner: sys::CMsgIter::new(buffer.as_ptr(), buffer.len()),
100            len: 0,
101            _p: PhantomData,
102        }
103    }
104
105    /// Finishes building, returns length of the control message.
106    pub fn finish(self) -> usize {
107        self.len
108    }
109
110    /// Try to append a control message entry into the buffer. If the buffer
111    /// does not have enough space or is not properly aligned with the value
112    /// type, returns `None`.
113    pub fn try_push<T>(&mut self, level: i32, ty: i32, value: T) -> Option<()> {
114        if !self.inner.is_aligned::<T>() || !self.inner.is_space_enough::<T>() {
115            return None;
116        }
117
118        // SAFETY: the buffer is zeroed and the pointer is valid and aligned
119        unsafe {
120            let mut cmsg = self.inner.current_mut()?;
121            cmsg.set_level(level);
122            cmsg.set_ty(ty);
123            self.len += cmsg.set_data(value);
124
125            self.inner.next();
126        }
127
128        Some(())
129    }
130}