1use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[repr(u8)]
13pub enum Op {
14 Accept = 1,
16 DownstreamRead = 2,
18 DownstreamWrite = 3,
20 UpstreamRead = 4,
22 UpstreamWrite = 5,
24 Connect = 6,
26 Splice = 7,
28}
29
30#[derive(Clone, Copy, PartialEq, Eq, Hash)]
32pub struct Token(u64);
33
34impl Token {
35 const OP_BITS: u64 = 8;
36 const GEN_BITS: u64 = 16;
37 const SLOT_BITS: u64 = 24;
38 const SLOT_SHIFT: u64 = Self::OP_BITS + Self::GEN_BITS;
39 const AUX_SHIFT: u64 = Self::SLOT_SHIFT + Self::SLOT_BITS;
40
41 #[must_use]
43 #[inline]
44 pub fn new(op: Op, slot: u32, generation: u16, aux: u16) -> Self {
45 debug_assert!(slot < (1 << Self::SLOT_BITS), "slot overflows token");
46 Self(
47 (op as u64)
48 | ((generation as u64) << Self::OP_BITS)
49 | ((slot as u64) << Self::SLOT_SHIFT)
50 | ((aux as u64) << Self::AUX_SHIFT),
51 )
52 }
53
54 #[must_use]
56 #[inline]
57 pub fn accept(listener: u16) -> Self {
58 Self::new(Op::Accept, 0, 0, listener)
59 }
60
61 #[must_use]
63 #[inline]
64 pub fn op(self) -> Op {
65 match self.0 & ((1 << Self::OP_BITS) - 1) {
68 1 => Op::Accept,
69 2 => Op::DownstreamRead,
70 3 => Op::DownstreamWrite,
71 4 => Op::UpstreamRead,
72 5 => Op::UpstreamWrite,
73 6 => Op::Connect,
74 _ => Op::Splice,
75 }
76 }
77
78 #[must_use]
80 #[inline]
81 pub fn slot(self) -> u32 {
82 ((self.0 >> Self::SLOT_SHIFT) & ((1 << Self::SLOT_BITS) - 1)) as u32
83 }
84
85 #[must_use]
87 #[inline]
88 pub fn generation(self) -> u16 {
89 ((self.0 >> Self::OP_BITS) & ((1 << Self::GEN_BITS) - 1)) as u16
90 }
91
92 #[must_use]
94 #[inline]
95 pub fn aux(self) -> u16 {
96 (self.0 >> Self::AUX_SHIFT) as u16
97 }
98
99 #[must_use]
101 #[inline]
102 pub fn bits(self) -> u64 {
103 self.0
104 }
105
106 #[must_use]
108 #[inline]
109 pub fn from_bits(bits: u64) -> Self {
110 Self(bits)
111 }
112}
113
114impl fmt::Debug for Token {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(
117 f,
118 "Token({:?}, slot {}, generation {}, aux {})",
119 self.op(),
120 self.slot(),
121 self.generation(),
122 self.aux()
123 )
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn roundtrip() {
133 let t = Token::new(Op::DownstreamRead, 123_456, 0xBEEF, 7);
134 assert_eq!(t.op(), Op::DownstreamRead);
135 assert_eq!(t.slot(), 123_456);
136 assert_eq!(t.generation(), 0xBEEF);
137 assert_eq!(t.aux(), 7);
138 }
139
140 #[test]
141 fn accept_token() {
142 let t = Token::accept(3);
143 assert_eq!(t.op(), Op::Accept);
144 assert_eq!(t.aux(), 3);
145 }
146}