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