dot15d4_frame/repr/ie/
payloads.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use super::super::super::{Error, Result};
use super::super::super::{NestedInformationElement, PayloadGroupId, PayloadInformationElement};

use super::NestedInformationElementRepr;

use heapless::Vec;

/// A high-level representation of a Payload Information Element.
#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub enum PayloadInformationElementRepr {
    /// MLME Payload Information Element.
    Mlme(Vec<NestedInformationElementRepr, 16>),
    /// Payload Termination Information Element.
    PayloadTermination,
}

#[cfg(feature = "fuzz")]
impl arbitrary::Arbitrary<'_> for PayloadInformationElementRepr {
    fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
        match u.int_in_range(0..=1)? {
            0 => Ok(Self::PayloadTermination),
            _ => {
                let mut nested_information_elements = Vec::new();

                for _ in 0..u.int_in_range(0..=15)? {
                    nested_information_elements
                        .push(NestedInformationElementRepr::arbitrary(u)?)
                        .map_err(|_err| arbitrary::Error::IncorrectFormat)?;
                }

                Ok(Self::Mlme(nested_information_elements))
            }
        }
    }
}

impl PayloadInformationElementRepr {
    /// Parse a Payload Information Element.
    pub fn parse(ie: &PayloadInformationElement<&[u8]>) -> Result<Self> {
        match ie.group_id() {
            PayloadGroupId::Mlme => {
                let mut nested_information_elements = Vec::new();

                for nested_ie in ie.nested_information_elements() {
                    if nested_information_elements
                        .push(NestedInformationElementRepr::parse(&nested_ie)?)
                        .is_err()
                    {
                        break;
                    }
                }

                Ok(Self::Mlme(nested_information_elements))
            }
            _ => Err(Error),
        }
    }

    /// The buffer length required to emit the Payload Information Element.
    pub fn buffer_len(&self) -> usize {
        2 + self.inner_len()
    }

    /// The buffer length required to emit the inner part of the Payload
    /// Information Element.
    fn inner_len(&self) -> usize {
        match self {
            Self::Mlme(nested_ies) => {
                let mut len = 0;

                for ie in nested_ies.iter() {
                    len += ie.buffer_len();
                }

                len
            }
            Self::PayloadTermination => 0,
        }
    }

    /// Emit the Payload Information Element into a buffer.
    pub fn emit(&self, w: &mut PayloadInformationElement<&mut [u8]>) {
        w.clear();
        w.set_length(self.inner_len() as u16);
        w.set_group_id(self.into());

        let buffer = w.content_mut();
        match self {
            Self::Mlme(nested_ies) => {
                let mut offset = 0;
                for ie in nested_ies.iter() {
                    ie.emit(&mut NestedInformationElement::new_unchecked(
                        &mut buffer[offset..],
                    ));
                    offset += ie.buffer_len();
                }
            }
            Self::PayloadTermination => todo!(),
        }
    }
}

impl From<&PayloadInformationElementRepr> for PayloadGroupId {
    fn from(val: &PayloadInformationElementRepr) -> Self {
        use PayloadInformationElementRepr::*;
        match val {
            Mlme(_) => PayloadGroupId::Mlme,
            PayloadTermination => PayloadGroupId::PayloadTermination,
        }
    }
}