jcm/message/
message_data.rs

1use std::{cmp, fmt, mem};
2
3use super::{Message, MAX_LEN};
4use crate::{Error, Result};
5
6mod conf_id;
7mod message_code;
8mod message_type;
9
10pub use conf_id::*;
11pub use message_code::*;
12pub use message_type::*;
13
14/// Maximum length of the [MessageData] when converted to bytes.
15pub const MAX_DATA_LEN: usize = MAX_LEN - MessageData::meta_len();
16
17/// Represents message data for JCM host-device communication.
18#[repr(C)]
19#[derive(Clone, Debug, Eq, PartialEq)]
20pub struct MessageData {
21    conf_id: ConfId,
22    uid: u8,
23    message_type: MessageType,
24    message_code: MessageCode,
25    additional: Vec<u8>,
26}
27
28impl MessageData {
29    /// Creates a new [MessageData].
30    pub const fn new() -> Self {
31        Self {
32            conf_id: ConfId::new(),
33            uid: 0,
34            message_type: MessageType::new(),
35            message_code: MessageCode::new(),
36            additional: Vec::new(),
37        }
38    }
39
40    /// Gets the [ConfId] of the [MessageData].
41    pub const fn conf_id(&self) -> ConfId {
42        self.conf_id
43    }
44
45    /// Sets the [ConfId] of the [MessageData].
46    pub fn set_conf_id(&mut self, val: ConfId) {
47        self.conf_id = val;
48    }
49
50    /// Builder function that sets the [ConfId] of the [MessageData].
51    pub fn with_conf_id(mut self, val: ConfId) -> Self {
52        self.set_conf_id(val);
53        self
54    }
55
56    /// Gets the UID of the [MessageData].
57    ///
58    /// - `0`: device powered on, and/or USB cable disconnected.
59    /// - `1-255`: device ID for disconnected device to send in a UID Request Message.
60    pub const fn uid(&self) -> u8 {
61        self.uid
62    }
63
64    /// Sets the UID of the [MessageData].
65    pub fn set_uid(&mut self, val: u8) {
66        self.uid = val;
67    }
68
69    /// Builder function that sets the UID of the [MessageData].
70    pub fn with_uid(mut self, val: u8) -> Self {
71        self.set_uid(val);
72        self
73    }
74
75    /// Gets the [MessageType] of the [MessageData].
76    pub const fn message_type(&self) -> MessageType {
77        self.message_type
78    }
79
80    /// Sets the [MessageType] of the [MessageData].
81    pub fn set_message_type(&mut self, val: MessageType) {
82        self.message_type = val;
83    }
84
85    /// Builder function that sets the [MessageType] of the [MessageData].
86    pub fn with_message_type(mut self, val: MessageType) -> Self {
87        self.set_message_type(val);
88        self
89    }
90
91    /// Gets the [MessageCode] of the [MessageData].
92    pub const fn message_code(&self) -> MessageCode {
93        self.message_code
94    }
95
96    /// Sets the [MessageCode] of the [MessageData].
97    pub fn set_message_code(&mut self, val: MessageCode) {
98        self.message_code = val;
99    }
100
101    /// Builder function that sets the [MessageCode] of the [MessageData].
102    pub fn with_message_code(mut self, val: MessageCode) -> Self {
103        self.set_message_code(val);
104        self
105    }
106
107    /// Gets a reference to the additional data of the [MessageData].
108    pub fn additional(&self) -> &[u8] {
109        &self.additional
110    }
111
112    /// Sets the additional data of the [MessageData].
113    pub fn set_additional(&mut self, additional: &[u8]) {
114        let len = cmp::min(additional.len(), MAX_DATA_LEN);
115        self.additional = additional[..len].into()
116    }
117
118    /// Builder function that sets the additional data of the [MessageData].
119    pub fn with_additional(mut self, additional: &[u8]) -> Self {
120        self.set_additional(additional);
121        self
122    }
123
124    /// Gets the length of the [MessageData].
125    pub fn len(&self) -> usize {
126        Self::meta_len() + self.additional.len()
127    }
128
129    pub(crate) const fn meta_len() -> usize {
130        ConfId::len() + mem::size_of::<u8>() + MessageType::len() + MessageCode::len()
131    }
132
133    /// Gets whether the [MessageData] is empty.
134    pub fn is_empty(&self) -> bool {
135        self.conf_id.is_empty()
136            || self.message_type.is_empty()
137            || self.message_code.is_empty()
138            || self.message_code.func_id().is_empty()
139            || self.additional.is_empty()
140    }
141
142    /// Writes the [MessageData] to the provided byte buffer.
143    pub fn to_bytes(&self, buf: &mut [u8]) -> Result<()> {
144        let len = self.len();
145        let buf_len = buf.len();
146
147        if buf_len < len {
148            Err(Error::InvalidMessageDataLen((buf_len, len)))
149        } else {
150            buf.iter_mut()
151                .take(len)
152                .zip(
153                    [self.conf_id.into(), self.uid, self.message_type.into()]
154                        .into_iter()
155                        .chain(self.message_code.to_bytes())
156                        .chain(self.additional.iter().cloned()),
157                )
158                .for_each(|(dst, src)| *dst = src);
159
160            Ok(())
161        }
162    }
163}
164
165impl From<&MessageData> for Vec<u8> {
166    fn from(val: &MessageData) -> Self {
167        [val.conf_id.into(), val.uid, val.message_type.into()]
168            .into_iter()
169            .chain(val.message_code.to_bytes())
170            .chain(val.additional.iter().cloned())
171            .collect()
172    }
173}
174
175impl From<MessageData> for Vec<u8> {
176    fn from(val: MessageData) -> Self {
177        [val.conf_id.into(), val.uid, val.message_type.into()]
178            .into_iter()
179            .chain(val.message_code.to_bytes())
180            .chain(val.additional)
181            .collect()
182    }
183}
184
185impl From<&MessageData> for Message {
186    fn from(val: &MessageData) -> Self {
187        Message::new().with_data(val.clone())
188    }
189}
190
191impl From<MessageData> for Message {
192    fn from(val: MessageData) -> Self {
193        Message::new().with_data(val)
194    }
195}
196
197impl TryFrom<&[u8]> for MessageData {
198    type Error = Error;
199
200    fn try_from(val: &[u8]) -> Result<Self> {
201        let len = val.len();
202        let meta_len = Self::meta_len();
203
204        if len < meta_len {
205            Err(Error::InvalidMessageDataLen((len, meta_len)))
206        } else if len > MAX_LEN {
207            Err(Error::InvalidMessageDataLen((len, MAX_LEN)))
208        } else {
209            let conf_id = ConfId::try_from(val[0])?;
210            let uid = val[1];
211            let message_type = MessageType::try_from(val[2])?;
212            let message_code = MessageCode::try_from(RawMessageCode::create(
213                message_type,
214                u16::from_le_bytes([val[3], val[4]]),
215            ))?;
216            let additional = val[5..].into();
217
218            Ok(Self {
219                conf_id,
220                uid,
221                message_type,
222                message_code,
223                additional,
224            })
225        }
226    }
227}
228
229impl Default for MessageData {
230    fn default() -> Self {
231        Self::new()
232    }
233}
234
235impl fmt::Display for MessageData {
236    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237        write!(f, "{{")?;
238        write!(f, r#""conf_id": {},"#, self.conf_id)?;
239        write!(f, r#""uid": {},"#, self.uid)?;
240        write!(f, r#""message_type": {},"#, self.message_type)?;
241        write!(f, r#""message_code": {},"#, self.message_code)?;
242        write!(f, r#""additional": ["#)?;
243        for (i, d) in self.additional.iter().enumerate() {
244            if i != 0 {
245                write!(f, ",")?;
246            }
247            write!(f, "{d}")?;
248        }
249        write!(f, "]}}")
250    }
251}
252
253#[cfg(test)]
254mod tests {
255    use super::*;
256
257    #[test]
258    #[rustfmt::skip]
259    fn test_message_data() -> Result<()> {
260        let raw: [u8; 5] = [
261            // conf ID
262            0x10,
263            // UID
264            0x00,
265            // message type
266            0x00,
267            // func ID + request/event code
268            0x01, 0x00,
269            // additional data (none)
270        ];
271
272        let exp = MessageData::new();
273        let msg = MessageData::try_from(raw.as_ref())?;
274
275        assert_eq!(msg, exp);
276
277        Ok(())
278    }
279
280    #[test]
281    #[rustfmt::skip]
282    fn test_message_data_with_additional() -> Result<()> {
283        let raw: [u8; 13] = [
284            // conf ID
285            0x10,
286            // UID
287            0x00,
288            // message type
289            0x00,
290            // func ID + request/event code
291            0x01, 0x00,
292            // additional data
293            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
294        ];
295
296        let exp = MessageData::new().with_additional(&raw[5..]);
297        let msg = MessageData::try_from(raw.as_ref())?;
298
299        assert_eq!(msg, exp);
300
301        Ok(())
302    }
303
304    #[test]
305    #[rustfmt::skip]
306    fn test_message_data_too_short() -> Result<()> {
307        let raw: [u8; 3] = [
308            // conf ID
309            0x10,
310            // UID
311            0x00,
312            // message type
313            0x00,
314        ];
315
316        assert!(MessageData::try_from(raw.as_ref()).is_err());
317
318        Ok(())
319    }
320
321    #[test]
322    #[rustfmt::skip]
323    fn test_message_data_too_long() -> Result<()> {
324        let raw: Vec<u8> = [
325            // conf ID
326            0x10,
327            // UID
328            0x00,
329            // message type
330            0x00,
331            // func ID + request/event code
332            0x01, 0x00,
333        ].into_iter().chain([0xff; MAX_LEN]).collect();
334
335        assert!(MessageData::try_from(raw.as_slice()).is_err());
336
337        Ok(())
338    }
339}