rm_frame/marshaler.rs
1//! Defines the [`Marshaler`] trait and related traits for payload serialization and deserialization.
2
3use crate::MarshalerError;
4
5type Result<T> = core::result::Result<T, MarshalerError>;
6
7///
8/// Payload marshaling interface.
9///
10/// [`Marshaler`] defines how a message payload is:
11/// - Serialized into raw bytes ([`Marshaler::marshal`])
12/// - Deserialized from raw bytes ([`Marshaler::unmarshal`])
13///
14/// Each payload type corresponds to exactly one command ID.
15///
16#[doc(alias("Marshal", "Unmarshal", "Serialize", "Deserialize"))]
17pub trait Marshaler: Sized {
18 /// Command ID associated with this payload type.
19 const CMD_ID: u16;
20 /// Expected size of the payload in bytes.
21 const PAYLOAD_SIZE: u16;
22
23 ///
24 /// Serialize the payload into the destination buffer.
25 ///
26 /// Returns the number of bytes written on success.
27 ///
28 /// # Notes
29 ///
30 /// If called manually, the caller must ensure
31 /// that the destination buffer is large enough
32 /// to hold the serialized payload.
33 ///
34 /// # Errors
35 ///
36 /// Returns an error if the destination buffer
37 /// is too small or the payload cannot be encoded.
38 ///
39 fn marshal(&self, dst: &mut [u8]) -> Result<usize>;
40
41 ///
42 /// Deserialize a payload from raw bytes.
43 ///
44 /// The input slice contains only the payload portion
45 /// (no header, command ID, or CRC).
46 ///
47 /// Implementations must not depend on framing details.
48 ///
49 /// # Errors
50 ///
51 /// Returns an error if the data is invalid
52 /// or does not match the expected payload format.
53 ///
54 fn unmarshal(raw: &[u8]) -> Result<Self>;
55}
56
57/// Provides the command ID and payload size constants for a message type.
58///
59/// This trait is a sub-trait of [`Marshaler`] and is automatically implemented
60/// for any type that implements [`Marshaler`]. It can also be implemented
61/// directly when only the metadata constants are needed.
62pub trait ImplCommandMsg: Sized {
63 /// See [`Marshaler::CMD_ID`] for details.
64 const CMD_ID: u16;
65 /// See [`Marshaler::PAYLOAD_SIZE`] for details.
66 const PAYLOAD_SIZE: u16;
67}
68
69impl<T: Marshaler> ImplCommandMsg for T {
70 const CMD_ID: u16 = T::CMD_ID;
71 const PAYLOAD_SIZE: u16 = T::PAYLOAD_SIZE;
72}
73
74/// Payload serialization half of [`Marshaler`].
75///
76/// Automatically implemented for any type that implements [`Marshaler`].
77/// Implement this trait directly — without implementing [`Marshaler`] —
78/// to create an encode-only type that does not support deserialization.
79///
80/// Used as the bound on [`Messager::pack`](crate::Messager::pack).
81pub trait ImplMarshal: ImplCommandMsg {
82 /// See [`Marshaler::marshal`] for details.
83 fn marshal(&self, dst: &mut [u8]) -> Result<usize>;
84}
85
86impl<T: Marshaler> ImplMarshal for T {
87 fn marshal(&self, dst: &mut [u8]) -> Result<usize> {
88 T::marshal(self, dst)
89 }
90}
91
92/// Payload deserialization half of [`Marshaler`].
93///
94/// Automatically implemented for any type that implements [`Marshaler`].
95/// Implement this trait directly — without implementing [`Marshaler`] —
96/// to create a decode-only type that does not support serialization.
97///
98/// Used as the bound on [`Messager::unmarshal`](crate::Messager::unmarshal) and [`RawFrame::unmarshal`](crate::RawFrame::unmarshal).
99pub trait ImplUnMarshal: ImplCommandMsg {
100 /// See [`Marshaler::unmarshal`] for details.
101 fn unmarshal(raw: &[u8]) -> Result<Self>;
102}
103
104impl<T: Marshaler> ImplUnMarshal for T {
105 fn unmarshal(raw: &[u8]) -> Result<Self> {
106 T::unmarshal(raw)
107 }
108}