Skip to content

Commit b9e9e12

Browse files
liljamooherrala
authored andcommitted
Refactor TaggedMacPair and decouple TagStack into a type
1 parent 79b56c8 commit b9e9e12

2 files changed

Lines changed: 118 additions & 49 deletions

File tree

luomu-common/src/addr_pair.rs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
22

3-
use crate::{MacAddr, TaggedMacAddr};
3+
use crate::{tagged_macaddr::TagStack, MacAddr, TagError};
44

55
use super::{Destination, Source};
66

@@ -317,40 +317,68 @@ impl AddrPair<MacAddr> for MacPair {
317317
}
318318
}
319319

320-
/// A pair of tagged MAC addresses.
320+
/// A pair of MAC addresses with support for storing a stack of VLAN IDs.
321321
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
322322
pub struct TaggedMacPair {
323-
src: Source<TaggedMacAddr>,
324-
dst: Destination<TaggedMacAddr>,
323+
src: Source<MacAddr>,
324+
dst: Destination<MacAddr>,
325+
tag_stack: TagStack,
325326
}
326327

327-
impl From<(Source<TaggedMacAddr>, Destination<TaggedMacAddr>)> for TaggedMacPair {
328-
fn from(value: (Source<TaggedMacAddr>, Destination<TaggedMacAddr>)) -> Self {
328+
impl TaggedMacPair {
329+
/// Push a VLAN tag into the stack. The outermost tag should be pushed
330+
/// first.
331+
pub const fn push_tag(&mut self, tag: u16) -> Result<(), TagError> {
332+
self.tag_stack.push_tag(tag)
333+
}
334+
335+
/// Pop a VLAN tag from the stack. The innermost tag pops out first.
336+
pub const fn pop_tag(&mut self) -> Option<u16> {
337+
self.tag_stack.pop_tag()
338+
}
339+
340+
/// Peek a next tag in stack, but don't pop it out.
341+
pub const fn peek_tag(&self) -> Option<u16> {
342+
self.tag_stack.peek_tag()
343+
}
344+
345+
/// Get all tags as an array.
346+
pub fn tag_array(&self) -> [u16; 5] {
347+
self.tag_stack.tag_array()
348+
}
349+
}
350+
351+
impl From<(Source<MacAddr>, Destination<MacAddr>)> for TaggedMacPair {
352+
fn from(value: (Source<MacAddr>, Destination<MacAddr>)) -> Self {
329353
let (src, dst) = value;
330354
TaggedMacPair::new(src, dst)
331355
}
332356
}
333357

334-
impl From<(Destination<TaggedMacAddr>, Source<TaggedMacAddr>)> for TaggedMacPair {
335-
fn from(value: (Destination<TaggedMacAddr>, Source<TaggedMacAddr>)) -> Self {
358+
impl From<(Destination<MacAddr>, Source<MacAddr>)> for TaggedMacPair {
359+
fn from(value: (Destination<MacAddr>, Source<MacAddr>)) -> Self {
336360
let (dst, src) = value;
337361
TaggedMacPair::new(src, dst)
338362
}
339363
}
340364

341-
impl AddrPair<TaggedMacAddr> for TaggedMacPair {
365+
impl AddrPair<MacAddr> for TaggedMacPair {
342366
/// Construct new `TaggedMacPair` with `Source` and `Destination` MAC addresses.
343-
fn new(src: Source<TaggedMacAddr>, dst: Destination<TaggedMacAddr>) -> Self {
344-
Self { src, dst }
367+
fn new(src: Source<MacAddr>, dst: Destination<MacAddr>) -> Self {
368+
Self {
369+
src,
370+
dst,
371+
tag_stack: TagStack::new(),
372+
}
345373
}
346374

347375
/// Return the source Mac.
348-
fn source(&self) -> Source<TaggedMacAddr> {
376+
fn source(&self) -> Source<MacAddr> {
349377
self.src
350378
}
351379

352380
/// Return the destionation Mac.
353-
fn destination(&self) -> Destination<TaggedMacAddr> {
381+
fn destination(&self) -> Destination<MacAddr> {
354382
self.dst
355383
}
356384

@@ -359,6 +387,7 @@ impl AddrPair<TaggedMacAddr> for TaggedMacPair {
359387
Self {
360388
src: self.dst.flip(),
361389
dst: self.src.flip(),
390+
tag_stack: self.tag_stack,
362391
}
363392
}
364393
}

luomu-common/src/tagged_macaddr.rs

Lines changed: 76 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,76 @@
11
use crate::{MacAddr, TagError};
22

3-
// Size of our tag stack. 64bit integer can store up to five VLAN tags.
4-
type TagStack = u64;
3+
/// Size of our tag stack. 64bit integer can store up to five VLAN tags.
4+
type TagStackSize = u64;
55

6-
/// A [MacAddr] with additional support for storing stack of VLAN IDs.
6+
/// A stack of up to five VLAN tags.
77
///
88
/// Tags are stored as a stack where the outermost tag should be pushed first
9-
/// and popped last (aka LIFO). There's enough room to store up to five VLAN
10-
/// IDs.
9+
/// and popped last (aka LIFO).
10+
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
11+
pub struct TagStack(TagStackSize);
12+
13+
impl Default for TagStack {
14+
fn default() -> Self {
15+
Self::new()
16+
}
17+
}
18+
19+
impl TagStack {
20+
/// Construct new [TagStack].
21+
pub const fn new() -> Self {
22+
Self(0)
23+
}
24+
25+
/// Push a VLAN tag into the stack. The outermost tag should be pushed
26+
/// first.
27+
pub const fn push_tag(&mut self, tag: u16) -> Result<(), TagError> {
28+
if tag > 0x0FFF {
29+
return Err(TagError::TooLargeTag);
30+
}
31+
32+
#[allow(clippy::unusual_byte_groupings)] // groups of 12 bits
33+
if self.0 & 0x0FFF_000_000_000_000 == 0 {
34+
self.0 = (self.0 << 12) | tag as TagStackSize;
35+
return Ok(());
36+
}
37+
38+
Err(TagError::TooManyTags)
39+
}
40+
41+
/// Pop a VLAN tag from the stack. The innermost tag pops out first.
42+
pub const fn pop_tag(&mut self) -> Option<u16> {
43+
let Some(tag) = self.peek_tag() else {
44+
return None;
45+
};
46+
self.0 >>= 12;
47+
Some(tag)
48+
}
49+
50+
/// Peek a next tag in stack, but don't pop it out.
51+
pub const fn peek_tag(&self) -> Option<u16> {
52+
let tag = self.0 & 0x0000000000000FFF;
53+
if tag > 0 {
54+
return Some(tag as u16);
55+
}
56+
57+
None
58+
}
59+
60+
/// Get all tags as an array.
61+
#[allow(clippy::unusual_byte_groupings)]
62+
pub fn tag_array(&self) -> [u16; 5] {
63+
let mut tags = [0u16; 5];
64+
tags[0] = ((self.0 & 0x0FFF_000_000_000_000) >> 48) as u16;
65+
tags[1] = ((self.0 & 0x0000_FFF_000_000_000) >> 36) as u16;
66+
tags[2] = ((self.0 & 0x0000_000_FFF_000_000) >> 24) as u16;
67+
tags[3] = ((self.0 & 0x0000_000_000_FFF_000) >> 12) as u16;
68+
tags[4] = (self.0 & 0x0000_000_000_000_FFF) as u16;
69+
tags
70+
}
71+
}
72+
73+
/// A [MacAddr] with additional support for storing a stack of VLAN IDs.
1174
///
1275
/// ```rust
1376
/// use luomu_common::{MacAddr, TaggedMacAddr};
@@ -30,7 +93,10 @@ pub struct TaggedMacAddr {
3093
impl TaggedMacAddr {
3194
/// Construct new [TaggedMacAddr].
3295
pub const fn new(mac: MacAddr) -> Self {
33-
Self { mac, tag_stack: 0 }
96+
Self {
97+
mac,
98+
tag_stack: TagStack::new(),
99+
}
34100
}
35101

36102
/// Get a reference to a [MacAddr].
@@ -46,48 +112,22 @@ impl TaggedMacAddr {
46112
/// Push a VLAN tag into the stack. The outermost tag should be pushed
47113
/// first.
48114
pub const fn push_tag(&mut self, tag: u16) -> Result<(), TagError> {
49-
if tag > 0x0FFF {
50-
return Err(TagError::TooLargeTag);
51-
}
52-
53-
#[allow(clippy::unusual_byte_groupings)] // groups of 12 bits
54-
if self.tag_stack & 0x0FFF_000_000_000_000 == 0 {
55-
self.tag_stack = (self.tag_stack << 12) | tag as TagStack;
56-
return Ok(());
57-
}
58-
59-
Err(TagError::TooManyTags)
115+
self.tag_stack.push_tag(tag)
60116
}
61117

62118
/// Pop a VLAN tag from the stack. The innermost tag pops out first.
63119
pub const fn pop_tag(&mut self) -> Option<u16> {
64-
let Some(tag) = self.peek_tag() else {
65-
return None;
66-
};
67-
self.tag_stack >>= 12;
68-
Some(tag)
120+
self.tag_stack.pop_tag()
69121
}
70122

71123
/// Peek a next tag in stack, but don't pop it out.
72124
pub const fn peek_tag(&self) -> Option<u16> {
73-
let tag = self.tag_stack & 0x0000000000000FFF;
74-
if tag > 0 {
75-
return Some(tag as u16);
76-
}
77-
78-
None
125+
self.tag_stack.peek_tag()
79126
}
80127

81128
/// Get all tags as an array.
82-
#[allow(clippy::unusual_byte_groupings)]
83129
pub fn tag_array(&self) -> [u16; 5] {
84-
let mut tags = [0u16; 5];
85-
tags[0] = ((self.tag_stack & 0x0FFF_000_000_000_000) >> 48) as u16;
86-
tags[1] = ((self.tag_stack & 0x0000_FFF_000_000_000) >> 36) as u16;
87-
tags[2] = ((self.tag_stack & 0x0000_000_FFF_000_000) >> 24) as u16;
88-
tags[3] = ((self.tag_stack & 0x0000_000_000_FFF_000) >> 12) as u16;
89-
tags[4] = (self.tag_stack & 0x0000_000_000_000_FFF) as u16;
90-
tags
130+
self.tag_stack.tag_array()
91131
}
92132
}
93133

0 commit comments

Comments
 (0)