Skip to main content

lxmf_embedded_mini/
wire.rs

1use heapless::Vec;
2
3use crate::{MiniError, MiniResult};
4
5pub const HASH_LENGTH: usize = 16;
6pub const SIGNATURE_LENGTH: usize = 64;
7pub const WIRE_HEADER_LENGTH: usize = HASH_LENGTH + HASH_LENGTH + SIGNATURE_LENGTH;
8
9const MSGPACK_ARRAY_4: u8 = 0x94;
10const MSGPACK_ARRAY_5: u8 = 0x95;
11const MSGPACK_NIL: u8 = 0xc0;
12const MSGPACK_F64: u8 = 0xcb;
13const MSGPACK_BIN8: u8 = 0xc4;
14const MSGPACK_BIN16: u8 = 0xc5;
15const MSGPACK_BIN32: u8 = 0xc6;
16const MSGPACK_STR8: u8 = 0xd9;
17const MSGPACK_STR16: u8 = 0xda;
18const MSGPACK_STR32: u8 = 0xdb;
19
20#[derive(Debug, Clone, Eq, PartialEq)]
21pub struct MiniMessage<const TITLE: usize, const CONTENT: usize> {
22    pub destination: [u8; HASH_LENGTH],
23    pub source: [u8; HASH_LENGTH],
24    pub signature: [u8; SIGNATURE_LENGTH],
25    pub timestamp: u64,
26    pub title: Vec<u8, TITLE>,
27    pub content: Vec<u8, CONTENT>,
28}
29
30impl<const TITLE: usize, const CONTENT: usize> MiniMessage<TITLE, CONTENT> {
31    pub fn new(
32        destination: [u8; HASH_LENGTH],
33        source: [u8; HASH_LENGTH],
34        signature: [u8; SIGNATURE_LENGTH],
35        timestamp: f64,
36        title: &[u8],
37        content: &[u8],
38    ) -> MiniResult<Self> {
39        if destination == [0; HASH_LENGTH] || source == [0; HASH_LENGTH] {
40            return Err(MiniError::InvalidInput);
41        }
42        let mut title_buf = Vec::new();
43        title_buf.extend_from_slice(title).map_err(|_| MiniError::CapacityExceeded)?;
44        let mut content_buf = Vec::new();
45        content_buf.extend_from_slice(content).map_err(|_| MiniError::CapacityExceeded)?;
46        Ok(Self {
47            destination,
48            source,
49            signature,
50            timestamp: timestamp.to_bits(),
51            title: title_buf,
52            content: content_buf,
53        })
54    }
55
56    pub fn timestamp(&self) -> f64 {
57        f64::from_bits(self.timestamp)
58    }
59
60    pub fn encoded_len(&self) -> MiniResult<usize> {
61        Ok(WIRE_HEADER_LENGTH
62            + 1
63            + 9
64            + bin_encoded_len(self.title.len())?
65            + bin_encoded_len(self.content.len())?
66            + 1)
67    }
68
69    pub fn encode(&self, out: &mut [u8]) -> MiniResult<usize> {
70        let needed = self.encoded_len()?;
71        if out.len() < needed {
72            return Err(MiniError::BufferTooSmall);
73        }
74
75        let mut idx = 0;
76        write_bytes(out, &mut idx, &self.destination)?;
77        write_bytes(out, &mut idx, &self.source)?;
78        write_bytes(out, &mut idx, &self.signature)?;
79        write_u8(out, &mut idx, MSGPACK_ARRAY_4)?;
80        write_u8(out, &mut idx, MSGPACK_F64)?;
81        write_bytes(out, &mut idx, &self.timestamp.to_be_bytes())?;
82        write_bin(out, &mut idx, &self.title)?;
83        write_bin(out, &mut idx, &self.content)?;
84        write_u8(out, &mut idx, MSGPACK_NIL)?;
85        Ok(idx)
86    }
87
88    pub fn decode(bytes: &[u8]) -> MiniResult<Self> {
89        if bytes.len() < WIRE_HEADER_LENGTH {
90            return Err(MiniError::InvalidWire);
91        }
92
93        let mut destination = [0u8; HASH_LENGTH];
94        let mut source = [0u8; HASH_LENGTH];
95        let mut signature = [0u8; SIGNATURE_LENGTH];
96        destination.copy_from_slice(&bytes[0..HASH_LENGTH]);
97        source.copy_from_slice(&bytes[HASH_LENGTH..HASH_LENGTH * 2]);
98        signature.copy_from_slice(&bytes[HASH_LENGTH * 2..WIRE_HEADER_LENGTH]);
99
100        let mut cursor = WIRE_HEADER_LENGTH;
101        let array_len = read_u8(bytes, &mut cursor)?;
102        if array_len == MSGPACK_ARRAY_5 {
103            return Err(MiniError::Unsupported);
104        }
105        if array_len != MSGPACK_ARRAY_4 {
106            return Err(MiniError::InvalidWire);
107        }
108        if read_u8(bytes, &mut cursor)? != MSGPACK_F64 {
109            return Err(MiniError::InvalidWire);
110        }
111        let timestamp = read_u64_be(bytes, &mut cursor)?;
112        let title_slice = read_bin_or_str(bytes, &mut cursor)?;
113        let content_slice = read_bin_or_str(bytes, &mut cursor)?;
114        if read_u8(bytes, &mut cursor)? != MSGPACK_NIL || cursor != bytes.len() {
115            return Err(MiniError::InvalidWire);
116        }
117
118        let mut title = Vec::new();
119        title.extend_from_slice(title_slice).map_err(|_| MiniError::CapacityExceeded)?;
120        let mut content = Vec::new();
121        content.extend_from_slice(content_slice).map_err(|_| MiniError::CapacityExceeded)?;
122        Ok(Self { destination, source, signature, timestamp, title, content })
123    }
124}
125
126fn bin_encoded_len(len: usize) -> MiniResult<usize> {
127    if len <= u8::MAX as usize {
128        Ok(2 + len)
129    } else if len <= u16::MAX as usize {
130        Ok(3 + len)
131    } else if len <= u32::MAX as usize {
132        Ok(5 + len)
133    } else {
134        Err(MiniError::InvalidInput)
135    }
136}
137
138fn write_u8(out: &mut [u8], idx: &mut usize, value: u8) -> MiniResult<()> {
139    if *idx >= out.len() {
140        return Err(MiniError::BufferTooSmall);
141    }
142    out[*idx] = value;
143    *idx += 1;
144    Ok(())
145}
146
147fn write_bytes(out: &mut [u8], idx: &mut usize, bytes: &[u8]) -> MiniResult<()> {
148    let end = idx.checked_add(bytes.len()).ok_or(MiniError::BufferTooSmall)?;
149    if end > out.len() {
150        return Err(MiniError::BufferTooSmall);
151    }
152    out[*idx..end].copy_from_slice(bytes);
153    *idx = end;
154    Ok(())
155}
156
157fn write_bin(out: &mut [u8], idx: &mut usize, bytes: &[u8]) -> MiniResult<()> {
158    if bytes.len() <= u8::MAX as usize {
159        write_u8(out, idx, MSGPACK_BIN8)?;
160        write_u8(out, idx, bytes.len() as u8)?;
161    } else if bytes.len() <= u16::MAX as usize {
162        write_u8(out, idx, MSGPACK_BIN16)?;
163        write_bytes(out, idx, &(bytes.len() as u16).to_be_bytes())?;
164    } else if bytes.len() <= u32::MAX as usize {
165        write_u8(out, idx, MSGPACK_BIN32)?;
166        write_bytes(out, idx, &(bytes.len() as u32).to_be_bytes())?;
167    } else {
168        return Err(MiniError::InvalidInput);
169    }
170    write_bytes(out, idx, bytes)
171}
172
173fn read_u8(bytes: &[u8], cursor: &mut usize) -> MiniResult<u8> {
174    let value = *bytes.get(*cursor).ok_or(MiniError::InvalidWire)?;
175    *cursor += 1;
176    Ok(value)
177}
178
179fn read_u64_be(bytes: &[u8], cursor: &mut usize) -> MiniResult<u64> {
180    let end = cursor.checked_add(8).ok_or(MiniError::InvalidWire)?;
181    let raw = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
182    let mut out = [0u8; 8];
183    out.copy_from_slice(raw);
184    *cursor = end;
185    Ok(u64::from_be_bytes(out))
186}
187
188fn read_len(bytes: &[u8], cursor: &mut usize, marker: u8) -> MiniResult<usize> {
189    match marker {
190        MSGPACK_BIN8 | MSGPACK_STR8 => Ok(read_u8(bytes, cursor)? as usize),
191        MSGPACK_BIN16 | MSGPACK_STR16 => {
192            let end = cursor.checked_add(2).ok_or(MiniError::InvalidWire)?;
193            let raw = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
194            *cursor = end;
195            Ok(u16::from_be_bytes([raw[0], raw[1]]) as usize)
196        }
197        MSGPACK_BIN32 | MSGPACK_STR32 => {
198            let end = cursor.checked_add(4).ok_or(MiniError::InvalidWire)?;
199            let raw = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
200            *cursor = end;
201            Ok(u32::from_be_bytes([raw[0], raw[1], raw[2], raw[3]]) as usize)
202        }
203        0xa0..=0xbf => Ok((marker & 0x1f) as usize),
204        _ => Err(MiniError::InvalidWire),
205    }
206}
207
208fn read_bin_or_str<'a>(bytes: &'a [u8], cursor: &mut usize) -> MiniResult<&'a [u8]> {
209    let marker = read_u8(bytes, cursor)?;
210    let len = read_len(bytes, cursor, marker)?;
211    let end = cursor.checked_add(len).ok_or(MiniError::InvalidWire)?;
212    let out = bytes.get(*cursor..end).ok_or(MiniError::InvalidWire)?;
213    *cursor = end;
214    Ok(out)
215}