Skip to main content

broadcast_common/
traits.rs

1//! Canonical `Parse` and `Serialize` traits for the DVB crate family.
2//!
3//! Each implementer picks its own error type via `type Error`, so
4//! domain-specific error variants stay visible to the caller.
5
6use alloc::vec::Vec;
7
8/// Parse a DVB structure from raw bytes. Borrowing allowed via `<'a>`; the
9/// concrete error type is chosen per implementer.
10pub trait Parse<'a>: Sized {
11    /// The error type this implementer returns. Typically the enclosing
12    /// crate's `Error` enum.
13    type Error;
14
15    /// Parse `bytes` as `Self`. Returns `Err(Self::Error)` on any protocol
16    /// violation or buffer underrun.
17    fn parse(bytes: &'a [u8]) -> Result<Self, Self::Error>;
18}
19
20/// Serialize a DVB structure back to bytes. Split from [`Parse`] so owned
21/// and borrowed variants of the same type can implement `Serialize`
22/// without carrying a lifetime.
23pub trait Serialize {
24    /// The error type this implementer returns (usually the same as the
25    /// corresponding [`Parse`] impl, but need not be).
26    type Error;
27
28    /// Number of bytes `serialize_into` will write.
29    fn serialized_len(&self) -> usize;
30
31    /// Write the serialised form into `buf`. Returns the number of bytes
32    /// written (always equal to `serialized_len()`).
33    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize, Self::Error>;
34
35    /// Allocate a `Vec` and serialize into it, returning the serializer's error instead of
36    /// panicking. This is the only
37    /// allocate-and-serialize entry point: there is deliberately no panicking
38    /// `to_bytes` (hand-built values, or values assembled from damaged wire data,
39    /// can violate a wire constraint, so the error must reach the caller).
40    fn try_to_bytes(&self) -> Result<Vec<u8>, Self::Error> {
41        let mut v = alloc::vec![0u8; self.serialized_len()];
42        let written = self.serialize_into(&mut v)?;
43        // A serializer that writes fewer bytes than it promised must not
44        // leave trailing zeros in the result.
45        if written != v.len() {
46            v.truncate(written);
47        }
48        Ok(v)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55    use core::fmt;
56
57    #[derive(Debug, PartialEq)]
58    struct TestError;
59
60    impl fmt::Display for TestError {
61        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62            f.write_str("test serializer error")
63        }
64    }
65
66    /// Minimal `Serialize` impl whose `serialize_into` fails when `fail` is set.
67    struct Flagged {
68        fail: bool,
69        written: usize,
70    }
71
72    impl Serialize for Flagged {
73        type Error = TestError;
74
75        fn serialized_len(&self) -> usize {
76            4
77        }
78
79        fn serialize_into(&self, buf: &mut [u8]) -> Result<usize, Self::Error> {
80            if self.fail {
81                return Err(TestError);
82            }
83            let n = self.written.min(buf.len());
84            buf[..n].copy_from_slice(&[1, 2, 3, 4][..n]);
85            Ok(n)
86        }
87    }
88
89    #[test]
90    fn try_to_bytes_returns_serializer_error() {
91        assert_eq!(
92            Flagged {
93                fail: true,
94                written: 0
95            }
96            .try_to_bytes(),
97            Err(TestError)
98        );
99    }
100
101    #[test]
102    fn try_to_bytes_truncates_when_serializer_writes_less_than_promised() {
103        // serialized_len is 4 but only 3 bytes are written: no trailing zero.
104        let v = Flagged {
105            fail: false,
106            written: 3,
107        }
108        .try_to_bytes()
109        .unwrap();
110        assert_eq!(v, vec![1, 2, 3]);
111    }
112
113    #[test]
114    fn try_to_bytes_happy_path_fills_buffer() {
115        let ok = Flagged {
116            fail: false,
117            written: 4,
118        };
119        assert_eq!(ok.try_to_bytes().unwrap(), vec![1, 2, 3, 4]);
120    }
121}