1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4pub mod buffer;
5pub mod de;
6mod macros;
7pub mod ser;
8
9use core::fmt::Display;
10
11use buffer::{SliceCursor, WriteBuffer};
12use serde::Deserialize;
13
14#[derive(Debug)]
15pub enum UcPackError {
17 BadVariant,
19 Eof,
21 NoSupport(&'static str),
24 TooLong,
27 BufferFull,
29 #[cfg(not(feature = "std"))]
31 SerError,
32 #[cfg(feature = "std")]
33 SerError(String),
34 #[cfg(not(feature = "std"))]
36 DeError,
37 #[cfg(feature = "std")]
38 DeError(String),
39 InvalidData,
43 WrongCrc,
45 WrongIndex,
47}
48
49impl Display for UcPackError {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 let msg = match self {
52 Self::NoSupport(typename) => {
53 return write!(f, "there's no support for type {typename}")
54 }
55 Self::Eof => "not enough data to deserialize",
56 Self::InvalidData => "invalid data for data type",
57 Self::BadVariant => "tried to serialize a variant index bigger than 255",
58 Self::TooLong => "tried to serialize more than 256 bytes",
59 Self::BufferFull => "tried to write but buffer reached capacity",
60
61 Self::WrongCrc => "crc verification failed",
62 Self::WrongIndex => "invalid start and/or stop indices",
63
64 #[cfg(not(feature = "std"))]
65 Self::SerError => "serde encountered an error serializing",
66 #[cfg(feature = "std")]
67 Self::SerError(err) => {
68 return write!(f, "serde encountered an error while serializing: {err}");
69 }
70
71 #[cfg(not(feature = "std"))]
72 Self::DeError => "serde encountered an error deserializing",
73 #[cfg(feature = "std")]
74 Self::DeError(err) => {
75 return write!(f, "serde encountered an error while deserializing: {err}");
76 }
77 };
78
79 f.write_str(msg)
80 }
81}
82
83#[cfg(feature = "std")]
84impl std::error::Error for UcPackError {}
85
86impl serde::ser::Error for UcPackError {
87 fn custom<T>(_msg: T) -> Self
88 where
89 T: Display,
90 {
91 #[cfg(not(feature = "std"))]
92 {
93 Self::SerError
94 }
95
96 #[cfg(feature = "std")]
97 {
98 Self::SerError(_msg.to_string())
99 }
100 }
101}
102
103impl serde::de::Error for UcPackError {
104 fn custom<T>(_msg: T) -> Self
105 where
106 T: Display,
107 {
108 #[cfg(not(feature = "std"))]
109 {
110 Self::DeError
111 }
112
113 #[cfg(feature = "std")]
114 {
115 Self::DeError(_msg.to_string())
116 }
117 }
118}
119pub struct UcPack {
123 start_index: u8,
124 end_index: u8,
125}
126
127impl Default for UcPack {
128 fn default() -> Self {
129 Self::new(b'A', b'#')
130 }
131}
132
133impl UcPack {
134 pub const fn new(start_index: u8, end_index: u8) -> Self {
135 Self {
136 start_index,
137 end_index,
138 }
139 }
140
141 #[cfg(feature = "std")]
142 pub fn serialize_vec(
143 &self,
144 payload: &impl serde::ser::Serialize,
145 ) -> Result<Vec<u8>, UcPackError> {
146 let mut buffer = vec![self.start_index, 0];
147
148 let mut serializer = ser::Serializer::new(&mut buffer);
149 payload.serialize(&mut serializer)?;
150
151 let data_end = buffer.len();
152 buffer[1] = u8::try_from(data_end - 2).map_err(|_| UcPackError::TooLong)?;
153
154 buffer.push(self.end_index);
155 buffer.push(crc8_slice(&buffer[2..data_end]));
156
157 Ok(buffer)
158 }
159
160 pub fn serialize_slice(
161 &self,
162 payload: &impl serde::ser::Serialize,
163 buffer: &mut [u8],
164 ) -> Result<usize, UcPackError> {
165 let mut cursor = SliceCursor::from_slice(&mut *buffer);
166 cursor.push_slice(&[self.start_index, 0])?; let mut serializer = ser::Serializer::new(&mut cursor);
169 payload.serialize(&mut serializer)?;
170
171 let data_end = cursor.index();
172 let crc = crc8_slice(&cursor.inner()[2..data_end]);
173 cursor.push_slice(&[self.end_index, crc])?;
174
175 let total_size = cursor.index();
176
177 buffer[1] = u8::try_from(data_end - 2).map_err(|_| UcPackError::TooLong)?;
178 Ok(total_size)
179 }
180
181 pub fn deserialize_slice<'d, 'b, T>(&self, buffer: &'b [u8]) -> Result<T, UcPackError>
182 where
183 T: Deserialize<'d>,
184 'b: 'd,
185 {
186 let packet = is_complete_message(buffer).ok_or(UcPackError::Eof)?;
187 let [index, _, payload @ .., end_index, crc] = packet else {
188 return Err(UcPackError::Eof);
189 };
190
191 if cfg!(feature = "strict") && (*index != self.start_index || *end_index != self.end_index)
192 {
193 return Err(UcPackError::WrongIndex);
194 }
195
196 let expected_crc = crc8_slice(payload);
197 if expected_crc != *crc {
198 return Err(UcPackError::WrongCrc);
199 }
200
201 let mut cursor = SliceCursor::from_slice(payload);
202 let mut de = de::Deserializer::new(&mut cursor);
203 T::deserialize(&mut de)
204 }
205}
206
207pub fn is_complete_message(buffer: &[u8]) -> Option<&[u8]> {
218 let length: usize = buffer.get(1).map(|&length| length.into())?;
219 buffer.get(..(length + 4))
220}
221
222#[inline]
224pub fn crc8_slice(input: &[u8]) -> u8 {
225 crc8(input.into_iter().copied())
226}
227
228pub fn crc8(input: impl IntoIterator<Item = u8>) -> u8 {
230 let input = input.into_iter();
231
232 input
233 .into_iter()
234 .flat_map(|byte| (0u8..8u8).map(move |j| (byte, j)))
235 .fold(0, |mut crc, (byte, j)| {
236 let sum = (crc ^ (byte >> j)) & 0x01;
237 crc >>= 1;
238 crc ^ (sum != 0).then_some(0x8C).unwrap_or(0) })
240}