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