Skip to main content

wire_repr/codec/
fixed.rs

1//! Fixed-width codec contracts.
2
3use super::EncodePlan;
4
5/// A codec whose encoded representation always has one fixed width.
6///
7/// [`Self::WIDTH`] must be nonzero. Every successful [`Self::plan`] must report that
8/// exact encoded length. For every such plan, [`EncodePlan::write_into`] called with
9/// an output slice of exactly [`Self::WIDTH`] bytes must write a complete representation
10/// whose decoding recovers the same semantic value supplied to [`Self::plan`]. Decoding
11/// is total for every exact-width byte pattern. A codec that violates these requirements
12/// is contract-invalid.
13///
14/// When a layout builder derives a region length through
15/// `Self::Value<'static>: TryFrom<usize>`, the complete conversion and codec round trip
16/// must preserve that length: converting the decoded planned representation back to
17/// `usize` must produce the original region length.
18///
19/// [`Self::plan`] completes all fallible encoding work before a caller mutates an output
20/// buffer. Layout parsing establishes exact-width bounds before calling [`Self::decode`].
21pub trait FixedCodec {
22    /// Semantic value represented by an exact-width wire representation.
23    type Value<'wire>
24    where
25        Self: 'wire;
26
27    /// Error returned while preparing an encoded value.
28    type EncodeError: core::fmt::Debug;
29
30    /// Prepared fixed-width encoded bytes.
31    type Plan<'value>: EncodePlan
32    where
33        Self: 'value;
34
35    /// Number of bytes in every encoded representation.
36    const WIDTH: usize;
37
38    /// Decodes an exact-width encoded representation.
39    fn decode<'wire>(bytes: &'wire [u8]) -> Self::Value<'wire>;
40
41    /// Prepares the complete encoded representation without mutating a caller buffer.
42    fn plan<'value>(value: Self::Value<'value>) -> Result<Self::Plan<'value>, Self::EncodeError>;
43}
44
45/// Error returned when an exact-width byte value has the wrong length.
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub struct ExactWidthError {
48    expected: usize,
49    actual: usize,
50}
51
52impl ExactWidthError {
53    /// Creates an error for an exact-width mismatch.
54    #[must_use]
55    pub const fn new(expected: usize, actual: usize) -> Self {
56        Self { expected, actual }
57    }
58
59    /// Returns the required byte length.
60    #[must_use]
61    pub const fn expected(&self) -> usize {
62        self.expected
63    }
64
65    /// Returns the supplied byte length.
66    #[must_use]
67    pub const fn actual(&self) -> usize {
68        self.actual
69    }
70}
71
72impl core::fmt::Display for ExactWidthError {
73    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74        write!(
75            formatter,
76            "fixed codec expected {} bytes, got {}",
77            self.expected, self.actual
78        )
79    }
80}
81
82impl core::error::Error for ExactWidthError {}
83
84/// A borrowed fixed-width span of wire bytes with no content interpretation.
85///
86/// `N` must be nonzero. Using `Bytes<0>` as a [`FixedCodec`] fails during constant
87/// evaluation rather than exposing a codec that violates [`FixedCodec::WIDTH`].
88///
89/// ```compile_fail
90/// use wire_repr::{Bytes, FixedCodec};
91///
92/// let _ = <Bytes<0> as FixedCodec>::WIDTH;
93/// ```
94///
95/// `Bytes<N>` decodes to the exact borrowed wire slice and plans an equally borrowed input
96/// slice for copying at write time. It does not validate magic values, reserved bytes, or
97/// any other domain semantics; consumers own those policies.
98#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
99pub struct Bytes<const N: usize>;
100
101impl<const N: usize> FixedCodec for Bytes<N> {
102    type Value<'wire>
103        = &'wire [u8]
104    where
105        Self: 'wire;
106    type EncodeError = ExactWidthError;
107    type Plan<'value>
108        = &'value [u8]
109    where
110        Self: 'value;
111
112    const WIDTH: usize = {
113        assert!(N != 0, "Bytes<N> requires a nonzero width");
114        N
115    };
116
117    #[inline]
118    fn decode<'wire>(bytes: &'wire [u8]) -> Self::Value<'wire> {
119        const { assert!(N != 0, "Bytes<N> requires a nonzero width") };
120        bytes
121    }
122
123    #[inline]
124    fn plan<'value>(value: Self::Value<'value>) -> Result<Self::Plan<'value>, Self::EncodeError> {
125        const { assert!(N != 0, "Bytes<N> requires a nonzero width") };
126        if value.len() == N {
127            Ok(value)
128        } else {
129            Err(ExactWidthError::new(N, value.len()))
130        }
131    }
132}