11use 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 {
3093impl 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