1 use crate::err::ValueTooBigError; 2 3 /// 6 bit unsigned integer containing the "Differentiated Services 4 /// Code Point" (present in the [`crate::Ipv4Header`]). 5 #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 6 pub struct Ipv4Dscp(u8); 7 8 impl Ipv4Dscp { 9 /// Ipv4Dscp with value 0. 10 pub const ZERO: Ipv4Dscp = Ipv4Dscp(0); 11 12 /// Maximum value of an IPv4 header DSCP. 13 pub const MAX_U8: u8 = 0b0011_1111; 14 15 /// Tries to create an [`Ipv4Dscp`] and checks that the passed value 16 /// is smaller or equal than [`Ipv4Dscp::MAX_U8`] (6 bit unsigned integer). 17 /// 18 /// In case the passed value is bigger then what can be represented in an 6 bit 19 /// integer an error is returned. Otherwise an `Ok` containing the [`Ipv4Dscp`]. 20 /// 21 /// ``` 22 /// use etherparse::Ipv4Dscp; 23 /// 24 /// let dscp = Ipv4Dscp::try_new(32).unwrap(); 25 /// assert_eq!(dscp.value(), 32); 26 /// 27 /// // if a number that can not be represented in an 6 bit integer 28 /// // gets passed in an error is returned 29 /// use etherparse::err::{ValueTooBigError, ValueType}; 30 /// assert_eq!( 31 /// Ipv4Dscp::try_new(Ipv4Dscp::MAX_U8 + 1), 32 /// Err(ValueTooBigError{ 33 /// actual: Ipv4Dscp::MAX_U8 + 1, 34 /// max_allowed: Ipv4Dscp::MAX_U8, 35 /// value_type: ValueType::Ipv4Dscp, 36 /// }) 37 /// ); 38 /// ``` 39 #[inline] try_new(value: u8) -> Result<Ipv4Dscp, ValueTooBigError<u8>>40 pub const fn try_new(value: u8) -> Result<Ipv4Dscp, ValueTooBigError<u8>> { 41 use crate::err::ValueType; 42 if value <= Ipv4Dscp::MAX_U8 { 43 Ok(Ipv4Dscp(value)) 44 } else { 45 Err(ValueTooBigError { 46 actual: value, 47 max_allowed: Ipv4Dscp::MAX_U8, 48 value_type: ValueType::Ipv4Dscp, 49 }) 50 } 51 } 52 53 /// Creates an [`Ipv4Dscp`] without checking that the value 54 /// is smaller or equal than [`Ipv4Dscp::MAX_U8`] (6 bit unsigned integer). 55 /// The caller must guarantee that `value <= Ipv4Dscp::MAX_U8`. 56 /// 57 /// # Safety 58 /// 59 /// `value` must be smaller or equal than [`Ipv4Dscp::MAX_U8`] 60 /// otherwise the behavior of functions or data structures relying 61 /// on this pre-requirement is undefined. 62 #[inline] new_unchecked(value: u8) -> Ipv4Dscp63 pub const unsafe fn new_unchecked(value: u8) -> Ipv4Dscp { 64 debug_assert!(value <= Ipv4Dscp::MAX_U8); 65 Ipv4Dscp(value) 66 } 67 68 /// Returns the underlying unsigned 6 bit value as an `u8` value. 69 #[inline] value(self) -> u870 pub const fn value(self) -> u8 { 71 self.0 72 } 73 } 74 75 impl core::fmt::Display for Ipv4Dscp { 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<Ipv4Dscp> for u8 { 83 #[inline] from(value: Ipv4Dscp) -> Self84 fn from(value: Ipv4Dscp) -> Self { 85 value.0 86 } 87 } 88 89 impl TryFrom<u8> for Ipv4Dscp { 90 type Error = ValueTooBigError<u8>; 91 92 #[inline] try_from(value: u8) -> Result<Self, Self::Error>93 fn try_from(value: u8) -> Result<Self, Self::Error> { 94 use crate::err::ValueType; 95 if value <= Ipv4Dscp::MAX_U8 { 96 Ok(Ipv4Dscp(value)) 97 } else { 98 Err(Self::Error { 99 actual: value, 100 max_allowed: Ipv4Dscp::MAX_U8, 101 value_type: ValueType::Ipv4Dscp, 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 = Ipv4Dscp(32); 119 let b = a; 120 assert_eq!(a, b); 121 assert_eq!(a.clone(), a); 122 } 123 124 // default 125 { 126 let actual: Ipv4Dscp = Default::default(); 127 assert_eq!(actual.value(), 0); 128 } 129 130 // debug 131 { 132 let a = Ipv4Dscp(32); 133 assert_eq!(format!("{:?}", a), format!("Ipv4Dscp(32)")); 134 } 135 136 // ord & partial ord 137 { 138 use core::cmp::Ordering; 139 let a = Ipv4Dscp(32); 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 Ipv4Dscp(64).hash(&mut hasher); 151 hasher.finish() 152 }; 153 let b = { 154 let mut hasher = DefaultHasher::new(); 155 Ipv4Dscp(64).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..=0b0011_1111u8, 166 invalid_value in 0b0100_0000u8..=u8::MAX 167 ) { 168 use crate::err::{ValueType, ValueTooBigError}; 169 assert_eq!( 170 valid_value, 171 Ipv4Dscp::try_new(valid_value).unwrap().value() 172 ); 173 assert_eq!( 174 Ipv4Dscp::try_new(invalid_value).unwrap_err(), 175 ValueTooBigError{ 176 actual: invalid_value, 177 max_allowed: 0b0011_1111, 178 value_type: ValueType::Ipv4Dscp 179 } 180 ); 181 } 182 } 183 184 proptest! { 185 #[test] 186 fn try_from( 187 valid_value in 0..=0b0011_1111u8, 188 invalid_value in 0b0100_0000u8..=u8::MAX 189 ) { 190 use crate::err::{ValueType, ValueTooBigError}; 191 // try_into 192 { 193 let actual: Ipv4Dscp = valid_value.try_into().unwrap(); 194 assert_eq!(actual.value(), valid_value); 195 196 let err: Result<Ipv4Dscp, ValueTooBigError<u8>> = invalid_value.try_into(); 197 assert_eq!( 198 err.unwrap_err(), 199 ValueTooBigError{ 200 actual: invalid_value, 201 max_allowed: 0b0011_1111, 202 value_type: ValueType::Ipv4Dscp 203 } 204 ); 205 } 206 // try_from 207 { 208 assert_eq!( 209 Ipv4Dscp::try_from(valid_value).unwrap().value(), 210 valid_value 211 ); 212 213 assert_eq!( 214 Ipv4Dscp::try_from(invalid_value).unwrap_err(), 215 ValueTooBigError{ 216 actual: invalid_value, 217 max_allowed: 0b0011_1111, 218 value_type: ValueType::Ipv4Dscp 219 } 220 ); 221 } 222 } 223 } 224 225 proptest! { 226 #[test] 227 fn new_unchecked(valid_value in 0..=0b0011_1111u8) { 228 assert_eq!( 229 valid_value, 230 unsafe { 231 Ipv4Dscp::new_unchecked(valid_value).value() 232 } 233 ); 234 } 235 } 236 237 proptest! { 238 #[test] 239 fn fmt(valid_value in 0..=0b0011_1111u8) { 240 assert_eq!(format!("{}", Ipv4Dscp(valid_value)), format!("{}", valid_value)); 241 } 242 } 243 244 proptest! { 245 #[test] 246 fn from(valid_value in 0..=0b0011_1111u8,) { 247 let dscp = Ipv4Dscp::try_new(valid_value).unwrap(); 248 let actual: u8 = dscp.into(); 249 assert_eq!(actual, valid_value); 250 } 251 } 252 } 253