1#![cfg_attr(not(feature = "std"), no_std)]
53#![forbid(unsafe_code)]
54#![warn(missing_docs)]
55
56#[cfg(feature = "alloc")]
57extern crate alloc;
58
59pub mod decode;
61pub mod encode;
63pub mod error;
65pub mod format;
67pub mod helpers;
69mod impls;
70#[cfg(feature = "primitives")]
72pub mod primitives;
73
74pub use decode::{CanonicalDecode, DecodeSource, SliceReader};
75pub use encode::{CanonicalEncode, EncodeSink};
76pub use error::{CodecError, CodecErrorKind};
77pub use helpers::{decode_from_slice, decode_from_slice_exact};
78
79#[cfg(feature = "alloc")]
80pub use helpers::encode_to_vec;
81
82#[cfg(all(test, feature = "alloc"))]
83mod tests {
84 use super::*;
85 use alloc::string::{String, ToString};
86 use alloc::vec;
87 use alloc::vec::Vec;
88 use core::fmt::Write as _;
89
90 #[derive(Debug, PartialEq, Eq)]
91 struct Message {
92 id: u32,
93 body: String,
94 urgent: bool,
95 }
96
97 impl CanonicalEncode for Message {
98 fn encode<W: EncodeSink + ?Sized>(&self, writer: &mut W) -> Result<(), CodecError> {
99 self.id.encode(writer)?;
100 self.body.encode(writer)?;
101 self.urgent.encode(writer)
102 }
103 }
104
105 impl CanonicalDecode for Message {
106 fn decode<R: DecodeSource + ?Sized>(reader: &mut R) -> Result<Self, CodecError> {
107 Ok(Self {
108 id: u32::decode(reader)?,
109 body: String::decode(reader)?,
110 urgent: bool::decode(reader)?,
111 })
112 }
113 }
114
115 #[test]
116 fn primitive_roundtrips_are_little_endian() {
117 assert_eq!(encode_to_vec(&0x1234u16).unwrap(), vec![0x34, 0x12]);
118 assert_eq!(
119 decode_from_slice_exact::<u16>(&[0x34, 0x12]).unwrap(),
120 0x1234
121 );
122 assert_eq!(encode_to_vec(&-2i16).unwrap(), (-2i16).to_le_bytes());
123 }
124
125 #[test]
126 fn integer_widths_roundtrip() {
127 macro_rules! assert_integer {
128 ($ty:ty, $value:expr) => {
129 let value = $value as $ty;
130 let encoded = encode_to_vec(&value).unwrap();
131 assert_eq!(encoded, value.to_le_bytes());
132 assert_eq!(decode_from_slice_exact::<$ty>(&encoded).unwrap(), value);
133 };
134 }
135
136 assert_integer!(u8, 200);
137 assert_integer!(i8, -12);
138 assert_integer!(u16, 0x1234);
139 assert_integer!(i16, -1234);
140 assert_integer!(u32, 0x1234_5678);
141 assert_integer!(i32, -123_456);
142 assert_integer!(u64, 0x1234_5678_9abc_def0);
143 assert_integer!(i64, -123_456_789);
144 assert_integer!(u128, 0x1234_5678_9abc_def0_1111_2222_3333_4444);
145 assert_integer!(i128, -123_456_789_123_456_789);
146 }
147
148 #[test]
149 fn bool_decode_is_strict() {
150 assert!(!decode_from_slice_exact::<bool>(&[0x00]).unwrap());
151 assert!(decode_from_slice_exact::<bool>(&[0x01]).unwrap());
152 let err = decode_from_slice_exact::<bool>(&[0x02]).unwrap_err();
153 assert_eq!(err.kind(), CodecErrorKind::InvalidValue);
154 }
155
156 #[test]
157 fn string_rejects_invalid_utf8() {
158 let err = decode_from_slice_exact::<String>(&[1, 0, 0, 0, 0xff]).unwrap_err();
159 assert_eq!(err.kind(), CodecErrorKind::InvalidValue);
160 }
161
162 #[test]
163 fn string_rejects_impossible_length_before_allocating() {
164 let err = decode_from_slice_exact::<String>(&u32::MAX.to_le_bytes()).unwrap_err();
165 assert_eq!(err.kind(), CodecErrorKind::UnexpectedEof);
166 }
167
168 #[test]
169 fn length_prefix_controls_string_bytes() {
170 assert_eq!(
171 encode_to_vec("abc").unwrap(),
172 vec![3, 0, 0, 0, b'a', b'b', b'c']
173 );
174 assert_eq!(
175 decode_from_slice_exact::<String>(&[3, 0, 0, 0, b'a', b'b', b'c']).unwrap(),
176 "abc"
177 );
178 }
179
180 #[test]
181 fn exact_decode_rejects_trailing_bytes() {
182 let err = decode_from_slice_exact::<u8>(&[1, 2]).unwrap_err();
183 assert_eq!(err.kind(), CodecErrorKind::TrailingBytes);
184 assert_eq!(decode_from_slice::<u8>(&[1, 2]).unwrap(), (1, 1));
185 }
186
187 #[test]
188 fn slice_reader_reports_remaining_and_eof() {
189 let mut reader = SliceReader::new(&[1, 2]);
190 assert!(!reader.is_empty());
191
192 let mut one = [0u8; 1];
193 reader.read_exact(&mut one).unwrap();
194 assert_eq!(one, [1]);
195 assert_eq!(reader.remaining(), 1);
196
197 let mut two = [0u8; 2];
198 let err = reader.read_exact(&mut two).unwrap_err();
199 assert_eq!(err.kind(), CodecErrorKind::UnexpectedEof);
200 }
201
202 #[test]
203 fn manual_struct_roundtrip() {
204 let message = Message {
205 id: 7,
206 body: String::from("ready"),
207 urgent: true,
208 };
209 let encoded = encode_to_vec(&message).unwrap();
210 assert_eq!(
211 decode_from_slice_exact::<Message>(&encoded).unwrap(),
212 message
213 );
214 }
215
216 #[test]
217 fn invalid_tags_fail() {
218 assert_eq!(
219 decode_from_slice_exact::<Option<u8>>(&[3])
220 .unwrap_err()
221 .kind(),
222 CodecErrorKind::InvalidValue
223 );
224 assert_eq!(
225 decode_from_slice_exact::<Result<u8, u8>>(&[3])
226 .unwrap_err()
227 .kind(),
228 CodecErrorKind::InvalidValue
229 );
230 }
231
232 #[test]
233 fn option_and_result_encode_all_branches() {
234 let none: Option<u16> = None;
235 assert_eq!(encode_to_vec(&none).unwrap(), vec![0]);
236 assert_eq!(decode_from_slice_exact::<Option<u16>>(&[0]).unwrap(), None);
237
238 let some = Some(0x1234u16);
239 assert_eq!(encode_to_vec(&some).unwrap(), vec![1, 0x34, 0x12]);
240 assert_eq!(
241 decode_from_slice_exact::<Option<u16>>(&[1, 0x34, 0x12]).unwrap(),
242 some
243 );
244
245 let ok: Result<u8, u16> = Ok(9);
246 assert_eq!(encode_to_vec(&ok).unwrap(), vec![0, 9]);
247 assert_eq!(
248 decode_from_slice_exact::<Result<u8, u16>>(&[0, 9]).unwrap(),
249 ok
250 );
251
252 let err: Result<u8, u16> = Err(0x1234);
253 assert_eq!(encode_to_vec(&err).unwrap(), vec![1, 0x34, 0x12]);
254 assert_eq!(
255 decode_from_slice_exact::<Result<u8, u16>>(&[1, 0x34, 0x12]).unwrap(),
256 err
257 );
258 }
259
260 #[test]
261 fn vec_and_array_roundtrip() {
262 let values = vec![1u16, 2, 3];
263 let encoded = encode_to_vec(&values).unwrap();
264 assert_eq!(
265 decode_from_slice_exact::<Vec<u16>>(&encoded).unwrap(),
266 values
267 );
268
269 let array = [1u8, 2, 3, 4];
270 let encoded = encode_to_vec(&array).unwrap();
271 assert_eq!(encoded, vec![1, 2, 3, 4]);
273 assert_eq!(decode_from_slice_exact::<[u8; 4]>(&encoded).unwrap(), array);
274 }
275
276 #[test]
277 fn vec_of_zero_sized_elements_roundtrips() {
278 let values: Vec<[u8; 0]> = vec![[], [], []];
282 let encoded = encode_to_vec(&values).unwrap();
283 assert_eq!(encoded, vec![3, 0, 0, 0]);
284 assert_eq!(
285 decode_from_slice_exact::<Vec<[u8; 0]>>(&encoded).unwrap(),
286 values
287 );
288 }
289
290 #[test]
291 fn tuples_roundtrip_by_field_order() {
292 assert_eq!(
293 decode_from_slice_exact::<(u8,)>(&encode_to_vec(&(1u8,)).unwrap()).unwrap(),
294 (1,)
295 );
296 assert_eq!(
297 decode_from_slice_exact::<(u8, u16)>(&encode_to_vec(&(1u8, 0x0203u16)).unwrap())
298 .unwrap(),
299 (1, 0x0203)
300 );
301 assert_eq!(
302 decode_from_slice_exact::<(u8, u16, bool)>(
303 &encode_to_vec(&(1u8, 0x0203u16, true)).unwrap()
304 )
305 .unwrap(),
306 (1, 0x0203, true)
307 );
308 assert_eq!(
309 decode_from_slice_exact::<(u8, u16, bool, i8)>(
310 &encode_to_vec(&(1u8, 0x0203u16, true, -4i8)).unwrap()
311 )
312 .unwrap(),
313 (1, 0x0203, true, -4)
314 );
315 }
316
317 #[test]
318 fn codec_error_accessors_and_display_are_actionable() {
319 let error = CodecError::new(CodecErrorKind::ReadFailed, "reader failed");
320 assert_eq!(error.kind(), CodecErrorKind::ReadFailed);
321 assert_eq!(error.message(), "reader failed");
322 assert_eq!(error.to_string(), "reader failed");
323
324 assert_eq!(CodecError::read_failed().kind(), CodecErrorKind::ReadFailed);
325 assert_eq!(
326 CodecError::write_failed().kind(),
327 CodecErrorKind::WriteFailed
328 );
329 assert_eq!(
330 CodecError::length_overflow("length too large").message(),
331 "length too large"
332 );
333
334 let mut rendered = String::new();
335 write!(&mut rendered, "{}", CodecError::trailing_bytes()).unwrap();
336 assert_eq!(rendered, "decode completed but trailing bytes remain");
337 }
338
339 #[test]
340 #[cfg(feature = "std")]
341 fn std_buf_writer_maps_write_failures() {
342 struct FailingWriter;
343
344 impl std::io::Write for FailingWriter {
345 fn write(&mut self, _buf: &[u8]) -> std::io::Result<usize> {
346 Err(std::io::Error::other("fail"))
347 }
348
349 fn flush(&mut self) -> std::io::Result<()> {
350 Ok(())
351 }
352 }
353
354 let mut writer = std::io::BufWriter::with_capacity(0, FailingWriter);
355 let err = 1u8.encode(&mut writer).unwrap_err();
356 assert_eq!(err.kind(), CodecErrorKind::WriteFailed);
357 }
358}