Skip to main content

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}