Skip to main content

wire_repr/codec/
range_source.rs

1//! Range-source conversion contract.
2
3use super::FixedCodec;
4
5/// Performs checked bidirectional structural conversion between a decoded fixed source
6/// representation and byte geometry.
7///
8/// A range uses the geometry as either a relative byte length (`bytes(source)`) or an
9/// exclusive endpoint relative to representation byte zero (`bytes_to(source)`). Generated
10/// parsers call [`Self::to_bytes`] at the consuming range before their existing checked
11/// range and input-bounds logic. During [`crate::PreparedLayout`] preparation, generated
12/// builders derive required geometry, require shared sources to agree on that geometry, and
13/// call [`Self::from_bytes`] once for each source before planning its physical codec. Commit
14/// only writes the prepared plan and remains capacity-only and atomic.
15///
16/// Supported source values and byte geometries must round-trip coherently. Implementations
17/// must use checked arithmetic and return an explicit error for structural underflow,
18/// alignment, or encoded-field bounds they cannot convert. Unrelated protocol policy
19/// remains consumer-owned.
20///
21/// Macro adapters are supported only on direct built-in integer fixed fields that physically
22/// precede at least one range. This is a current hard ownership boundary: custom
23/// [`FixedCodec`] values or plans can require self-referential prepared storage. The
24/// adapter does not create a geometry getter; the ordinary source getter remains the raw
25/// wire integer. Unsigned bit projections may coexist with an adapter and read that whole
26/// integer; the adapter also consumes and returns the whole packed value.
27pub trait RangeSource<C: FixedCodec> {
28    /// Error returned when converting between the fixed representation and byte geometry.
29    type Error: core::fmt::Debug;
30
31    /// Converts a decoded fixed source value to a byte length or absolute endpoint.
32    fn to_bytes(value: C::Value<'_>) -> Result<usize, Self::Error>;
33
34    /// Converts a byte length or absolute endpoint to an owned fixed source value.
35    fn from_bytes(bytes: usize) -> Result<C::Value<'static>, Self::Error>;
36}
37
38#[cfg(test)]
39mod tests {
40    use super::RangeSource;
41    use crate::{BeU16, FixedCodec, U8};
42
43    struct U8Length;
44
45    impl RangeSource<U8> for U8Length {
46        type Error = ();
47
48        fn to_bytes(value: <U8 as FixedCodec>::Value<'_>) -> Result<usize, Self::Error> {
49            Ok(usize::from(value))
50        }
51
52        fn from_bytes(bytes: usize) -> Result<<U8 as FixedCodec>::Value<'static>, Self::Error> {
53            u8::try_from(bytes).map_err(|_| ())
54        }
55    }
56
57    struct BeU16Length;
58
59    impl RangeSource<BeU16> for BeU16Length {
60        type Error = ();
61
62        fn to_bytes(value: <BeU16 as FixedCodec>::Value<'_>) -> Result<usize, Self::Error> {
63            Ok(usize::from(value))
64        }
65
66        fn from_bytes(bytes: usize) -> Result<<BeU16 as FixedCodec>::Value<'static>, Self::Error> {
67            u16::try_from(bytes).map_err(|_| ())
68        }
69    }
70
71    #[test]
72    fn local_integer_adapters_need_no_allocation() {
73        assert_eq!(U8Length::to_bytes(7), Ok(7));
74        assert_eq!(U8Length::from_bytes(255), Ok(255));
75        assert_eq!(BeU16Length::to_bytes(0x1234), Ok(0x1234));
76        assert_eq!(BeU16Length::from_bytes(0xffff), Ok(0xffff));
77    }
78}