use num_derive::{FromPrimitive, ToPrimitive};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use super::command_message::{CommandMessage, MessageType};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize_repr, Deserialize_repr, FromPrimitive, ToPrimitive)]
#[repr(u8)]
pub enum ControlType {
NoOp = 0,
Initialize = 1,
Finalize = 2,
Register = 3,
RegisterAck = 4,
Configure = 5,
Status = 6,
}
impl Default for ControlType {
fn default() -> Self {
ControlType::NoOp
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct IpcMessageHeader {
pub length: u32,
pub message_type: MessageType,
}
impl IpcMessageHeader {
pub const SIZE: usize = 5;
pub fn new(message_type: MessageType, payload_length: u32) -> Self {
Self {
length: payload_length,
message_type,
}
}
pub fn from_message(msg: &CommandMessage) -> Result<Self, serde_json::Error> {
let payload = serde_json::to_vec(msg)?;
Ok(Self {
length: payload.len() as u32,
message_type: msg.message_type,
})
}
pub fn to_bytes(&self) -> [u8; Self::SIZE] {
let mut bytes = [0u8; Self::SIZE];
bytes[0..4].copy_from_slice(&self.length.to_le_bytes());
bytes[4] = self.message_type as u8;
bytes
}
pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self {
let length = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
let message_type = MessageType::from(bytes[4]);
Self {
length,
message_type,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModuleRegistration {
pub name: String,
pub version: String,
pub capabilities: Vec<String>,
}
impl ModuleRegistration {
pub fn new(name: &str, version: &str) -> Self {
Self {
name: name.to_string(),
version: version.to_string(),
capabilities: Vec::new(),
}
}
pub fn with_capabilities(mut self, caps: Vec<String>) -> Self {
self.capabilities = caps;
self
}
pub fn to_command_message(&self) -> CommandMessage {
CommandMessage::control(
"register",
serde_json::to_value(self).unwrap_or(serde_json::Value::Null),
)
}
pub fn from_command_message(msg: &CommandMessage) -> Result<Self, serde_json::Error> {
serde_json::from_value(msg.data.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_serialization() {
let header = IpcMessageHeader::new(MessageType::Request, 1024);
let bytes = header.to_bytes();
let decoded = IpcMessageHeader::from_bytes(&bytes);
assert_eq!(decoded.length, 1024);
assert_eq!(decoded.message_type, MessageType::Request);
}
#[test]
fn test_header_from_message() {
let msg = CommandMessage::read("test.topic");
let header = IpcMessageHeader::from_message(&msg).unwrap();
assert_eq!(header.message_type, MessageType::Read);
assert!(header.length > 0);
}
#[test]
fn test_module_registration() {
let reg = ModuleRegistration::new("test_module", "1.0.0")
.with_capabilities(vec!["read".to_string(), "write".to_string()]);
let msg = reg.to_command_message();
assert_eq!(msg.message_type, MessageType::Control);
assert!(msg.topic.contains("register"));
let parsed = ModuleRegistration::from_command_message(&msg).unwrap();
assert_eq!(parsed.name, "test_module");
assert_eq!(parsed.version, "1.0.0");
assert_eq!(parsed.capabilities.len(), 2);
}
}