1use crate::buffer::BufferReader;
22use crate::error::DecodeError;
23
24#[cfg(feature = "alloc")]
25use crate::buffer::BufferWriter;
26#[cfg(feature = "alloc")]
27use crate::error::EncodeError;
28
29#[cfg(feature = "alloc")]
35pub trait CdrEncode {
36 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError>;
41}
42
43#[cfg(not(feature = "alloc"))]
47pub trait CdrEncode {}
48
49pub trait CdrDecode: Sized {
51 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError>;
56}
57
58#[cfg(feature = "alloc")]
63impl CdrEncode for u8 {
64 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
65 writer.write_u8(*self)
66 }
67}
68
69impl CdrDecode for u8 {
70 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
71 reader.read_u8()
72 }
73}
74
75#[cfg(feature = "alloc")]
76impl CdrEncode for i8 {
77 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
78 writer.write_u8(*self as u8)
79 }
80}
81
82impl CdrDecode for i8 {
83 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
84 Ok(reader.read_u8()? as i8)
85 }
86}
87
88#[cfg(feature = "alloc")]
89impl CdrEncode for u16 {
90 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
91 writer.write_u16(*self)
92 }
93}
94
95impl CdrDecode for u16 {
96 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
97 reader.read_u16()
98 }
99}
100
101#[cfg(feature = "alloc")]
102impl CdrEncode for i16 {
103 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
104 writer.write_u16(*self as u16)
105 }
106}
107
108impl CdrDecode for i16 {
109 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
110 Ok(reader.read_u16()? as i16)
111 }
112}
113
114#[cfg(feature = "alloc")]
115impl CdrEncode for u32 {
116 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
117 writer.write_u32(*self)
118 }
119}
120
121impl CdrDecode for u32 {
122 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
123 reader.read_u32()
124 }
125}
126
127#[cfg(feature = "alloc")]
128impl CdrEncode for i32 {
129 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
130 writer.write_u32(*self as u32)
131 }
132}
133
134impl CdrDecode for i32 {
135 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
136 Ok(reader.read_u32()? as i32)
137 }
138}
139
140#[cfg(feature = "alloc")]
141impl CdrEncode for u64 {
142 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
143 writer.write_u64(*self)
144 }
145}
146
147impl CdrDecode for u64 {
148 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
149 reader.read_u64()
150 }
151}
152
153#[cfg(feature = "alloc")]
154impl CdrEncode for i64 {
155 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
156 writer.write_u64(*self as u64)
157 }
158}
159
160impl CdrDecode for i64 {
161 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
162 Ok(reader.read_u64()? as i64)
163 }
164}
165
166#[cfg(feature = "alloc")]
167impl CdrEncode for f32 {
168 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
169 writer.write_u32(self.to_bits())
170 }
171}
172
173impl CdrDecode for f32 {
174 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
175 Ok(Self::from_bits(reader.read_u32()?))
176 }
177}
178
179#[cfg(feature = "alloc")]
180impl CdrEncode for f64 {
181 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
182 writer.write_u64(self.to_bits())
183 }
184}
185
186impl CdrDecode for f64 {
187 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
188 Ok(Self::from_bits(reader.read_u64()?))
189 }
190}
191
192#[cfg(feature = "alloc")]
193impl CdrEncode for bool {
194 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
195 writer.write_u8(u8::from(*self))
196 }
197}
198
199impl CdrDecode for bool {
200 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
201 let offset = reader.position();
202 let byte = reader.read_u8()?;
203 match byte {
204 0 => Ok(false),
205 1 => Ok(true),
206 other => Err(DecodeError::InvalidBool {
207 value: other,
208 offset,
209 }),
210 }
211 }
212}
213
214#[cfg(feature = "alloc")]
215impl CdrEncode for char {
216 fn encode(&self, writer: &mut BufferWriter) -> Result<(), EncodeError> {
217 writer.write_u32(*self as u32)
219 }
220}
221
222impl CdrDecode for char {
223 fn decode(reader: &mut BufferReader<'_>) -> Result<Self, DecodeError> {
224 let offset = reader.position();
225 let value = reader.read_u32()?;
226 char::from_u32(value).ok_or(DecodeError::InvalidChar { value, offset })
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 #![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]
233 use super::*;
234 use crate::Endianness;
235
236 #[cfg(feature = "alloc")]
237 fn roundtrip_alloc<T>(value: T)
238 where
239 T: CdrEncode + CdrDecode + PartialEq + core::fmt::Debug,
240 {
241 let mut w = BufferWriter::new(Endianness::Little);
242 value.encode(&mut w).expect("encode");
243 let bytes = w.into_bytes();
244 let mut r = BufferReader::new(&bytes, Endianness::Little);
245 let decoded = T::decode(&mut r).expect("decode");
246 assert_eq!(decoded, value);
247 assert_eq!(r.remaining(), 0);
248 }
249
250 #[cfg(feature = "alloc")]
251 fn roundtrip_be_alloc<T>(value: T)
252 where
253 T: CdrEncode + CdrDecode + PartialEq + core::fmt::Debug,
254 {
255 let mut w = BufferWriter::new(Endianness::Big);
256 value.encode(&mut w).expect("encode");
257 let bytes = w.into_bytes();
258 let mut r = BufferReader::new(&bytes, Endianness::Big);
259 let decoded = T::decode(&mut r).expect("decode");
260 assert_eq!(decoded, value);
261 }
262
263 #[cfg(feature = "alloc")]
264 #[test]
265 fn u8_roundtrip() {
266 roundtrip_alloc(0u8);
267 roundtrip_alloc(0xABu8);
268 roundtrip_alloc(0xFFu8);
269 }
270
271 #[cfg(feature = "alloc")]
272 #[test]
273 fn i8_roundtrip() {
274 roundtrip_alloc(0i8);
275 roundtrip_alloc(-1i8);
276 roundtrip_alloc(127i8);
277 roundtrip_alloc(-128i8);
278 }
279
280 #[cfg(feature = "alloc")]
281 #[test]
282 fn u16_roundtrip_le_and_be() {
283 roundtrip_alloc(0x1234u16);
284 roundtrip_be_alloc(0x1234u16);
285 roundtrip_alloc(u16::MAX);
286 }
287
288 #[cfg(feature = "alloc")]
289 #[test]
290 fn i16_roundtrip() {
291 roundtrip_alloc(-1i16);
292 roundtrip_alloc(i16::MIN);
293 roundtrip_alloc(i16::MAX);
294 }
295
296 #[cfg(feature = "alloc")]
297 #[test]
298 fn u32_roundtrip() {
299 roundtrip_alloc(0xDEAD_BEEFu32);
300 roundtrip_be_alloc(0xCAFE_BABEu32);
301 }
302
303 #[cfg(feature = "alloc")]
304 #[test]
305 fn i32_roundtrip() {
306 roundtrip_alloc(-1i32);
307 roundtrip_alloc(i32::MIN);
308 roundtrip_alloc(i32::MAX);
309 }
310
311 #[cfg(feature = "alloc")]
312 #[test]
313 fn u64_roundtrip() {
314 roundtrip_alloc(0x0102_0304_0506_0708u64);
315 roundtrip_be_alloc(0x0102_0304_0506_0708u64);
316 }
317
318 #[cfg(feature = "alloc")]
319 #[test]
320 fn i64_roundtrip() {
321 roundtrip_alloc(-1i64);
322 roundtrip_alloc(i64::MIN);
323 roundtrip_alloc(i64::MAX);
324 }
325
326 #[cfg(feature = "alloc")]
327 #[test]
328 fn f32_roundtrip_normal_values() {
329 roundtrip_alloc(0.0f32);
330 roundtrip_alloc(1.5f32);
331 roundtrip_alloc(-2.5f32);
332 roundtrip_alloc(f32::MIN_POSITIVE);
333 }
334
335 #[cfg(feature = "alloc")]
336 #[test]
337 fn f32_roundtrip_special() {
338 let mut w = BufferWriter::new(Endianness::Little);
340 f32::NAN.encode(&mut w).unwrap();
341 let bytes = w.into_bytes();
342 let mut r = BufferReader::new(&bytes, Endianness::Little);
343 let decoded = f32::decode(&mut r).unwrap();
344 assert!(decoded.is_nan());
345 }
346
347 #[cfg(feature = "alloc")]
348 #[test]
349 fn f64_roundtrip() {
350 roundtrip_alloc(0.0f64);
351 roundtrip_alloc(core::f64::consts::PI);
352 roundtrip_alloc(-1.0e-308f64);
353 }
354
355 #[cfg(feature = "alloc")]
356 #[test]
357 fn bool_roundtrip() {
358 roundtrip_alloc(true);
359 roundtrip_alloc(false);
360 }
361
362 #[test]
363 fn bool_decode_rejects_other_values() {
364 let bytes = [0xFFu8];
365 let mut r = BufferReader::new(&bytes, Endianness::Little);
366 let res = bool::decode(&mut r);
367 assert!(matches!(
368 res,
369 Err(DecodeError::InvalidBool {
370 value: 0xFF,
371 offset: 0
372 })
373 ));
374 }
375
376 #[cfg(feature = "alloc")]
377 #[test]
378 fn char_roundtrip_ascii_and_unicode() {
379 roundtrip_alloc('A');
380 roundtrip_alloc('z');
381 roundtrip_alloc('0');
382 roundtrip_alloc('🦀'); roundtrip_alloc('ä');
384 }
385
386 #[test]
387 fn char_decode_rejects_surrogate() {
388 let bytes = [0x00, 0xD8, 0x00, 0x00];
390 let mut r = BufferReader::new(&bytes, Endianness::Little);
391 let res = char::decode(&mut r);
392 assert!(matches!(
393 res,
394 Err(DecodeError::InvalidChar { value: 0xD800, .. })
395 ));
396 }
397
398 #[cfg(feature = "alloc")]
399 #[test]
400 fn primitives_align_correctly_when_mixed() {
401 let mut w = BufferWriter::new(Endianness::Little);
403 1u8.encode(&mut w).unwrap();
404 2u16.encode(&mut w).unwrap();
405 3u32.encode(&mut w).unwrap();
406 4u64.encode(&mut w).unwrap();
407 assert_eq!(w.position(), 16);
408
409 let bytes = w.into_bytes();
410 let mut r = BufferReader::new(&bytes, Endianness::Little);
411 assert_eq!(u8::decode(&mut r).unwrap(), 1);
412 assert_eq!(u16::decode(&mut r).unwrap(), 2);
413 assert_eq!(u32::decode(&mut r).unwrap(), 3);
414 assert_eq!(u64::decode(&mut r).unwrap(), 4);
415 }
416}