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}