Skip to main content

vane_core/
token.rs

1//! Completion tokens: routing CQEs back to the session and operation that
2//! produced them.
3//!
4//! Layout (64 bits): `[ op: 8 | generation: 16 | slot: 24 | aux: 16 ]`.
5//! The 16-bit generation guards against stale completions for a slot whose
6//! session was closed and its slot reused.
7
8use std::fmt;
9
10/// Operation kind encoded in a [`Token`].
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[repr(u8)]
13pub enum Op {
14    /// Listener readiness (a new connection can be accepted).
15    Accept = 1,
16    /// Read from the downstream (client-facing) socket.
17    DownstreamRead = 2,
18    /// Write to the downstream socket.
19    DownstreamWrite = 3,
20    /// Read from the upstream (backend) socket.
21    UpstreamRead = 4,
22    /// Write to the upstream socket.
23    UpstreamWrite = 5,
24    /// Nonblocking connect to an upstream completed.
25    Connect = 6,
26    /// Splice pump progress (L4 passthrough).
27    Splice = 7,
28}
29
30/// Uniquely identifies an in-flight engine operation.
31#[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    /// Packs `op`, `slot`, `generation`, and an auxiliary value.
42    #[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    /// Listener token (aux = listener index).
55    #[must_use]
56    #[inline]
57    pub fn accept(listener: u16) -> Self {
58        Self::new(Op::Accept, 0, 0, listener)
59    }
60
61    /// Decodes the operation kind.
62    #[must_use]
63    #[inline]
64    pub fn op(self) -> Op {
65        // SAFETY-free: all byte patterns 0..=7 are valid `Op` discriminants
66        // we ever encode; anything else maps to a panic-free fallback.
67        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    /// Decodes the session slot.
79    #[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    /// Decodes the session generation.
86    #[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    /// Decodes the auxiliary payload.
93    #[must_use]
94    #[inline]
95    pub fn aux(self) -> u16 {
96        (self.0 >> Self::AUX_SHIFT) as u16
97    }
98
99    /// Raw bits (engine backends store tokens directly).
100    #[must_use]
101    #[inline]
102    pub fn bits(self) -> u64 {
103        self.0
104    }
105
106    /// Rebuilds a token from raw bits.
107    #[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}