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