etherparse/link/
single_vlan_header.rs1use crate::*;
2
3#[derive(Clone, Debug, Eq, PartialEq, Default)]
5pub struct SingleVlanHeader {
6 pub pcp: VlanPcp,
8 pub drop_eligible_indicator: bool,
10 pub vlan_id: VlanId,
12 pub ether_type: EtherType,
14}
15
16impl SingleVlanHeader {
17 pub const LEN: usize = 4;
19
20 #[deprecated(since = "0.14.0", note = "Use `SingleVlanHeader::LEN` instead")]
21 pub const SERIALIZED_SIZE: usize = SingleVlanHeader::LEN;
22
23 #[deprecated(since = "0.10.1", note = "Use SingleVlanHeader::from_slice instead.")]
25 #[inline]
26 pub fn read_from_slice(slice: &[u8]) -> Result<(SingleVlanHeader, &[u8]), err::LenError> {
27 SingleVlanHeader::from_slice(slice)
28 }
29
30 #[inline]
32 pub fn from_slice(slice: &[u8]) -> Result<(SingleVlanHeader, &[u8]), err::LenError> {
33 Ok((
34 SingleVlanHeaderSlice::from_slice(slice)?.to_header(),
35 &slice[SingleVlanHeader::LEN..],
36 ))
37 }
38
39 #[inline]
41 pub fn from_bytes(bytes: [u8; 4]) -> SingleVlanHeader {
42 SingleVlanHeader {
43 pcp: unsafe {
44 VlanPcp::new_unchecked((bytes[0] >> 5) & 0b0000_0111u8)
47 },
48 drop_eligible_indicator: 0 != (bytes[0] & 0b0001_0000u8),
49 vlan_id: unsafe {
50 VlanId::new_unchecked(u16::from_be_bytes([bytes[0] & 0b0000_1111u8, bytes[1]]))
53 },
54 ether_type: EtherType(u16::from_be_bytes([bytes[2], bytes[3]])),
55 }
56 }
57
58 #[cfg(feature = "std")]
60 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
61 pub fn read<T: std::io::Read + std::io::Seek + Sized>(
62 reader: &mut T,
63 ) -> Result<SingleVlanHeader, std::io::Error> {
64 let buffer = {
65 let mut buffer: [u8; SingleVlanHeader::LEN] = [0; SingleVlanHeader::LEN];
66 reader.read_exact(&mut buffer)?;
67 buffer
68 };
69
70 Ok(
71 unsafe { SingleVlanHeaderSlice::from_slice_unchecked(&buffer) }.to_header(),
73 )
74 }
75
76 #[inline]
78 #[cfg(feature = "std")]
79 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
80 pub fn write<T: std::io::Write + Sized>(&self, writer: &mut T) -> Result<(), std::io::Error> {
81 writer.write_all(&self.to_bytes())
82 }
83
84 #[inline]
86 pub fn header_len(&self) -> usize {
87 4
88 }
89
90 #[inline]
93 pub fn to_bytes(&self) -> [u8; 4] {
94 let id_be = self.vlan_id.value().to_be_bytes();
95 let eth_type_be = self.ether_type.0.to_be_bytes();
96 [
97 (if self.drop_eligible_indicator {
98 id_be[0] | 0x10
99 } else {
100 id_be[0]
101 } | (self.pcp.value() << 5)),
102 id_be[1],
103 eth_type_be[0],
104 eth_type_be[1],
105 ]
106 }
107}
108
109#[cfg(test)]
110mod test {
111 use crate::{test_gens::*, *};
112 use alloc::{format, vec::Vec};
113 use proptest::prelude::*;
114 use std::io::{Cursor, ErrorKind};
115
116 #[test]
117 fn constants() {
118 assert_eq!(4, SingleVlanHeader::LEN);
119 }
120
121 proptest! {
122 #[test]
123 fn from_slice(
124 input in vlan_single_any(),
125 dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
126 ) {
127 let mut buffer: Vec<u8> = Vec::with_capacity(input.header_len() + dummy_data.len());
129 input.write(&mut buffer).unwrap();
130 buffer.extend(&dummy_data[..]);
131
132 {
134 let (result, rest) = SingleVlanHeader::from_slice(&buffer).unwrap();
135 assert_eq!(result, input);
136 assert_eq!(rest, &buffer[4..]);
137 }
138 #[allow(deprecated)]
139 {
140 let (result, rest) = SingleVlanHeader::read_from_slice(&buffer).unwrap();
141 assert_eq!(result, input);
142 assert_eq!(rest, &buffer[4..]);
143 }
144
145 for len in 0..4 {
147 assert_eq!(
148 SingleVlanHeader::from_slice(&buffer[..len])
149 .unwrap_err(),
150 err::LenError{
151 required_len: 4,
152 len: len,
153 len_source: LenSource::Slice,
154 layer: err::Layer::VlanHeader,
155 layer_start_offset: 0,
156 }
157 );
158 }
159 }
160 }
161
162 proptest! {
163 #[test]
164 fn from_bytes(input in vlan_single_any()) {
165 let actual = SingleVlanHeader::from_bytes(
166 input.to_bytes()
167 );
168 assert_eq!(actual, input);
169 }
170 }
171
172 proptest! {
173 #[test]
174 fn read(
175 input in vlan_single_any(),
176 dummy_data in proptest::collection::vec(any::<u8>(), 0..20)
177 ) {
178 let mut buffer: Vec<u8> = Vec::with_capacity(input.header_len() + dummy_data.len());
180 input.write(&mut buffer).unwrap();
181 buffer.extend(&dummy_data[..]);
182
183 {
185 let mut cursor = Cursor::new(&buffer);
186 let result = SingleVlanHeader::read(&mut cursor).unwrap();
187 assert_eq!(result, input);
188 assert_eq!(4, cursor.position());
189 }
190
191 for len in 0..4 {
193 let mut cursor = Cursor::new(&buffer[0..len]);
194 assert_eq!(
195 SingleVlanHeader::read(&mut cursor)
196 .unwrap_err()
197 .kind(),
198 ErrorKind::UnexpectedEof
199 );
200 }
201 }
202 }
203
204 proptest! {
205 #[test]
206 fn write_and_to_bytes(input in vlan_single_any()) {
207 {
209 let mut buffer: Vec<u8> = Vec::with_capacity(input.header_len());
210 input.write(&mut buffer).unwrap();
211 assert_eq!(&buffer[..], &input.to_bytes());
212 {
213 let id_be = input.vlan_id.value().to_be_bytes();
214 let eth_type_be = input.ether_type.0.to_be_bytes();
215 assert_eq!(
216 input.to_bytes(),
217 [
218 (
219 id_be[0] | if input.drop_eligible_indicator {
220 0x10
221 } else {
222 0
223 } | (input.pcp.value() << 5)
224 ),
225 id_be[1],
226 eth_type_be[0],
227 eth_type_be[1]
228 ]
229 );
230 }
231 }
232
233 for len in 0..4 {
235 let mut buffer = [0u8;4];
236 let mut cursor = Cursor::new(&mut buffer[..len]);
237 assert!(input.write(&mut cursor).is_err());
238 }
239 }
240 }
241
242 proptest! {
243 #[test]
244 fn header_len(input in vlan_single_any()) {
245 assert_eq!(4, input.header_len());
246 }
247 }
248
249 #[test]
250 fn default() {
251 let actual: SingleVlanHeader = Default::default();
252 assert_eq!(0, actual.pcp.value());
253 assert_eq!(false, actual.drop_eligible_indicator);
254 assert_eq!(0, actual.vlan_id.value());
255 assert_eq!(0, actual.ether_type.0);
256 }
257
258 proptest! {
259 #[test]
260 fn clone_eq(input in vlan_single_any()) {
261 assert_eq!(input, input.clone());
262 }
263 }
264
265 proptest! {
266 #[test]
267 fn dbg(input in vlan_single_any()) {
268 assert_eq!(
269 &format!(
270 "SingleVlanHeader {{ pcp: {:?}, drop_eligible_indicator: {}, vlan_id: {:?}, ether_type: {:?} }}",
271 input.pcp,
272 input.drop_eligible_indicator,
273 input.vlan_id,
274 input.ether_type,
275 ),
276 &format!("{:?}", input)
277 );
278 }
279 }
280}