Skip to main content

ridl_rt/
payload.rs

1//! Encoding, verifying and decoding a payload.
2//!
3//! A generated payload type implements [`Payload<E>`] once for each encoding.
4//! Its `verify` checks the structure of the bytes and the typl constraints of
5//! the value in one pass. Its `decode` takes a [`Ref`], and only
6//! [`Ref::verify`] and [`Ref::encode`] build a `Ref`. So a value is decoded
7//! only from bytes that were checked, or that its own encoder wrote.
8
9use core::marker::PhantomData;
10
11use crate::encoding::Encoding;
12
13/// A type that can be carried as a payload in the encoding `E`.
14///
15/// Generated code implements this trait and never calls its methods directly:
16/// it calls [`Ref::verify`], [`Ref::encode`] and [`Ref::decode`].
17pub trait Payload<E: Encoding>: Sized {
18    /// The largest encoded size of any legal value, in bytes.
19    const MAX_SIZE: usize;
20
21    /// What a successful check or encode leaves behind: the bytes, an
22    /// accessor over the bytes, or a parsed value.
23    type View<'a>;
24
25    /// Writes `self` into `out` and returns the bytes written.
26    ///
27    /// The bytes are a subslice of `out`, not necessarily a prefix of it: an
28    /// encoding whose builder works backwards — FlatBuffers does — fills `out`
29    /// from its end. A caller reads [`Encoded::bytes`] and passes it on rather
30    /// than assuming where in `out` it sits.
31    fn encode<'o>(&self, out: &'o mut [u8]) -> Result<Encoded<'o, Self::View<'o>>, EncodeError>;
32
33    /// Checks the structure of `buf` and the typl constraints of the value it
34    /// holds, in one pass.
35    fn verify(buf: &[u8]) -> Result<Self::View<'_>, VerifyError>;
36
37    /// Builds the value from a proof. It cannot fail, because the proof shows
38    /// that the bytes were checked or encoded.
39    fn decode(r: Ref<'_, Self, E>) -> Self;
40}
41
42/// The result of [`Payload::encode`]: the bytes written and their view. It is
43/// data, not a proof.
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45pub struct Encoded<'a, V> {
46    /// The encoded bytes, a subslice of the output buffer.
47    pub bytes: &'a [u8],
48    /// The view of those bytes.
49    pub view: V,
50}
51
52/// A proof that some bytes passed `T::verify` or were written by `T::encode`.
53///
54/// The fields are private and [`Ref::verify`] and [`Ref::encode`] are the only
55/// constructors. A crate outside `ridl-rt` builds a `Ref` by checking:
56///
57/// ```
58/// use ridl_rt::encoding::ReprC;
59/// use ridl_rt::payload::{Payload, Ref, VerifyError};
60///
61/// fn check<'a, T>(bytes: &'a [u8]) -> Result<Ref<'a, T, ReprC>, VerifyError>
62/// where
63///     T: Payload<ReprC, View<'a> = &'a [u8]>,
64/// {
65///     Ref::verify(bytes)
66/// }
67/// ```
68///
69/// and cannot build one from its fields:
70///
71/// ```compile_fail,E0451
72/// use core::marker::PhantomData;
73/// use ridl_rt::encoding::ReprC;
74/// use ridl_rt::payload::{Payload, Ref};
75///
76/// fn forge<'a, T>(bytes: &'a [u8]) -> Ref<'a, T, ReprC>
77/// where
78///     T: Payload<ReprC, View<'a> = &'a [u8]>,
79/// {
80///     Ref { bytes, view: bytes, _e: PhantomData }
81/// }
82/// ```
83pub struct Ref<'a, T: Payload<E>, E: Encoding> {
84    bytes: &'a [u8],
85    view: T::View<'a>,
86    _e: PhantomData<E>,
87}
88
89impl<'a, T: Payload<E>, E: Encoding> Ref<'a, T, E> {
90    /// Checks `buf` with `T::verify` and returns the proof.
91    pub fn verify(buf: &'a [u8]) -> Result<Self, VerifyError> {
92        let view = T::verify(buf)?;
93        Ok(Ref {
94            bytes: buf,
95            view,
96            _e: PhantomData,
97        })
98    }
99
100    /// Encodes `value` into `out` with `T::encode` and returns the proof.
101    ///
102    /// It does not check the value's typl constraints: a value is trusted to
103    /// be valid when constructed, and the receiver's `verify` reports a value
104    /// that is not.
105    pub fn encode(value: &T, out: &'a mut [u8]) -> Result<Self, EncodeError> {
106        let Encoded { bytes, view } = value.encode(out)?;
107        Ok(Ref {
108            bytes,
109            view,
110            _e: PhantomData,
111        })
112    }
113
114    /// The checked or encoded bytes.
115    pub fn bytes(&self) -> &'a [u8] {
116        self.bytes
117    }
118
119    /// Lends the view.
120    pub fn view(&self) -> &T::View<'a> {
121        &self.view
122    }
123
124    /// Moves the view out.
125    pub fn into_view(self) -> T::View<'a> {
126        self.view
127    }
128
129    /// Builds the value with `T::decode`.
130    pub fn decode(self) -> T {
131        T::decode(self)
132    }
133}
134
135/// An encode that failed.
136#[non_exhaustive]
137#[derive(Clone, Copy, Debug, PartialEq, Eq)]
138pub enum EncodeError {
139    /// The output buffer is shorter than the encoding.
140    Capacity {
141        /// The bytes the encoding needs: a lower bound, not always the whole
142        /// requirement.
143        ///
144        /// An encoder that knows its size before it writes reports the whole
145        /// encoding. One that builds incrementally — the FlatBuffers encoder
146        /// does, because a child's size is known only once it is written —
147        /// reports what it needed at the point it gave up, which is at least
148        /// `available + 1` and at most the whole encoding. Either way a
149        /// caller that grows the buffer to `needed` has made progress, and
150        /// one that wants a buffer that always suffices uses
151        /// [`Payload::MAX_SIZE`].
152        needed: usize,
153        /// The bytes the output buffer has.
154        available: usize,
155    },
156}
157
158/// A check that failed.
159#[non_exhaustive]
160#[derive(Clone, Copy, Debug, PartialEq, Eq)]
161pub enum VerifyError {
162    /// The bytes are not a well-formed encoding: a serialization failure, ridl
163    /// §10.3.
164    Structure(Malformed),
165    /// The bytes are well formed and hold a value that breaks a typl
166    /// constraint: `INVALID_VALUE`, ridl §10.2.
167    Contract(Violation),
168}
169
170/// How the bytes of an encoding are malformed.
171#[non_exhaustive]
172#[derive(Clone, Copy, Debug, PartialEq, Eq)]
173pub enum Malformed {
174    /// An offset or a length points outside the buffer.
175    OutOfBounds,
176    /// A value is not at its required alignment.
177    Unaligned,
178    /// A required field is absent.
179    MissingRequired,
180    /// A string is not valid UTF-8.
181    Utf8,
182    /// A union's type does not match its value.
183    Union,
184    /// The nesting is deeper than the verifier's limit.
185    TooDeep,
186    /// The buffer holds more tables than the verifier's limit.
187    TooManyTables,
188    /// The buffer is larger than the verifier's limit.
189    TooLarge,
190}
191
192/// A value that breaks a typl constraint.
193#[derive(Clone, Copy, Debug, PartialEq, Eq)]
194pub struct Violation {
195    /// The name of the typl type whose constraint failed.
196    pub type_name: &'static str,
197    /// The kind of constraint that failed.
198    pub rule: Rule,
199}
200
201/// The kind of typl constraint a [`Violation`] breaks.
202#[non_exhaustive]
203#[derive(Clone, Copy, Debug, PartialEq, Eq)]
204pub enum Rule {
205    /// A number is outside its declared range.
206    Range,
207    /// A number is not its range's lower bound plus a whole multiple of its
208    /// declared step.
209    Step,
210    /// A string, a byte sequence or a collection is outside its declared
211    /// length bounds.
212    Length,
213    /// A string does not match its declared pattern.
214    Pattern,
215    /// A discriminant names no declared variant.
216    Variant,
217}
218
219#[cfg(test)]
220mod tests {
221    use core::marker::PhantomData;
222
223    use super::{EncodeError, Encoded, Payload, Ref, Rule, VerifyError};
224    use crate::encoding::ReprC;
225
226    /// A payload for this test only: its view is the bytes.
227    struct Raw;
228
229    impl Payload<ReprC> for Raw {
230        const MAX_SIZE: usize = 0;
231        type View<'a> = &'a [u8];
232
233        fn encode<'o>(&self, out: &'o mut [u8]) -> Result<Encoded<'o, &'o [u8]>, EncodeError> {
234            let bytes: &'o [u8] = &out[..0];
235            Ok(Encoded { bytes, view: bytes })
236        }
237
238        fn verify(buf: &[u8]) -> Result<&[u8], VerifyError> {
239            Ok(buf)
240        }
241
242        fn decode(_: Ref<'_, Self, ReprC>) -> Self {
243            Raw
244        }
245    }
246
247    /// The struct literal names every field, so a field added to `Ref` fails
248    /// to compile this test. The `compile_fail` doctest on `Ref` cannot pin
249    /// the field set, because it fails for any compile error.
250    #[test]
251    fn a_ref_is_built_from_exactly_its_three_fields() {
252        let bytes: &[u8] = &[1, 2];
253        let proof: Ref<'_, Raw, ReprC> = Ref {
254            bytes,
255            view: bytes,
256            _e: PhantomData,
257        };
258        assert_eq!(proof.bytes(), bytes);
259    }
260
261    /// The match names every variant with no `_` arm, so a `Rule` variant
262    /// added or removed fails this test to compile.
263    #[test]
264    fn rule_is_exactly_these_five_variants() {
265        fn all(r: Rule) {
266            match r {
267                Rule::Range => {}
268                Rule::Step => {}
269                Rule::Length => {}
270                Rule::Pattern => {}
271                Rule::Variant => {}
272            }
273        }
274        all(Rule::Range);
275    }
276}