Skip to main content

st_protocol/
verb.rs

1//! Verb definitions using control ASCII codes as opcodes
2//!
3//! Each verb is a single byte in the control ASCII range (0x01-0x1F).
4//! 0x00 is reserved for END marker.
5
6/// Protocol verbs mapped to control ASCII codes
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[repr(u8)]
9pub enum Verb {
10    // === Core Operations ===
11    /// SOH (0x01) - Scan directory
12    Scan = 0x01,
13    /// STX (0x02) - Format output
14    Format = 0x02,
15    /// ETX (0x03) - Search files/content
16    Search = 0x03,
17    /// EOT (0x04) - End stream/session
18    EndStream = 0x04,
19
20    // === Heartbeat & Status ===
21    /// ENQ (0x05) - Ping/health check
22    Ping = 0x05,
23    /// ACK (0x06) - OK/acknowledgment
24    Ok = 0x06,
25    /// BEL (0x07) - Alert/notification
26    Alert = 0x07,
27
28    // === Navigation & History ===
29    /// BS (0x08) - Back/undo
30    Back = 0x08,
31    /// HT (0x09) - Request context
32    Context = 0x09,
33    /// LF (0x0A) - Next item in sequence
34    Next = 0x0A,
35
36    // === Stats & Completion ===
37    /// VT (0x0B) - Statistics request
38    Stats = 0x0B,
39    /// FF (0x0C) - Clear/reset
40    Clear = 0x0C,
41    /// CR (0x0D) - Complete/commit
42    Complete = 0x0D,
43
44    // === Authentication ===
45    /// SO (0x0E) - Start auth block
46    AuthStart = 0x0E,
47    /// SI (0x0F) - End auth block
48    AuthEnd = 0x0F,
49
50    // === Audio/Media ===
51    /// DLE (0x10) - Audio data (AcousticMemory from liquid-rust)
52    Audio = 0x10,
53
54    // === Access Control ===
55    /// DC1 (0x11) - Permit access
56    Permit = 0x11,
57    /// DC2 (0x12) - Deny access
58    Deny = 0x12,
59    /// DC3 (0x13) - Elevate privileges
60    Elevate = 0x13,
61    /// DC4 (0x14) - Audit log
62    Audit = 0x14,
63
64    // === Error & Subscription ===
65    /// NAK (0x15) - Error response
66    Error = 0x15,
67    /// SYN (0x16) - Subscribe to updates
68    Subscribe = 0x16,
69    /// ETB (0x17) - Unsubscribe
70    Unsubscribe = 0x17,
71    /// CAN (0x18) - Cancel operation
72    Cancel = 0x18,
73
74    // === M8 Memory Operations ===
75    /// EM (0x19) - Wave signal (M8 memory)
76    M8Wave = 0x19,
77    /// SUB (0x1A) - Remember/store
78    Remember = 0x1A,
79    /// FS (0x1C) - Recall from memory
80    Recall = 0x1C,
81    /// GS (0x1D) - Forget/delete
82    Forget = 0x1D,
83
84    // === Session Management ===
85    /// RS (0x1E) - Session control
86    Session = 0x1E,
87    /// US (0x1F) - User identification
88    User = 0x1F,
89}
90
91impl Verb {
92    /// Create verb from raw byte
93    pub fn from_byte(b: u8) -> Option<Self> {
94        match b {
95            0x01 => Some(Verb::Scan),
96            0x02 => Some(Verb::Format),
97            0x03 => Some(Verb::Search),
98            0x04 => Some(Verb::EndStream),
99            0x05 => Some(Verb::Ping),
100            0x06 => Some(Verb::Ok),
101            0x07 => Some(Verb::Alert),
102            0x08 => Some(Verb::Back),
103            0x09 => Some(Verb::Context),
104            0x0A => Some(Verb::Next),
105            0x0B => Some(Verb::Stats),
106            0x0C => Some(Verb::Clear),
107            0x0D => Some(Verb::Complete),
108            0x0E => Some(Verb::AuthStart),
109            0x0F => Some(Verb::AuthEnd),
110            0x10 => Some(Verb::Audio),
111            0x11 => Some(Verb::Permit),
112            0x12 => Some(Verb::Deny),
113            0x13 => Some(Verb::Elevate),
114            0x14 => Some(Verb::Audit),
115            0x15 => Some(Verb::Error),
116            0x16 => Some(Verb::Subscribe),
117            0x17 => Some(Verb::Unsubscribe),
118            0x18 => Some(Verb::Cancel),
119            0x19 => Some(Verb::M8Wave),
120            0x1A => Some(Verb::Remember),
121            0x1C => Some(Verb::Recall),
122            0x1D => Some(Verb::Forget),
123            0x1E => Some(Verb::Session),
124            0x1F => Some(Verb::User),
125            _ => None,
126        }
127    }
128
129    /// Get raw byte value
130    #[inline]
131    pub fn as_byte(self) -> u8 {
132        self as u8
133    }
134
135    /// Check if verb requires authentication
136    pub fn requires_auth(self) -> bool {
137        matches!(
138            self,
139            Verb::Format
140                | Verb::Clear
141                | Verb::Permit
142                | Verb::Deny
143                | Verb::Elevate
144                | Verb::Remember
145                | Verb::Forget
146        )
147    }
148
149    /// Get the security level required for this verb
150    pub fn security_level(self) -> u8 {
151        match self {
152            // Level 0: Read-only (no auth) + memory ops (TODO: add auth in Phase 4)
153            Verb::Scan | Verb::Search | Verb::Stats | Verb::Ping |
154            Verb::Context | Verb::Recall | Verb::Format |
155            Verb::Remember | Verb::Forget | Verb::M8Wave | Verb::Audio => 0,
156
157            // Level 1: Local write (session required)
158            Verb::Clear | Verb::Subscribe | Verb::Unsubscribe => 1,
159
160            // Level 2: Mutate (FIDO required)
161            Verb::Elevate => 2,
162
163            // Level 3: Admin (FIDO + PIN)
164            Verb::Permit | Verb::Deny | Verb::Audit => 3,
165
166            // Everything else: session required
167            _ => 1,
168        }
169    }
170
171    /// Human-readable name
172    pub fn name(self) -> &'static str {
173        match self {
174            Verb::Scan => "SCAN",
175            Verb::Format => "FORMAT",
176            Verb::Search => "SEARCH",
177            Verb::EndStream => "END_STREAM",
178            Verb::Ping => "PING",
179            Verb::Ok => "OK",
180            Verb::Alert => "ALERT",
181            Verb::Back => "BACK",
182            Verb::Context => "CONTEXT",
183            Verb::Next => "NEXT",
184            Verb::Stats => "STATS",
185            Verb::Clear => "CLEAR",
186            Verb::Complete => "COMPLETE",
187            Verb::AuthStart => "AUTH_START",
188            Verb::AuthEnd => "AUTH_END",
189            Verb::Audio => "AUDIO",
190            Verb::Permit => "PERMIT",
191            Verb::Deny => "DENY",
192            Verb::Elevate => "ELEVATE",
193            Verb::Audit => "AUDIT",
194            Verb::Error => "ERROR",
195            Verb::Subscribe => "SUBSCRIBE",
196            Verb::Unsubscribe => "UNSUBSCRIBE",
197            Verb::Cancel => "CANCEL",
198            Verb::M8Wave => "M8_WAVE",
199            Verb::Remember => "REMEMBER",
200            Verb::Recall => "RECALL",
201            Verb::Forget => "FORGET",
202            Verb::Session => "SESSION",
203            Verb::User => "USER",
204        }
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use super::*;
211
212    #[test]
213    fn test_verb_roundtrip() {
214        for b in 0x01..=0x1F {
215            if let Some(verb) = Verb::from_byte(b) {
216                assert_eq!(verb.as_byte(), b);
217            }
218        }
219    }
220
221    #[test]
222    fn test_ping_is_0x05() {
223        assert_eq!(Verb::Ping.as_byte(), 0x05);
224    }
225
226    #[test]
227    fn test_security_levels() {
228        // Read-only operations are level 0
229        assert_eq!(Verb::Scan.security_level(), 0);
230        assert_eq!(Verb::Search.security_level(), 0);
231        assert_eq!(Verb::Ping.security_level(), 0);
232
233        // Admin operations are level 3
234        assert_eq!(Verb::Permit.security_level(), 3);
235        assert_eq!(Verb::Deny.security_level(), 3);
236    }
237}