neli/
iter.rs

1//! Module for iteration over netlink responses
2
3use std::{io::Cursor, marker::PhantomData};
4
5use log::trace;
6
7use crate::{
8    FromBytes, FromBytesWithInput, Size, consts::nl::NlType, err::SocketError, nl::Nlmsghdr,
9};
10
11/// Iterator over a single buffer received from a [`recv`][crate::socket::NlSocket::recv]
12/// call.
13pub struct NlBufferIter<T, P, B> {
14    buffer: Cursor<B>,
15    next_is_none: bool,
16    data: PhantomData<(T, P)>,
17}
18
19impl<T, P, B> NlBufferIter<T, P, B>
20where
21    B: AsRef<[u8]>,
22{
23    #[cfg(any(feature = "sync", feature = "async"))]
24    pub(crate) fn new(buffer: Cursor<B>) -> Self {
25        NlBufferIter {
26            buffer,
27            next_is_none: false,
28            data: PhantomData,
29        }
30    }
31
32    /// Optional method for parsing messages of varied types in the same buffer. Models
33    /// the [`Iterator`] API.
34    pub fn next_typed<TT, PP>(&mut self) -> Option<Result<Nlmsghdr<TT, PP>, SocketError>>
35    where
36        TT: NlType,
37        PP: Size + FromBytesWithInput<Input = usize>,
38    {
39        if self.buffer.position() as usize == self.buffer.get_ref().as_ref().len()
40            || self.next_is_none
41        {
42            None
43        } else {
44            match Nlmsghdr::from_bytes(&mut self.buffer).map_err(SocketError::from) {
45                Ok(msg) => {
46                    trace!("Message received: {msg:?}");
47                    Some(Ok(msg))
48                }
49                Err(e) => {
50                    self.next_is_none = true;
51                    Some(Err(e))
52                }
53            }
54        }
55    }
56}
57
58impl<T, P, B> Iterator for NlBufferIter<T, P, B>
59where
60    B: AsRef<[u8]>,
61    T: NlType,
62    P: Size + FromBytesWithInput<Input = usize>,
63{
64    type Item = Result<Nlmsghdr<T, P>, SocketError>;
65
66    fn next(&mut self) -> Option<Self::Item> {
67        self.next_typed::<T, P>()
68    }
69}