1use alloc::vec::Vec;
4use core::fmt;
5use core::ops::Range;
6
7pub const MESSAGE_MAGIC: u32 = 0x4e49_5043;
9pub const VERSION_MAJOR: u16 = 1;
11pub const VERSION_MINOR: u16 = 0;
13pub const ENVELOPE_LEN: usize = 72;
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub struct Limits {
19 pub max_message_bytes: u32,
21 pub max_payload_bytes: u32,
23 pub max_records: u32,
25 pub max_allocation_bytes: u32,
27}
28
29pub struct DecodeContext<'a> {
31 limits: &'a Limits,
32 records_remaining: u32,
33 allocation_remaining: u32,
34}
35
36impl<'a> DecodeContext<'a> {
37 fn new(limits: &'a Limits) -> Self {
38 Self {
39 limits,
40 records_remaining: limits.max_records,
41 allocation_remaining: limits.max_allocation_bytes,
42 }
43 }
44
45 pub const fn limits(&self) -> &Limits {
47 self.limits
48 }
49
50 pub fn claim_records(&mut self, count: u32) -> Result<(), DecodeError> {
52 self.records_remaining = self
53 .records_remaining
54 .checked_sub(count)
55 .ok_or(DecodeError::LimitExceeded(LimitKind::Records))?;
56 Ok(())
57 }
58
59 pub fn claim_allocation(&mut self, bytes: u32) -> Result<(), DecodeError> {
61 self.allocation_remaining = self
62 .allocation_remaining
63 .checked_sub(bytes)
64 .ok_or(DecodeError::LimitExceeded(LimitKind::AllocationBytes))?;
65 Ok(())
66 }
67
68 pub fn copy_bytes(&mut self, source: &[u8]) -> Result<Vec<u8>, DecodeError> {
70 let len = u32::try_from(source.len()).map_err(|_| DecodeError::LengthOverflow)?;
71 self.claim_allocation(len)?;
72 Ok(source.to_vec())
73 }
74}
75
76impl Limits {
77 pub const fn new(
79 max_message_bytes: u32,
80 max_payload_bytes: u32,
81 max_records: u32,
82 max_allocation_bytes: u32,
83 ) -> Self {
84 Self {
85 max_message_bytes,
86 max_payload_bytes,
87 max_records,
88 max_allocation_bytes,
89 }
90 }
91}
92
93#[derive(Clone, Copy, Debug, Eq, PartialEq)]
95pub struct Envelope {
96 pub kind: u32,
98 pub flags: u32,
100 pub generation: u64,
102 pub sequence: u64,
104 payload_len: u32,
105}
106
107impl Envelope {
108 pub const fn new(kind: u32, flags: u32, generation: u64, sequence: u64) -> Self {
110 Self {
111 kind,
112 flags,
113 generation,
114 sequence,
115 payload_len: 0,
116 }
117 }
118
119 pub const fn payload_len(self) -> u32 {
121 self.payload_len
122 }
123
124 pub fn total_len(self) -> Result<usize, EncodeError> {
126 ENVELOPE_LEN
127 .checked_add(self.payload_len as usize)
128 .ok_or(EncodeError::LengthOverflow)
129 }
130
131 fn with_payload_len(mut self, payload_len: usize) -> Result<Self, EncodeError> {
132 self.payload_len = u32::try_from(payload_len).map_err(|_| EncodeError::LengthOverflow)?;
133 Ok(self)
134 }
135}
136
137#[derive(Clone, Debug, Eq, PartialEq)]
139pub struct DecodedMessage<T> {
140 pub envelope: Envelope,
142 pub message: T,
144}
145
146pub trait Protocol {
152 type Message;
154
155 const SCHEMA_ID: [u8; 32];
157
158 fn encode_payload(
160 message: &Self::Message,
161 destination: &mut [u8],
162 ) -> Result<usize, EncodeError>;
163
164 fn decode_payload(
166 source: &[u8],
167 context: &mut DecodeContext<'_>,
168 ) -> Result<Self::Message, DecodeError>;
169}
170
171pub fn encode_message<P: Protocol>(
173 envelope: Envelope,
174 message: &P::Message,
175 destination: &mut [u8],
176) -> Result<usize, EncodeError> {
177 if envelope.generation == 0 {
178 return Err(EncodeError::ZeroGeneration);
179 }
180 if envelope.sequence == 0 {
181 return Err(EncodeError::ZeroSequence);
182 }
183 if destination.len() < ENVELOPE_LEN {
184 return Err(EncodeError::DestinationTooSmall {
185 required: ENVELOPE_LEN,
186 actual: destination.len(),
187 });
188 }
189
190 let payload_len = P::encode_payload(message, &mut destination[ENVELOPE_LEN..])?;
191 let envelope = envelope.with_payload_len(payload_len)?;
192 let total_len = envelope.total_len()?;
193 if total_len > destination.len() {
194 return Err(EncodeError::DestinationTooSmall {
195 required: total_len,
196 actual: destination.len(),
197 });
198 }
199 encode_envelope::<P>(envelope, &mut destination[..ENVELOPE_LEN]);
200 Ok(total_len)
201}
202
203pub fn decode_message<P: Protocol>(
205 source: &[u8],
206 limits: &Limits,
207) -> Result<DecodedMessage<P::Message>, DecodeError> {
208 if source.len() < ENVELOPE_LEN {
209 return Err(DecodeError::Truncated {
210 required: ENVELOPE_LEN,
211 actual: source.len(),
212 });
213 }
214 if source.len() > limits.max_message_bytes as usize {
215 return Err(DecodeError::LimitExceeded(LimitKind::MessageBytes));
216 }
217 let envelope = decode_envelope::<P>(&source[..ENVELOPE_LEN])?;
218 let payload_len = envelope.payload_len as usize;
219 if payload_len > limits.max_payload_bytes as usize {
220 return Err(DecodeError::LimitExceeded(LimitKind::PayloadBytes));
221 }
222 let total_len = ENVELOPE_LEN
223 .checked_add(payload_len)
224 .ok_or(DecodeError::LengthOverflow)?;
225 if total_len != source.len() {
226 return Err(DecodeError::NonCanonicalLength {
227 declared: total_len,
228 actual: source.len(),
229 });
230 }
231 let mut context = DecodeContext::new(limits);
232 let message = P::decode_payload(&source[ENVELOPE_LEN..], &mut context)?;
233 Ok(DecodedMessage { envelope, message })
234}
235
236#[derive(Clone, Debug, Eq, PartialEq)]
238pub struct RelativeRange(Range<usize>);
239
240impl RelativeRange {
241 pub fn new(offset: u32, len: u32, containing_len: usize) -> Result<Self, DecodeError> {
243 let start = offset as usize;
244 let end = start
245 .checked_add(len as usize)
246 .ok_or(DecodeError::LengthOverflow)?;
247 if end > containing_len {
248 return Err(DecodeError::RelativeRangeOutOfBounds {
249 offset,
250 len,
251 containing_len,
252 });
253 }
254 Ok(Self(start..end))
255 }
256
257 pub fn range(&self) -> Range<usize> {
259 self.0.clone()
260 }
261}
262
263#[derive(Clone, Copy, Debug, Eq, PartialEq)]
265pub enum EncodeError {
266 DestinationTooSmall {
268 required: usize,
270 actual: usize,
272 },
273 LengthOverflow,
275 ZeroGeneration,
277 ZeroSequence,
279 Protocol(u16),
281}
282
283#[derive(Clone, Copy, Debug, Eq, PartialEq)]
285pub enum LimitKind {
286 MessageBytes,
288 PayloadBytes,
290 Records,
292 AllocationBytes,
294}
295
296#[derive(Clone, Copy, Debug, Eq, PartialEq)]
298pub enum DecodeError {
299 Truncated {
301 required: usize,
303 actual: usize,
305 },
306 BadMagic(u32),
308 BadVersion {
310 major: u16,
312 minor: u16,
314 },
315 SchemaMismatch,
317 ZeroGeneration,
319 ZeroSequence,
321 NonCanonicalLength {
323 declared: usize,
325 actual: usize,
327 },
328 LengthOverflow,
330 RelativeRangeOutOfBounds {
332 offset: u32,
334 len: u32,
336 containing_len: usize,
338 },
339 LimitExceeded(LimitKind),
341 Protocol(u16),
343}
344
345impl fmt::Display for EncodeError {
346 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
347 write!(formatter, "message encoding failed: {self:?}")
348 }
349}
350
351impl fmt::Display for DecodeError {
352 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
353 write!(formatter, "message decoding failed: {self:?}")
354 }
355}
356
357#[cfg(feature = "std")]
358impl std::error::Error for EncodeError {}
359#[cfg(feature = "std")]
360impl std::error::Error for DecodeError {}
361
362fn encode_envelope<P: Protocol>(envelope: Envelope, bytes: &mut [u8]) {
363 put_u32(bytes, 0, MESSAGE_MAGIC);
364 put_u16(bytes, 4, VERSION_MAJOR);
365 put_u16(bytes, 6, VERSION_MINOR);
366 put_u32(bytes, 8, envelope.kind);
367 put_u32(bytes, 12, envelope.flags);
368 put_u32(bytes, 16, envelope.payload_len);
369 put_u32(bytes, 20, ENVELOPE_LEN as u32);
370 put_u64(bytes, 24, envelope.generation);
371 put_u64(bytes, 32, envelope.sequence);
372 bytes[40..72].copy_from_slice(&P::SCHEMA_ID);
373}
374
375fn decode_envelope<P: Protocol>(bytes: &[u8]) -> Result<Envelope, DecodeError> {
376 let magic = get_u32(bytes, 0);
377 if magic != MESSAGE_MAGIC {
378 return Err(DecodeError::BadMagic(magic));
379 }
380 let major = get_u16(bytes, 4);
381 let minor = get_u16(bytes, 6);
382 if major != VERSION_MAJOR || minor != VERSION_MINOR {
383 return Err(DecodeError::BadVersion { major, minor });
384 }
385 let header_len = get_u32(bytes, 20);
386 if header_len != ENVELOPE_LEN as u32 {
387 return Err(DecodeError::NonCanonicalLength {
388 declared: header_len as usize,
389 actual: ENVELOPE_LEN,
390 });
391 }
392 if bytes[40..72] != P::SCHEMA_ID {
393 return Err(DecodeError::SchemaMismatch);
394 }
395 let generation = get_u64(bytes, 24);
396 if generation == 0 {
397 return Err(DecodeError::ZeroGeneration);
398 }
399 let sequence = get_u64(bytes, 32);
400 if sequence == 0 {
401 return Err(DecodeError::ZeroSequence);
402 }
403 Ok(Envelope {
404 kind: get_u32(bytes, 8),
405 flags: get_u32(bytes, 12),
406 generation,
407 sequence,
408 payload_len: get_u32(bytes, 16),
409 })
410}
411
412fn put_u16(bytes: &mut [u8], offset: usize, value: u16) {
413 bytes[offset..offset + 2].copy_from_slice(&value.to_le_bytes());
414}
415
416fn put_u32(bytes: &mut [u8], offset: usize, value: u32) {
417 bytes[offset..offset + 4].copy_from_slice(&value.to_le_bytes());
418}
419
420fn put_u64(bytes: &mut [u8], offset: usize, value: u64) {
421 bytes[offset..offset + 8].copy_from_slice(&value.to_le_bytes());
422}
423
424fn get_u16(bytes: &[u8], offset: usize) -> u16 {
425 u16::from_le_bytes(
426 bytes[offset..offset + 2]
427 .try_into()
428 .expect("fixed checked range"),
429 )
430}
431
432fn get_u32(bytes: &[u8], offset: usize) -> u32 {
433 u32::from_le_bytes(
434 bytes[offset..offset + 4]
435 .try_into()
436 .expect("fixed checked range"),
437 )
438}
439
440fn get_u64(bytes: &[u8], offset: usize) -> u64 {
441 u64::from_le_bytes(
442 bytes[offset..offset + 8]
443 .try_into()
444 .expect("fixed checked range"),
445 )
446}
447
448#[cfg(test)]
449#[path = "codec_test.rs"]
450mod tests;