vitaminc_aead/plaintext/mod.rs
1//! The plaintext data model: a source describes itself once ([`Encrypt`])
2//! to a consumer ([`Sink`]), the way serde splits `Serialize` from
3//! `Serializer`.
4//!
5//! - **Containers are push-style.** [`SeqSink::element`] returns a sink for
6//! the next element rather than taking the element as a value, so the
7//! source drives the whole walk and any number of sinks can share it
8//! (see [`Tee`]).
9//! - **Sources can fail.** Every sink error implements [`Error`], so a
10//! source can stop the walk with [`Error::source`] without knowing which
11//! sink it is feeding. That is what lets a native binding walk a live host
12//! object, where a getter can throw, without taking a snapshot first.
13//! - **Lengths are optional,** for host iterables that do not know their
14//! size.
15//! - **A scalar is a physical value plus an optional logical type.** One
16//! [`Sink::scalar`] method takes a [`Physical`] value and an optional
17//! [`Logical`] type, rather than a method per kind. See [`kinds`].
18//!
19//! `Sink` is implemented inside vitaminc and its host bindings. Application
20//! code implements `Encrypt`, usually by derive.
21
22pub mod depth;
23pub mod kinds;
24mod path;
25mod sources;
26mod tee;
27
28pub use kinds::{
29 FixedType, Float, Int, Kind, KnownLogical, Logical, Physical, TimeUnit, UnknownLogical,
30 UnknownLogicalId, Width,
31};
32#[cfg(any(test, feature = "test-support"))]
33#[doc(hidden)]
34pub use path::render;
35pub use path::{Path, Step};
36pub use sources::{Bytes, Raw};
37
38/// What `#[derive(Encrypt)]`'s expansion needs by path. Not an API.
39#[doc(hidden)]
40pub mod __private {
41 pub use super::sources::discard_one;
42}
43pub use tee::Tee;
44
45/// A value that can describe itself to a [`Sink`].
46///
47/// Implemented by Rust primitives and containers, by the optional chrono,
48/// `rust_decimal` and uuid types, and by host bindings for their own values.
49/// A struct implements it by walking its fields into a map, which is what
50/// `#[derive(Encrypt)]` generates.
51///
52/// `Encrypt` and [`Decrypt`](crate::Decrypt) are the pair a type implements
53/// to say how it is encrypted and decrypted. Neither does any cryptography:
54/// that is the [`Cipher`](crate::Cipher)'s job, and the same walk also
55/// feeds sinks that are not ciphers, such as equality terms and the
56/// transport frame. This trait replaces the visitor-based `Encrypt` of
57/// vitaminc 0.5, which drove a cipher directly.
58///
59/// # Owned values and `Protected`
60///
61/// A source implements `Encrypt` for `T` and for `&T`. The by-value walk
62/// consumes the value; the borrowed walk hands the sink borrows of what
63/// the value holds and leaves it where it is. `Protected<T>` walks as a
64/// borrow of what it wraps, so nothing leaves the wrapper during the walk
65/// and everything in it, visited or not, is zeroized when it drops. That
66/// is why a type that is to sit inside a `Protected`, a derived struct
67/// included, needs the borrowed impl; the derive generates it.
68///
69/// An owned byte or text leaf (`String`, `Vec<u8>`, `[u8; N]`) wraps itself
70/// in a `Protected` before the sink sees it, so its buffer is wiped however
71/// it arrives. A bare container that is walked by value and stops part way
72/// discards the children it did not reach through their own walks, so
73/// their owned leaves are wiped too rather than dropped bare. A
74/// hand-written leaf that owns a secret buffer should wrap itself the same
75/// way, and a hand-written container should not drop unvisited children
76/// bare.
77pub trait Encrypt {
78 /// How deep a value of this type can nest below its own root, when the
79 /// type alone fixes it: `Some(0)` for a scalar, one more than its
80 /// deepest child for a sequence or map (see [`depth`]). `None`, the
81 /// default, when it depends on the value: a recursive type, a frame, a
82 /// live host value.
83 ///
84 /// `#[derive(Encrypt)]` works this out from the fields' depths and fails
85 /// to compile a type deeper than [`MAX_DEPTH`](crate::frame::MAX_DEPTH),
86 /// whose fully populated values the encrypting sink would always
87 /// refuse. A hand-written impl may leave it `None`, which skips the
88 /// check for every type that contains it; the walk still refuses a
89 /// value that is too deep. It must never be more than the deepest a
90 /// value of the type can nest, or a type that is fine fails to compile.
91 const DEPTH: Option<usize> = None;
92
93 /// The fixed-width scalar type every value of this type has, if it has
94 /// one: an int, a float, a date, a timestamp, a decimal. `None`, the
95 /// default, for everything else: a bool (whose leaf is already as short
96 /// as a null's), text, bytes, a container, a value whose type depends
97 /// on the value.
98 ///
99 /// `Option<Self>` walks its `None` as a [`Sink::typed_null`] of this
100 /// type, so the encrypting sink seals it padded to the length of a
101 /// `Some`, and [`Decrypt`](crate::Decrypt) reads that typed null back
102 /// only into an `Option` of the same type. It must be the type
103 /// [`visit`](Encrypt::visit) always walks, normalised as
104 /// [`FixedType`] normalises it, or a `None` and a `Some` seal at
105 /// different lengths.
106 const FIXED: Option<FixedType> = None;
107
108 /// Describe `self` to `sink`, consuming it.
109 fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error>;
110}
111
112/// Every sink's error type.
113///
114/// A source reports its own failure through [`source`](Error::source),
115/// without knowing which sink it is feeding.
116pub trait Error: Sized {
117 /// Wrap a failure that came from the source, not the sink.
118 fn source(error: SourceError) -> Self;
119}
120
121/// A failure reading the source: a host getter threw, a string had an
122/// unpaired surrogate, a big integer was out of range, a timestamp was a
123/// leap second.
124///
125/// Transparent: it displays as the wrapped error, and its `source()` is the
126/// wrapped error's, so a reporter that walks the chain sees what lies behind
127/// a failed getter.
128#[derive(Debug, thiserror::Error)]
129#[error(transparent)]
130pub struct SourceError(Box<dyn core::error::Error + Send + Sync>);
131
132impl SourceError {
133 /// A source error from any error type.
134 pub fn new(error: impl core::error::Error + Send + Sync + 'static) -> Self {
135 Self(Box::new(error))
136 }
137
138 /// A source error from a message.
139 pub fn msg(msg: impl Into<String>) -> Self {
140 Self(msg.into().into())
141 }
142
143 /// The underlying error, which can be downcast to its concrete type.
144 pub fn inner(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
145 &*self.0
146 }
147}
148
149/// A consumer of one value's description.
150///
151/// A sink is used once: each method takes `self`. Containers hand back a
152/// [`SeqSink`] or [`MapSink`] that produces one child sink per element or
153/// entry.
154pub trait Sink: Sized {
155 /// What the sink produces when the walk ends.
156 type Ok;
157 /// The sink's error, which can also carry a [`SourceError`].
158 type Error: Error;
159 /// The sink for a sequence's elements.
160 type Seq: SeqSink<Ok = Self::Ok, Error = Self::Error>;
161 /// The sink for a map's entries.
162 type Map: MapSink<Ok = Self::Ok, Error = Self::Error>;
163
164 /// One scalar: a physical value, and the logical type it represents,
165 /// if any. See [`kinds`].
166 ///
167 /// # Examples
168 ///
169 /// A plain value has no logical type. A value that means something
170 /// more names the type it is stored as, and the sink checks that the
171 /// physical value fits it ([`Logical::admits`]).
172 ///
173 /// ```
174 /// use vitaminc_aead::plaintext::{Int, Logical, Physical, Encrypt, Sink};
175 ///
176 /// struct Celsius(i32);
177 ///
178 /// impl Encrypt for Celsius {
179 /// fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
180 /// sink.scalar(None, Physical::Int(Int::I32(self.0)))
181 /// }
182 /// }
183 ///
184 /// /// Days since 1970-01-01.
185 /// struct Day(i32);
186 ///
187 /// impl Encrypt for Day {
188 /// fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
189 /// sink.scalar(Some(Logical::Date), Physical::Int(Int::I32(self.0)))
190 /// }
191 /// }
192 /// ```
193 fn scalar(self, ty: Option<Logical>, value: Physical<'_>) -> Result<Self::Ok, Self::Error>;
194
195 /// An absent value of a fixed-width type: a null that says what it
196 /// stands in for. `Option<T>` walks its `None` here when `T` has a
197 /// [`FIXED`](Encrypt::FIXED) type, and a host that knows a missing
198 /// value's type does the same.
199 ///
200 /// It means what `scalar(None, Physical::Null)` means; the type is
201 /// there so its length can be hidden. The encrypting sink seals it as a
202 /// typed null padded to the type's leaf length (see
203 /// [`tags::TYPED_NULL`](crate::tags::TYPED_NULL)), the frame carries
204 /// it, and a typed decode target reads it only as an `Option` of the
205 /// same type. A sink that only needs to know a value is absent treats
206 /// it as a null. A sink that forwards to other sinks must forward it as
207 /// it is, or the padding is lost and absent values show again.
208 fn typed_null(self, ty: FixedType) -> Result<Self::Ok, Self::Error>;
209
210 /// Start a sequence. `len` is a hint; a source that does not know its
211 /// length passes `None`.
212 fn seq(self, len: Option<usize>) -> Result<Self::Seq, Self::Error>;
213
214 /// Start a map with string keys. `len` is a hint.
215 fn map(self, len: Option<usize>) -> Result<Self::Map, Self::Error>;
216
217 /// A subtree that travels in the clear. It is walked like anything
218 /// else; the sink decides what "in the clear" means for it.
219 ///
220 /// The value is `Clone` so that a sink which is really several sinks
221 /// (see [`Tee`]) can give the subtree to each of them. Passthrough is
222 /// non-sensitive by contract, so the copy carries no secret.
223 fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<Self::Ok, Self::Error>;
224}
225
226/// The sink for a sequence's elements.
227pub trait SeqSink: Sized {
228 type Ok;
229 type Error: Error;
230 /// A sink for one element. It borrows the sequence sink and writes
231 /// into it; its own `Ok` is incidental.
232 type Element<'s>: Sink<Error = Self::Error>
233 where
234 Self: 's;
235
236 /// A sink for the next element.
237 fn element(&mut self) -> Result<Self::Element<'_>, Self::Error>;
238
239 /// Finish the sequence.
240 fn end(self) -> Result<Self::Ok, Self::Error>;
241}
242
243/// The sink for a map's entries. Keys are strings and travel in the clear.
244pub trait MapSink: Sized {
245 type Ok;
246 type Error: Error;
247 /// A sink for one entry's value.
248 type Entry<'s>: Sink<Error = Self::Error>
249 where
250 Self: 's;
251
252 /// A sink for the value under `key`.
253 fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, Self::Error>;
254
255 /// Finish the map.
256 fn end(self) -> Result<Self::Ok, Self::Error>;
257}
258
259/// Walk each item into its own element sink: the loop every sequence
260/// source writes.
261pub fn visit_seq<S, I>(sink: S, len: Option<usize>, items: I) -> Result<S::Ok, S::Error>
262where
263 S: Sink,
264 I: IntoIterator,
265 I::Item: Encrypt,
266{
267 let mut seq = sink.seq(len)?;
268 for item in items {
269 item.visit(seq.element()?)?;
270 }
271 seq.end()
272}
273
274/// Walk each `(key, value)` into its own entry sink: the loop every map
275/// source writes.
276///
277/// # Examples
278///
279/// ```
280/// use std::collections::BTreeMap;
281/// use vitaminc_aead::plaintext::{visit_map, Encrypt, Sink};
282///
283/// struct Scores(BTreeMap<String, u32>);
284///
285/// impl Encrypt for Scores {
286/// fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
287/// let len = Some(self.0.len());
288/// visit_map(sink, len, self.0.iter().map(|(name, score)| (name.as_str(), *score)))
289/// }
290/// }
291/// ```
292pub fn visit_map<'k, S, I, P>(sink: S, len: Option<usize>, entries: I) -> Result<S::Ok, S::Error>
293where
294 S: Sink,
295 I: IntoIterator<Item = (&'k str, P)>,
296 P: Encrypt,
297{
298 let mut map = sink.map(len)?;
299 for (key, value) in entries {
300 value.visit(map.entry(key)?)?;
301 }
302 map.end()
303}
304
305#[cfg(test)]
306pub(crate) mod record {
307 //! A sink that records every call, for tests of sources and of sinks
308 //! that forward to other sinks.
309
310 use super::*;
311
312 #[derive(Debug, Clone, PartialEq)]
313 pub enum Event {
314 Scalar(Option<Logical>, Owned),
315 TypedNull(FixedType),
316 Seq(Option<usize>),
317 Element,
318 EndSeq,
319 Map(Option<usize>),
320 Entry(String),
321 EndMap,
322 Passthrough,
323 }
324
325 /// An owned copy of a physical value, so a recording can outlive the
326 /// borrow a source handed over.
327 #[derive(Debug, Clone, PartialEq)]
328 pub enum Owned {
329 Null,
330 Bool(bool),
331 Int(Int),
332 Float(Float),
333 Text(String),
334 Bytes(Vec<u8>),
335 }
336
337 impl From<Physical<'_>> for Owned {
338 fn from(v: Physical<'_>) -> Self {
339 match v {
340 Physical::Null => Owned::Null,
341 Physical::Bool(b) => Owned::Bool(b),
342 Physical::Int(i) => Owned::Int(i),
343 Physical::Float(f) => Owned::Float(f),
344 Physical::Text(s) => Owned::Text(s.to_owned()),
345 Physical::Bytes(b) => Owned::Bytes(b.to_vec()),
346 }
347 }
348 }
349
350 #[derive(Debug)]
351 pub struct RecordError(pub String);
352
353 impl Error for RecordError {
354 fn source(error: SourceError) -> Self {
355 Self(error.to_string())
356 }
357 }
358
359 /// Records into a shared log. `Ok` is `()`.
360 pub struct Record<'l>(pub &'l mut Vec<Event>);
361
362 impl Sink for Record<'_> {
363 type Ok = ();
364 type Error = RecordError;
365 type Seq = Self;
366 type Map = Self;
367
368 fn scalar(self, ty: Option<Logical>, value: Physical<'_>) -> Result<(), RecordError> {
369 self.0.push(Event::Scalar(ty, value.into()));
370 Ok(())
371 }
372
373 fn typed_null(self, ty: FixedType) -> Result<(), RecordError> {
374 self.0.push(Event::TypedNull(ty));
375 Ok(())
376 }
377
378 fn seq(self, len: Option<usize>) -> Result<Self, RecordError> {
379 self.0.push(Event::Seq(len));
380 Ok(self)
381 }
382
383 fn map(self, len: Option<usize>) -> Result<Self, RecordError> {
384 self.0.push(Event::Map(len));
385 Ok(self)
386 }
387
388 fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<(), RecordError> {
389 self.0.push(Event::Passthrough);
390 value.visit(Record(self.0))
391 }
392 }
393
394 impl SeqSink for Record<'_> {
395 type Ok = ();
396 type Error = RecordError;
397 type Element<'s>
398 = Record<'s>
399 where
400 Self: 's;
401
402 fn element(&mut self) -> Result<Record<'_>, RecordError> {
403 self.0.push(Event::Element);
404 Ok(Record(self.0))
405 }
406
407 fn end(self) -> Result<(), RecordError> {
408 self.0.push(Event::EndSeq);
409 Ok(())
410 }
411 }
412
413 impl MapSink for Record<'_> {
414 type Ok = ();
415 type Error = RecordError;
416 type Entry<'s>
417 = Record<'s>
418 where
419 Self: 's;
420
421 fn entry(&mut self, key: &str) -> Result<Record<'_>, RecordError> {
422 self.0.push(Event::Entry(key.to_owned()));
423 Ok(Record(self.0))
424 }
425
426 fn end(self) -> Result<(), RecordError> {
427 self.0.push(Event::EndMap);
428 Ok(())
429 }
430 }
431
432 /// Walk `p` and return what a sink would have seen.
433 pub fn record<P: Encrypt>(p: P) -> Result<Vec<Event>, RecordError> {
434 let mut log = Vec::new();
435 p.visit(Record(&mut log))?;
436 Ok(log)
437 }
438}