etherparse/link/
vlan_pcp.rs

1use crate::err::ValueTooBigError;
2
3/// 3 bit unsigned integer containing the "Priority Code Point"
4/// (present in the [`crate::SingleVlanHeader`]).
5///
6/// Refers to the IEEE 802.1p class of service and maps to the
7/// frame priority level.
8#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
9pub struct VlanPcp(u8);
10
11impl VlanPcp {
12    /// VlanPcp with value 0.
13    pub const ZERO: VlanPcp = VlanPcp(0);
14
15    /// Maximum value of an vlan header PCP.
16    pub const MAX_U8: u8 = 0b0000_0111;
17
18    /// Tries to create an [`VlanPcp`] and checks that the passed value
19    /// is smaller or equal than [`VlanPcp::MAX_U8`] (3 bit unsigned integer).
20    ///
21    /// In case the passed value is bigger then what can be represented in an 3 bit
22    /// integer an error is returned. Otherwise an `Ok` containing the [`VlanPcp`].
23    ///
24    /// ```
25    /// use etherparse::VlanPcp;
26    ///
27    /// let pcp = VlanPcp::try_new(2).unwrap();
28    /// assert_eq!(pcp.value(), 2);
29    ///
30    /// // if a number that can not be represented in an 3 bit integer
31    /// // gets passed in an error is returned
32    /// use etherparse::err::{ValueTooBigError, ValueType};
33    /// assert_eq!(
34    ///     VlanPcp::try_new(VlanPcp::MAX_U8 + 1),
35    ///     Err(ValueTooBigError{
36    ///         actual: VlanPcp::MAX_U8 + 1,
37    ///         max_allowed: VlanPcp::MAX_U8,
38    ///         value_type: ValueType::VlanPcp,
39    ///     })
40    /// );
41    /// ```
42    #[inline]
43    pub const fn try_new(value: u8) -> Result<VlanPcp, ValueTooBigError<u8>> {
44        use crate::err::ValueType;
45        if value <= VlanPcp::MAX_U8 {
46            Ok(VlanPcp(value))
47        } else {
48            Err(ValueTooBigError {
49                actual: value,
50                max_allowed: VlanPcp::MAX_U8,
51                value_type: ValueType::VlanPcp,
52            })
53        }
54    }
55
56    /// Creates an [`VlanPcp`] without checking that the value
57    /// is smaller or equal than [`VlanPcp::MAX_U8`] (3 bit unsigned integer).
58    /// The caller must guarantee that `value <= VlanPcp::MAX_U8`.
59    ///
60    /// # Safety
61    ///
62    /// `value` must be smaller or equal than [`VlanPcp::MAX_U8`]
63    /// otherwise the behavior of functions or data structures relying
64    /// on this pre-requirement is undefined.
65    #[inline]
66    pub const unsafe fn new_unchecked(value: u8) -> VlanPcp {
67        debug_assert!(value <= VlanPcp::MAX_U8);
68        VlanPcp(value)
69    }
70
71    /// Returns the underlying unsigned 3 bit value as an `u8` value.
72    #[inline]
73    pub const fn value(self) -> u8 {
74        self.0
75    }
76}
77
78impl core::fmt::Display for VlanPcp {
79    #[inline]
80    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81        self.0.fmt(f)
82    }
83}
84
85impl From<VlanPcp> for u8 {
86    #[inline]
87    fn from(value: VlanPcp) -> Self {
88        value.0
89    }
90}
91
92impl TryFrom<u8> for VlanPcp {
93    type Error = ValueTooBigError<u8>;
94
95    #[inline]
96    fn try_from(value: u8) -> Result<Self, Self::Error> {
97        use crate::err::ValueType;
98        if value <= VlanPcp::MAX_U8 {
99            Ok(VlanPcp(value))
100        } else {
101            Err(Self::Error {
102                actual: value,
103                max_allowed: VlanPcp::MAX_U8,
104                value_type: ValueType::VlanPcp,
105            })
106        }
107    }
108}
109
110#[cfg(test)]
111mod test {
112    use super::*;
113    use core::hash::{Hash, Hasher};
114    use proptest::prelude::*;
115    use std::format;
116
117    #[test]
118    fn derived_traits() {
119        // copy & clone
120        {
121            let a = VlanPcp(2);
122            let b = a;
123            assert_eq!(a, b);
124            assert_eq!(a.clone(), a);
125        }
126
127        // default
128        {
129            let actual: VlanPcp = Default::default();
130            assert_eq!(actual.value(), 0);
131        }
132
133        // debug
134        {
135            let a = VlanPcp(2);
136            assert_eq!(format!("{:?}", a), format!("VlanPcp(2)"));
137        }
138
139        // ord & partial ord
140        {
141            use core::cmp::Ordering;
142            let a = VlanPcp(2);
143            let b = a;
144            assert_eq!(a.cmp(&b), Ordering::Equal);
145            assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal));
146        }
147
148        // hash
149        {
150            use std::collections::hash_map::DefaultHasher;
151            let a = {
152                let mut hasher = DefaultHasher::new();
153                VlanPcp(2).hash(&mut hasher);
154                hasher.finish()
155            };
156            let b = {
157                let mut hasher = DefaultHasher::new();
158                VlanPcp(2).hash(&mut hasher);
159                hasher.finish()
160            };
161            assert_eq!(a, b);
162        }
163    }
164
165    proptest! {
166        #[test]
167        fn try_new(
168            valid_value in 0..=0b0000_0111u8,
169            invalid_value in 0b0000_1000u8..=u8::MAX
170        ) {
171            use crate::err::{ValueType, ValueTooBigError};
172            assert_eq!(
173                valid_value,
174                VlanPcp::try_new(valid_value).unwrap().value()
175            );
176            assert_eq!(
177                VlanPcp::try_new(invalid_value).unwrap_err(),
178                ValueTooBigError{
179                    actual: invalid_value,
180                    max_allowed: 0b0000_0111,
181                    value_type:  ValueType::VlanPcp
182                }
183            );
184        }
185    }
186
187    proptest! {
188        #[test]
189        fn try_from(
190            valid_value in 0..=0b0000_0111u8,
191            invalid_value in 0b0000_1000u8..=u8::MAX
192        ) {
193            use crate::err::{ValueType, ValueTooBigError};
194            // try_into
195            {
196                let actual: VlanPcp = valid_value.try_into().unwrap();
197                assert_eq!(actual.value(), valid_value);
198
199                let err: Result<VlanPcp, ValueTooBigError<u8>> = invalid_value.try_into();
200                assert_eq!(
201                    err.unwrap_err(),
202                    ValueTooBigError{
203                        actual: invalid_value,
204                        max_allowed: 0b0000_0111,
205                        value_type:  ValueType::VlanPcp
206                    }
207                );
208            }
209            // try_from
210            {
211                assert_eq!(
212                    VlanPcp::try_from(valid_value).unwrap().value(),
213                    valid_value
214                );
215
216                assert_eq!(
217                    VlanPcp::try_from(invalid_value).unwrap_err(),
218                    ValueTooBigError{
219                        actual: invalid_value,
220                        max_allowed: 0b0000_0111,
221                        value_type:  ValueType::VlanPcp
222                    }
223                );
224            }
225        }
226    }
227
228    proptest! {
229        #[test]
230        fn new_unchecked(valid_value in 0..=0b0000_0111u8) {
231            assert_eq!(
232                valid_value,
233                unsafe {
234                    VlanPcp::new_unchecked(valid_value).value()
235                }
236            );
237        }
238    }
239
240    proptest! {
241        #[test]
242        fn fmt(valid_value in 0..=0b0000_0111u8) {
243            assert_eq!(format!("{}", VlanPcp(valid_value)), format!("{}", valid_value));
244        }
245    }
246
247    proptest! {
248        #[test]
249        fn from(valid_value in 0..=0b0000_0111u8,) {
250            let pcp = VlanPcp::try_new(valid_value).unwrap();
251            let actual: u8 = pcp.into();
252            assert_eq!(actual, valid_value);
253        }
254    }
255}