1 use 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)]
9 pub struct VlanPcp(u8);
10 
11 impl 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]
try_new(value: u8) -> Result<VlanPcp, ValueTooBigError<u8>>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]
new_unchecked(value: u8) -> VlanPcp66     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]
value(self) -> u873     pub const fn value(self) -> u8 {
74         self.0
75     }
76 }
77 
78 impl core::fmt::Display for VlanPcp {
79     #[inline]
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result80     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
81         self.0.fmt(f)
82     }
83 }
84 
85 impl From<VlanPcp> for u8 {
86     #[inline]
from(value: VlanPcp) -> Self87     fn from(value: VlanPcp) -> Self {
88         value.0
89     }
90 }
91 
92 impl TryFrom<u8> for VlanPcp {
93     type Error = ValueTooBigError<u8>;
94 
95     #[inline]
try_from(value: u8) -> Result<Self, Self::Error>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)]
111 mod test {
112     use super::*;
113     use core::hash::{Hash, Hasher};
114     use proptest::prelude::*;
115     use std::format;
116 
117     #[test]
derived_traits()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 }
256