lnmp_net/
kind.rs

1//! Message kind classification for LNMP-Net
2
3use std::fmt;
4use std::str::FromStr;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9/// Semantic message classification for network routing and LLM integration
10///
11/// Each kind has different routing, priority, and LLM processing characteristics:
12///
13/// - **Event**: Asynchronous notifications (sensor data, telemetry, user actions)
14/// - **State**: System/component state snapshots (health status, metrics)
15/// - **Command**: Imperative actions ("start motor", "deploy model")
16/// - **Query**: Information requests ("get current temperature")
17/// - **Alert**: Critical warnings (health/safety/security)
18///
19/// # Examples
20///
21/// ```
22/// use lnmp_net::MessageKind;
23///
24/// let kind = MessageKind::Event;
25/// assert_eq!(kind.to_string(), "Event");
26/// assert_eq!(kind.default_priority(), 100);
27/// assert_eq!(kind.default_ttl_ms(), 5000);
28/// ```
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
30#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
31pub enum MessageKind {
32    /// Sensor data, telemetry, system events
33    #[default]
34    Event,
35    /// Component/system state snapshots
36    State,
37    /// Imperative actions ("do this")
38    Command,
39    /// Information requests ("give me data")
40    Query,
41    /// Critical health/safety/security warnings
42    Alert,
43}
44
45impl MessageKind {
46    /// Returns true if this is an Alert message
47    pub fn is_alert(&self) -> bool {
48        matches!(self, MessageKind::Alert)
49    }
50
51    /// Returns true if this is a Command message
52    pub fn is_command(&self) -> bool {
53        matches!(self, MessageKind::Command)
54    }
55
56    /// Returns true if this is a Query message
57    pub fn is_query(&self) -> bool {
58        matches!(self, MessageKind::Query)
59    }
60
61    /// Returns true if this is an Event message
62    pub fn is_event(&self) -> bool {
63        matches!(self, MessageKind::Event)
64    }
65
66    /// Returns true if this is a State message
67    pub fn is_state(&self) -> bool {
68        matches!(self, MessageKind::State)
69    }
70
71    /// Returns the default priority for this message kind (0-255)
72    ///
73    /// Priority ranges:
74    /// - Alert: 255 (critical)
75    /// - Command: 150 (high)
76    /// - Query: 120 (medium-high)
77    /// - State: 100 (medium)
78    /// - Event: 100 (medium)
79    pub fn default_priority(&self) -> u8 {
80        match self {
81            MessageKind::Alert => 255,
82            MessageKind::Command => 150,
83            MessageKind::Query => 120,
84            MessageKind::State => 100,
85            MessageKind::Event => 100,
86        }
87    }
88
89    /// Returns the default TTL (time-to-live) in milliseconds
90    ///
91    /// TTL ranges:
92    /// - Alert: 1000ms (1s - urgent)
93    /// - Command: 2000ms (2s - timely execution)
94    /// - Query: 5000ms (5s - quick response)
95    /// - State: 10000ms (10s - snapshot validity)
96    /// - Event: 5000ms (5s - real-time relevance)
97    pub fn default_ttl_ms(&self) -> u32 {
98        match self {
99            MessageKind::Alert => 1000,
100            MessageKind::Command => 2000,
101            MessageKind::Query => 5000,
102            MessageKind::State => 10000,
103            MessageKind::Event => 5000,
104        }
105    }
106
107    /// Returns all message kinds as an array
108    pub fn all() -> [MessageKind; 5] {
109        [
110            MessageKind::Event,
111            MessageKind::State,
112            MessageKind::Command,
113            MessageKind::Query,
114            MessageKind::Alert,
115        ]
116    }
117}
118
119impl fmt::Display for MessageKind {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        match self {
122            MessageKind::Event => write!(f, "Event"),
123            MessageKind::State => write!(f, "State"),
124            MessageKind::Command => write!(f, "Command"),
125            MessageKind::Query => write!(f, "Query"),
126            MessageKind::Alert => write!(f, "Alert"),
127        }
128    }
129}
130
131impl FromStr for MessageKind {
132    type Err = String;
133
134    fn from_str(s: &str) -> Result<Self, Self::Err> {
135        match s.to_lowercase().as_str() {
136            "event" => Ok(MessageKind::Event),
137            "state" => Ok(MessageKind::State),
138            "command" => Ok(MessageKind::Command),
139            "query" => Ok(MessageKind::Query),
140            "alert" => Ok(MessageKind::Alert),
141            _ => Err(format!("Invalid MessageKind: {}", s)),
142        }
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn test_message_kind_display() {
152        assert_eq!(MessageKind::Event.to_string(), "Event");
153        assert_eq!(MessageKind::State.to_string(), "State");
154        assert_eq!(MessageKind::Command.to_string(), "Command");
155        assert_eq!(MessageKind::Query.to_string(), "Query");
156        assert_eq!(MessageKind::Alert.to_string(), "Alert");
157    }
158
159    #[test]
160    fn test_message_kind_from_str() {
161        assert_eq!("event".parse::<MessageKind>().unwrap(), MessageKind::Event);
162        assert_eq!("Event".parse::<MessageKind>().unwrap(), MessageKind::Event);
163        assert_eq!("EVENT".parse::<MessageKind>().unwrap(), MessageKind::Event);
164        assert_eq!("alert".parse::<MessageKind>().unwrap(), MessageKind::Alert);
165        assert!("invalid".parse::<MessageKind>().is_err());
166    }
167
168    #[test]
169    fn test_is_methods() {
170        assert!(MessageKind::Alert.is_alert());
171        assert!(!MessageKind::Event.is_alert());
172
173        assert!(MessageKind::Command.is_command());
174        assert!(!MessageKind::Query.is_command());
175
176        assert!(MessageKind::Event.is_event());
177        assert!(MessageKind::State.is_state());
178        assert!(MessageKind::Query.is_query());
179    }
180
181    #[test]
182    fn test_default_priority_ranges() {
183        assert_eq!(MessageKind::Alert.default_priority(), 255);
184        assert_eq!(MessageKind::Command.default_priority(), 150);
185        assert_eq!(MessageKind::Query.default_priority(), 120);
186        assert_eq!(MessageKind::State.default_priority(), 100);
187        assert_eq!(MessageKind::Event.default_priority(), 100);
188    }
189
190    #[test]
191    fn test_default_ttl_values() {
192        assert_eq!(MessageKind::Alert.default_ttl_ms(), 1000);
193        assert_eq!(MessageKind::Command.default_ttl_ms(), 2000);
194        assert_eq!(MessageKind::Query.default_ttl_ms(), 5000);
195        assert_eq!(MessageKind::State.default_ttl_ms(), 10000);
196        assert_eq!(MessageKind::Event.default_ttl_ms(), 5000);
197    }
198
199    #[test]
200    fn test_all_kinds() {
201        let all = MessageKind::all();
202        assert_eq!(all.len(), 5);
203        assert!(all.contains(&MessageKind::Event));
204        assert!(all.contains(&MessageKind::Alert));
205    }
206
207    #[test]
208    fn test_default() {
209        assert_eq!(MessageKind::default(), MessageKind::Event);
210    }
211}