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