veecle_os_data_support_can/
frame.rs1use tinyvec::ArrayVec;
2
3use crate::id::{Id, PackedId};
4
5#[derive(Clone, Copy, serde::Serialize, serde::Deserialize)]
7pub struct Frame {
8 id: PackedId,
10 data: ArrayVec<[u8; 8]>,
11}
12
13mod sealed {
14 pub trait Sealed {}
18 impl Sealed for [u8; 0] {}
19 impl Sealed for [u8; 1] {}
20 impl Sealed for [u8; 2] {}
21 impl Sealed for [u8; 3] {}
22 impl Sealed for [u8; 4] {}
23 impl Sealed for [u8; 5] {}
24 impl Sealed for [u8; 6] {}
25 impl Sealed for [u8; 7] {}
26 impl Sealed for [u8; 8] {}
27}
28
29pub trait FrameSize: sealed::Sealed {}
31impl FrameSize for [u8; 0] {}
32impl FrameSize for [u8; 1] {}
33impl FrameSize for [u8; 2] {}
34impl FrameSize for [u8; 3] {}
35impl FrameSize for [u8; 4] {}
36impl FrameSize for [u8; 5] {}
37impl FrameSize for [u8; 6] {}
38impl FrameSize for [u8; 7] {}
39impl FrameSize for [u8; 8] {}
40
41impl Frame {
42 pub fn new<const N: usize>(id: impl Into<Id>, data: [u8; N]) -> Self
46 where
47 [u8; N]: FrameSize,
48 {
49 Self::new_checked(id, &data).expect("the const generic guarantees it's ok")
50 }
51
52 pub fn new_checked(id: impl Into<Id>, data: &[u8]) -> Option<Self> {
56 let id = PackedId::from(id.into());
57 let data = ArrayVec::try_from(data).ok()?;
58 Some(Self { id, data })
59 }
60
61 pub fn id(&self) -> Id {
63 self.id.into()
64 }
65
66 pub fn data(&self) -> &[u8] {
68 &self.data
69 }
70}
71
72impl Default for Frame {
73 fn default() -> Self {
74 Self::new(crate::StandardId::new(0).unwrap(), [])
75 }
76}
77
78impl veecle_os_runtime::Flatten for Frame {
79 fn flatten(&self, _buffer: &mut impl veecle_os_runtime::MetricBuffer) {}
80}
81
82impl veecle_os_runtime::Storable for Frame {
83 type DataType = Self;
84}
85
86impl core::fmt::Debug for Frame {
87 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
88 write!(f, "Frame {{ id: {:?}, data: '", self.id())?;
89 for byte in self.data() {
90 write!(f, "{byte:02x}")?;
91 }
92 f.write_str("' }")?;
93
94 Ok(())
95 }
96}
97
98#[cfg(test)]
99#[cfg_attr(coverage_nightly, coverage(off))]
100mod tests {
101 use crate::Frame;
102
103 #[test]
104 fn test_deserialize_frame_standard() {
105 let json = r#"{"id":{"Standard":291},"data":[1,2,3,4]}"#;
106 let frame: Frame = serde_json::from_str(json).unwrap();
107 assert_eq!(frame.id(), crate::StandardId::new(0x123).unwrap().into());
108 assert_eq!(frame.data(), &[1, 2, 3, 4]);
109 assert_eq!(json, serde_json::to_string(&frame).unwrap());
110 }
111
112 #[test]
113 fn test_deserialize_frame_extended() {
114 let json = r#"{"id":{"Extended":74565},"data":[1,2,3,4]}"#;
115 let frame: Frame = serde_json::from_str(json).unwrap();
116 assert_eq!(frame.id(), crate::ExtendedId::new(74565).unwrap().into());
117 assert_eq!(frame.data(), &[1, 2, 3, 4]);
118 assert_eq!(json, serde_json::to_string(&frame).unwrap());
119 }
120
121 #[test]
123 fn test_debug() {
124 fn to_debug(value: impl core::fmt::Debug) -> std::string::String {
125 std::format!("{value:?}")
126 }
127
128 assert_eq!(
129 to_debug(Frame::new(crate::StandardId::new(0).unwrap(), [])),
130 "Frame { id: Standard(0x0), data: '' }"
131 );
132
133 assert_eq!(
134 to_debug(Frame::new(
135 crate::ExtendedId::new(0x153EAB12).unwrap(),
136 [0x04, 0xA2, 0xC2, 0xED, 0xCA, 0xE3, 0x88, 0x74]
137 )),
138 "Frame { id: Extended(0x153eab12), data: '04a2c2edcae38874' }"
139 );
140
141 assert_eq!(
142 to_debug(Frame::new(
143 crate::ExtendedId::new(0x1B56C72D).unwrap(),
144 [0x40, 0x71, 0xEF, 0x61]
145 )),
146 "Frame { id: Extended(0x1b56c72d), data: '4071ef61' }"
147 );
148 }
149}