1#![no_std]
2extern crate alloc;
3
4use alloc::string::String;
5use alloc::string::ToString;
6use alloc::vec::Vec;
7
8pub const WIRE_MAGIC: u32 = u32::from_le_bytes(*b"MOON");
9pub const WIRE_VERSION: u16 = 1;
10
11#[repr(u16)]
12#[derive(Clone, Copy)]
13pub enum OpCode {
14 EchoTyped = 1,
15 ListProcessTyped = 2,
16}
17
18#[repr(C)]
19pub struct WireHeader {
20 pub magic: u32,
21 pub version: u16,
22 pub op: u16,
23 pub payload_len: u32,
24}
25
26#[derive(Debug)]
27pub enum CodecError {
28 InvalidHeader,
29 WrongMagic,
30 WrongVersion,
31 Truncated,
32 Deserialize,
33 Serialize,
34}
35
36pub trait Codec: Sized {
37 fn encode(&self, out: &mut Vec<u8>);
38 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError>;
39}
40
41impl Codec for u64 {
42 fn encode(&self, out: &mut Vec<u8>) {
43 out.extend_from_slice(&self.to_le_bytes());
44 }
45 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError> {
46 if input.len() < 8 {
47 return Err(CodecError::Truncated);
48 }
49 let mut a = [0u8; 8];
50 a.copy_from_slice(&input[0..8]);
51 Ok((u64::from_le_bytes(a), 8))
52 }
53}
54impl Codec for u32 {
55 fn encode(&self, out: &mut Vec<u8>) {
56 out.extend_from_slice(&self.to_le_bytes());
57 }
58 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError> {
59 if input.len() < 4 {
60 return Err(CodecError::Truncated);
61 }
62 let mut a = [0u8; 4];
63 a.copy_from_slice(&input[0..4]);
64 Ok((u32::from_le_bytes(a), 4))
65 }
66}
67impl Codec for u16 {
68 fn encode(&self, out: &mut Vec<u8>) {
69 out.extend_from_slice(&self.to_le_bytes());
70 }
71 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError> {
72 if input.len() < 2 {
73 return Err(CodecError::Truncated);
74 }
75 let mut a = [0u8; 2];
76 a.copy_from_slice(&input[0..2]);
77 Ok((u16::from_le_bytes(a), 2))
78 }
79}
80impl Codec for bool {
81 fn encode(&self, out: &mut Vec<u8>) {
82 out.push(if *self { 1 } else { 0 });
83 }
84 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError> {
85 if input.is_empty() {
86 Err(CodecError::Truncated)
87 } else {
88 Ok((input[0] != 0, 1))
89 }
90 }
91}
92impl Codec for String {
93 fn encode(&self, out: &mut Vec<u8>) {
94 let b = self.as_bytes();
95 (b.len() as u32).encode(out);
96 out.extend_from_slice(b);
97 }
98 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError> {
99 let (len, mut off) = u32::decode(input)?;
100 let len = len as usize;
101 if input.len() < off + len {
102 return Err(CodecError::Truncated);
103 }
104 let s = core::str::from_utf8(&input[off..off + len])
105 .map_err(|_| CodecError::Deserialize)?
106 .to_string();
107 off += len;
108 Ok((s, off))
109 }
110}
111impl<T: Codec> Codec for Vec<T> {
112 fn encode(&self, out: &mut Vec<u8>) {
113 (self.len() as u32).encode(out);
114 for item in self {
115 item.encode(out);
116 }
117 }
118 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError> {
119 let (count, mut off) = u32::decode(input)?;
120 let mut v = Vec::with_capacity(count as usize);
121 for _ in 0..count {
122 let (item, read) = T::decode(&input[off..])?;
123 off += read;
124 v.push(item);
125 }
126 Ok((v, off))
127 }
128}
129impl<T: Codec> Codec for Option<T> {
130 fn encode(&self, out: &mut Vec<u8>) {
131 match self {
132 Some(v) => {
133 out.push(1);
134 v.encode(out);
135 }
136 None => out.push(0),
137 }
138 }
139 fn decode(input: &[u8]) -> Result<(Self, usize), CodecError> {
140 if input.is_empty() {
141 return Err(CodecError::Truncated);
142 }
143 if input[0] == 0 {
144 Ok((None, 1))
145 } else {
146 let (v, r) = T::decode(&input[1..])?;
147 Ok((Some(v), 1 + r))
148 }
149 }
150}
151
152pub fn build_header(op: OpCode, payload_len: u32) -> [u8; 12] {
153 let mut h = [0u8; 12];
154 h[0..4].copy_from_slice(&WIRE_MAGIC.to_le_bytes());
155 h[4..6].copy_from_slice(&WIRE_VERSION.to_le_bytes());
156 let op_u16 = op as u16;
157 h[6..8].copy_from_slice(&op_u16.to_le_bytes());
158 h[8..12].copy_from_slice(&payload_len.to_le_bytes());
159 h
160}
161
162pub fn parse_header(buf: &[u8]) -> Result<(OpCode, u32), CodecError> {
163 if buf.len() < 12 {
164 return Err(CodecError::InvalidHeader);
165 }
166 let magic = u32::from_le_bytes(buf[0..4].try_into().unwrap());
167 if magic != WIRE_MAGIC {
168 return Err(CodecError::WrongMagic);
169 }
170 let version = u16::from_le_bytes(buf[4..6].try_into().unwrap());
171 if version != WIRE_VERSION {
172 return Err(CodecError::WrongVersion);
173 }
174 let op = u16::from_le_bytes(buf[6..8].try_into().unwrap());
175 let payload_len = u32::from_le_bytes(buf[8..12].try_into().unwrap());
176 let op = match op {
177 1 => OpCode::EchoTyped,
178 2 => OpCode::ListProcessTyped,
179 _ => return Err(CodecError::InvalidHeader),
180 };
181 Ok((op, payload_len))
182}
183
184pub fn encode_frame_raw(op: OpCode, payload: &[u8]) -> Vec<u8> {
185 let header = build_header(op, payload.len() as u32);
186 let mut frame = Vec::with_capacity(12 + payload.len());
187 frame.extend_from_slice(&header);
188 frame.extend_from_slice(payload);
189 frame
190}
191
192pub fn decode_frame_raw<'a>(buf: &'a [u8]) -> Result<(OpCode, &'a [u8]), CodecError> {
193 let (op, payload_len) = parse_header(buf)?;
194 let total = 12usize + payload_len as usize;
195 if buf.len() < total {
196 return Err(CodecError::Truncated);
197 }
198 Ok((op, &buf[12..total]))
199}
200
201pub fn encode_typed<T: Codec>(v: &T) -> Vec<u8> {
202 let mut out = Vec::new();
203 v.encode(&mut out);
204 out
205}
206pub fn decode_typed<T: Codec>(buf: &[u8]) -> Result<(T, usize), CodecError> {
207 T::decode(buf)
208}
209pub fn encode_frame_typed<T: Codec>(op: OpCode, v: &T) -> Vec<u8> {
210 let payload = encode_typed(v);
211 encode_frame_raw(op, &payload)
212}
213pub fn decode_frame_typed<'a, T: Codec>(buf: &'a [u8]) -> Result<(OpCode, T), CodecError> {
214 let (op, payload) = decode_frame_raw(buf)?;
215 let (v, _) = decode_typed::<T>(payload)?;
216 Ok((op, v))
217}