#[non_exhaustive]pub enum ContextPiece<'a> {
}Expand description
One part of a context, or a list of parts.
IntoContext::into_context builds
one from any context type, and encode turns it into the
bytes both the AEAD and the PRF use. The tree is a stand-in for the value
it was built from: a runtime list with the same parts is the same context
as the static value, on both sides, because there is only one encoding.
use std::borrow::Cow;
use vitaminc_context::{ContextPiece, IntoContext};
let value = ("users/email", 7u64);
let runtime = ContextPiece::List(vec![
ContextPiece::Text(Cow::Borrowed("users/email")),
ContextPiece::U64(7),
]);
assert_eq!(runtime.encode(), value.into_context().encode());This matters for a context that arrives as data rather than as a Rust type, for example across an FFI boundary. It needs no mirror type of its own:
Some(x)is the one-element list andNoneis the empty list;(a, b)is the two-element list;nonempty!(a).with(b).with(c)is the nested list((a, b), c);()isUnit.
A flat list of three or more parts is also a valid context. It has no
tuple spelling in Rust, so build it with List directly.
Display renders a tree so that different trees never
print the same, for example ("users/email", 7u64), and
leaves walks the parts in encoding order for a caller
that wants to render or bind them itself.
PartialEq compares trees, not encodings, and since every typed leaf is
tagged, trees that differ encode differently too. The one exception is
Encoded: a Bytes leaf and an Encoded leaf holding
that leaf’s encoding are unequal as trees and equal as bytes, which is
what Encoded is for.
MaybeEmpty is implemented by the same rule the static types use, so
a tree can be wrapped in NonEmpty:
text and bytes are empty at zero length, unit is empty, an integer never
is, and a list is empty only when every part is.
Encoded counts as empty whatever its bytes, because
framing hides whether the value behind them carried anything.
The enum is #[non_exhaustive], so a new kind of leaf must not break a
downstream match.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Text(Cow<'a, str>)
Text; a typed leaf of its UTF-8 bytes. &str, String.
Bytes(Cow<'a, [u8]>)
Opaque bytes; a typed leaf of the bytes themselves. Byte slices and
arrays, Vec<u8>, Cow<[u8]>.
Unit
The unit context, (). Encodes as no bytes at all. Not the same as
empty bytes, which are a typed leaf, or the empty list, which is
framed.
U8(u8)
A u8; a typed leaf of one little-endian byte.
U16(u16)
A u16; a typed leaf of two little-endian bytes.
U32(u32)
A u32; a typed leaf of four little-endian bytes.
U64(u64)
A u64; a typed leaf of eight little-endian bytes.
U128(u128)
A u128; a typed leaf of sixteen little-endian bytes.
I8(i8)
An i8; a typed leaf of one two’s-complement byte.
I16(i16)
An i16; a typed leaf of two little-endian two’s-complement bytes.
I32(i32)
An i32; a typed leaf of four little-endian two’s-complement bytes.
I64(i64)
An i64; a typed leaf of eight little-endian two’s-complement bytes.
I128(i128)
An i128; a typed leaf of sixteen little-endian two’s-complement
bytes.
Encoded(Cow<'a, [u8]>)
Bytes this encoder already produced; encodes as itself, untagged. The
parts view of a Context, which is how a stored or derived context
is passed back in as a value. Only Context::from_encoded and the
derived-context methods on Context produce one. It counts as
empty whatever its bytes, because framing hides
whether the value behind them carried anything.
List(Vec<ContextPiece<'a>>)
A list of parts; encodes as their PAE. A tuple is the list of its
halves, Some(x) the one-element list, None the empty list.
Implementations§
Source§impl<'a> ContextPiece<'a>
impl<'a> ContextPiece<'a>
Sourcepub fn encode(self) -> Context<'a>
pub fn encode(self) -> Context<'a>
The canonical bytes of this context.
A typed leaf and a list allocate exactly once, sized up front. Unit
allocates nothing. Encoded hands its bytes through as they are, so
a borrowed encoded context stays borrowed.
Sourcepub fn into_owned(self) -> ContextPiece<'static>
pub fn into_owned(self) -> ContextPiece<'static>
Copy every borrowed part, so the tree can outlive its source.
Sourcepub fn leaves(&self) -> impl Iterator<Item = &ContextPiece<'a>>
pub fn leaves(&self) -> impl Iterator<Item = &ContextPiece<'a>>
The non-list parts, depth first, in the order they are encoded. A leaf piece yields itself; an empty list yields nothing.
Nesting is dropped, so distinct contexts can share a leaf sequence:
(("a", 1u8), "b") and ("a", (1u8, "b")) both yield a, 1, b
while encoding to different bytes. Use this to render or bind the
parts, not to identify the context; the bytes from
encode are its identity.
Trait Implementations§
Source§impl<'a> Clone for ContextPiece<'a>
impl<'a> Clone for ContextPiece<'a>
Source§fn clone(&self) -> ContextPiece<'a>
fn clone(&self) -> ContextPiece<'a>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<'a> Debug for ContextPiece<'a>
impl<'a> Debug for ContextPiece<'a>
Source§impl Display for ContextPiece<'_>
Renders the tree in Rust literal syntax, and different trees never
render the same. Text is quoted and escaped as Debug does, integers
carry their type suffix, bytes print as 0x-prefixed hex, encoded bytes
print as Encoded(0x…), unit prints as (), a list is parenthesised and
comma-separated, and the empty list prints as None (the context it
is). So ("users/email", 7u64) prints as ("users/email", 7u64).
impl Display for ContextPiece<'_>
Renders the tree in Rust literal syntax, and different trees never
render the same. Text is quoted and escaped as Debug does, integers
carry their type suffix, bytes print as 0x-prefixed hex, encoded bytes
print as Encoded(0x…), unit prints as (), a list is parenthesised and
comma-separated, and the empty list prints as None (the context it
is). So ("users/email", 7u64) prints as ("users/email", 7u64).
Each kind starts differently: " for text, a digit or - for an
integer, 0x for bytes, E for encoded bytes, () for unit, (
followed by a part for a list, and None for the empty list. Integer
suffixes keep types of the same width apart, and quoting keeps
separators inside text from reading as structure. Two contexts that
encode to different bytes therefore never share a log line.
impl<'a> Eq for ContextPiece<'a>
Source§impl<'a> IntoContext<'a> for ContextPiece<'a>
The tree of a tree is itself.
impl<'a> IntoContext<'a> for ContextPiece<'a>
The tree of a tree is itself.
Source§fn into_context(self) -> ContextPiece<'a>
fn into_context(self) -> ContextPiece<'a>
self as a tree of parts.Source§impl MaybeEmpty for ContextPiece<'_>
The same emptiness rule the static types use, applied to the tree. Text
and bytes are empty at zero length. Unit is empty. An integer is never
empty, because even zero is information the caller chose. A list is
empty only when every part is, so None and Some("") are empty and
("", 7u64) is not, matching what Option<T> and (A, B) decide.
impl MaybeEmpty for ContextPiece<'_>
The same emptiness rule the static types use, applied to the tree. Text
and bytes are empty at zero length. Unit is empty. An integer is never
empty, because even zero is information the caller chose. A list is
empty only when every part is, so None and Some("") are empty and
("", 7u64) is not, matching what Option<T> and (A, B) decide.
An Encoded leaf counts as empty whatever its
bytes, because those bytes cannot say whether the value behind them
carried anything: framing gives an empty value a non-empty encoding, so
None arrives back as an eight-byte count word and a byte check would
certify exactly the degenerate context NonEmpty
exists to exclude.
It is the same reason Context has no MaybeEmpty impl of its own.
An encoded context therefore never contributes to a proof: prove the
value non-empty before it is encoded, or extend a proven head with
NonEmpty::with, which pairs a
tail in without checking it.