Thanks to visit codestin.com
Credit goes to docs.rs

etherparse/net/
ip_dscp_known.rs

1use crate::err::ip::IpDscpUnknownValueError;
2
3use super::IpDscp;
4
5/// Known "Differentiated Services Field Codepoints" (DSCP) values according to
6/// the [IANA registry](https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml)
7/// (exported on 2025-04-24).
8///
9/// DSCP was established in
10/// [RFC-2472](https://datatracker.ietf.org/doc/html/rfc2474) and defined/maintained in the
11/// [IANA dscp-registry](https://www.iana.org/assignments/dscp-registry/dscp-registry.xhtml)
12#[derive(Copy, Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
13pub enum IpDscpKnown {
14    /// Class Selector 0 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
15    ClassSelector0 = 0b0000_0000,
16
17    /// Class Selector 1 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
18    ClassSelector1 = 0b0000_1000,
19
20    /// Class Selector 2 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
21    ClassSelector2 = 0b0001_0000,
22
23    /// Class Selector 3 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
24    ClassSelector3 = 0b0001_1000,
25
26    /// Class Selector 4 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
27    ClassSelector4 = 0b0010_0000,
28
29    /// Class Selector 5 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
30    ClassSelector5 = 0b0010_1000,
31
32    /// Class Selector 6 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
33    ClassSelector6 = 0b0011_0000,
34
35    /// Class Selector 7 (Pool 1) [RFC-2474](https://datatracker.ietf.org/doc/html/rfc2474)
36    ClassSelector7 = 0b0011_1000,
37
38    /// Assured Forwarding PHB Group 11 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
39    AfGroup11 = 0b0000_1010,
40
41    /// Assured Forwarding PHB Group 12 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
42    AfGroup12 = 0b0000_1100,
43
44    /// Assured Forwarding PHB Group 13 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
45    AfGroup13 = 0b0000_1110,
46
47    /// Assured Forwarding PHB Group 21 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
48    AfGroup21 = 0b0001_0010,
49
50    /// Assured Forwarding PHB Group 22 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
51    AfGroup22 = 0b0001_0100,
52
53    /// Assured Forwarding PHB Group 23 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
54    AfGroup23 = 0b0001_0110,
55
56    /// Assured Forwarding PHB Group 31 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
57    AfGroup31 = 0b0001_1010,
58
59    /// Assured Forwarding PHB Group 32 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
60    AfGroup32 = 0b0001_1100,
61
62    /// Assured Forwarding PHB Group 33 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
63    AfGroup33 = 0b0001_1110,
64
65    /// Assured Forwarding PHB Group 41 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
66    AfGroup41 = 0b0010_0010,
67
68    /// Assured Forwarding PHB Group 42 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
69    AfGroup42 = 0b0010_0100,
70
71    /// Assured Forwarding PHB Group 43 (Pool 1) [RFC-2597](https://datatracker.ietf.org/doc/html/rfc2597)
72    AfGroup43 = 0b0010_0110,
73
74    /// Expedited Forwarding (Pool 1) [RFC-3246](https://datatracker.ietf.org/doc/html/rfc3246)
75    ExpeditedForwarding = 0b_0010_1110,
76
77    /// Voice admit (Pool 1) [RFC-5865](https://datatracker.ietf.org/doc/html/rfc5865)
78    VoiceAdmit = 0b0010_1100,
79
80    /// Lower Effort PHB (Pool 3) [RFC-8622](https://datatracker.ietf.org/doc/html/rfc8622)
81    LowerEffort = 0b0000_0001,
82    // NOTE: NQB was omitted here because it has an expiration in the IANA registry.
83}
84
85impl IpDscpKnown {
86    /// Try converting an [`IpDscp`] into a [`IpDscpKnown`] value.
87    ///
88    /// Returns an error if the value is not a known DSCP value.
89    pub const fn try_from_ip_dscp(value: IpDscp) -> Result<IpDscpKnown, IpDscpUnknownValueError> {
90        match value {
91            IpDscp::CS0 => Ok(IpDscpKnown::ClassSelector0),
92            IpDscp::CS1 => Ok(IpDscpKnown::ClassSelector1),
93            IpDscp::CS2 => Ok(IpDscpKnown::ClassSelector2),
94            IpDscp::CS3 => Ok(IpDscpKnown::ClassSelector3),
95            IpDscp::CS4 => Ok(IpDscpKnown::ClassSelector4),
96            IpDscp::CS5 => Ok(IpDscpKnown::ClassSelector5),
97            IpDscp::CS6 => Ok(IpDscpKnown::ClassSelector6),
98            IpDscp::CS7 => Ok(IpDscpKnown::ClassSelector7),
99            IpDscp::AF11 => Ok(IpDscpKnown::AfGroup11),
100            IpDscp::AF12 => Ok(IpDscpKnown::AfGroup12),
101            IpDscp::AF13 => Ok(IpDscpKnown::AfGroup13),
102            IpDscp::AF21 => Ok(IpDscpKnown::AfGroup21),
103            IpDscp::AF22 => Ok(IpDscpKnown::AfGroup22),
104            IpDscp::AF23 => Ok(IpDscpKnown::AfGroup23),
105            IpDscp::AF31 => Ok(IpDscpKnown::AfGroup31),
106            IpDscp::AF32 => Ok(IpDscpKnown::AfGroup32),
107            IpDscp::AF33 => Ok(IpDscpKnown::AfGroup33),
108            IpDscp::AF41 => Ok(IpDscpKnown::AfGroup41),
109            IpDscp::AF42 => Ok(IpDscpKnown::AfGroup42),
110            IpDscp::AF43 => Ok(IpDscpKnown::AfGroup43),
111            IpDscp::EF => Ok(IpDscpKnown::ExpeditedForwarding),
112            IpDscp::VOICE_ADMIT => Ok(IpDscpKnown::VoiceAdmit),
113            IpDscp::LOWER_EFFORT => Ok(IpDscpKnown::LowerEffort),
114            value => Err(IpDscpUnknownValueError {
115                value: value.value(),
116            }),
117        }
118    }
119}
120
121impl TryFrom<IpDscp> for IpDscpKnown {
122    type Error = crate::err::ip::IpDscpUnknownValueError;
123
124    fn try_from(value: IpDscp) -> Result<Self, Self::Error> {
125        Self::try_from_ip_dscp(value)
126    }
127}
128
129impl From<IpDscpKnown> for u8 {
130    fn from(value: IpDscpKnown) -> Self {
131        value as u8
132    }
133}
134
135impl From<IpDscpKnown> for IpDscp {
136    fn from(value: IpDscpKnown) -> Self {
137        // SAFE: As all IpDscpKnown values are bellow the maximum
138        //       value of IpDscp::MAX_U8.
139        unsafe { IpDscp::new_unchecked(value as u8) }
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146    use crate::{err::ip::IpDscpUnknownValueError, IpDscp};
147
148    #[test]
149    fn try_from_ip_dscp() {
150        // ok value conversions
151        {
152            use IpDscpKnown::*;
153            let tests = [
154                (ClassSelector0, 0b0000_0000u8),
155                (ClassSelector1, 0b0000_1000u8),
156                (ClassSelector2, 0b0001_0000u8),
157                (ClassSelector3, 0b0001_1000u8),
158                (ClassSelector4, 0b0010_0000u8),
159                (ClassSelector5, 0b0010_1000u8),
160                (ClassSelector6, 0b0011_0000u8),
161                (ClassSelector7, 0b0011_1000u8),
162                (AfGroup11, 0b0000_1010u8),
163                (AfGroup12, 0b0000_1100u8),
164                (AfGroup13, 0b0000_1110u8),
165                (AfGroup21, 0b0001_0010u8),
166                (AfGroup22, 0b0001_0100u8),
167                (AfGroup23, 0b0001_0110u8),
168                (AfGroup31, 0b0001_1010u8),
169                (AfGroup32, 0b0001_1100u8),
170                (AfGroup33, 0b0001_1110u8),
171                (AfGroup41, 0b0010_0010u8),
172                (AfGroup42, 0b0010_0100u8),
173                (AfGroup43, 0b0010_0110u8),
174                (ExpeditedForwarding, 0b_0010_1110u8),
175                (VoiceAdmit, 0b0010_1100u8),
176                (LowerEffort, 0b0000_0001u8),
177            ];
178            for (expected, value) in tests {
179                let ip_dscp = IpDscp::try_new(value).unwrap();
180                assert_eq!(Ok(expected), IpDscpKnown::try_from_ip_dscp(ip_dscp));
181                assert_eq!(Ok(expected), IpDscpKnown::try_from(ip_dscp));
182            }
183        }
184
185        // unknown conversions (experimental range)
186        {
187            // defined based on IANA registry
188            let unknown_ranges = [
189                2..=7u8,
190                9..=9u8,
191                11..=11u8,
192                13..=13u8,
193                15..=15u8,
194                17..=17u8,
195                19..=19u8,
196                21..=21u8,
197                23..=23u8,
198                25..=25u8,
199                27..=27u8,
200                29..=29u8,
201                31..=31u8,
202                33..=33u8,
203                35..=35u8,
204                37..=37u8,
205                39..=39u8,
206                41..=43u8,
207                45..=45u8,
208                47..=47u8,
209                49..=55u8,
210                57..=0b0011_1111u8,
211            ];
212            for range in unknown_ranges {
213                for value in range {
214                    let ip_dscp = IpDscp::try_new(value).unwrap();
215                    assert_eq!(
216                        Err(IpDscpUnknownValueError { value }),
217                        IpDscpKnown::try_from_ip_dscp(ip_dscp)
218                    );
219                    assert_eq!(
220                        Err(IpDscpUnknownValueError { value }),
221                        IpDscpKnown::try_from(ip_dscp)
222                    );
223                }
224            }
225        }
226    }
227
228    #[test]
229    fn into_u8_and_ip_dscp() {
230        use IpDscpKnown::*;
231        let tests = [
232            (ClassSelector0, 0b0000_0000u8),
233            (ClassSelector1, 0b0000_1000u8),
234            (ClassSelector2, 0b0001_0000u8),
235            (ClassSelector3, 0b0001_1000u8),
236            (ClassSelector4, 0b0010_0000u8),
237            (ClassSelector5, 0b0010_1000u8),
238            (ClassSelector6, 0b0011_0000u8),
239            (ClassSelector7, 0b0011_1000u8),
240            (AfGroup11, 0b0000_1010u8),
241            (AfGroup12, 0b0000_1100u8),
242            (AfGroup13, 0b0000_1110u8),
243            (AfGroup21, 0b0001_0010u8),
244            (AfGroup22, 0b0001_0100u8),
245            (AfGroup23, 0b0001_0110u8),
246            (AfGroup31, 0b0001_1010u8),
247            (AfGroup32, 0b0001_1100u8),
248            (AfGroup33, 0b0001_1110u8),
249            (AfGroup41, 0b0010_0010u8),
250            (AfGroup42, 0b0010_0100u8),
251            (AfGroup43, 0b0010_0110u8),
252            (ExpeditedForwarding, 0b_0010_1110u8),
253            (VoiceAdmit, 0b0010_1100u8),
254            (LowerEffort, 0b0000_0001u8),
255        ];
256        for (input, expected) in tests {
257            assert_eq!(expected, u8::from(input));
258            assert_eq!(IpDscp::try_new(expected).unwrap(), IpDscp::from(input));
259        }
260    }
261}