Skip to main content

miden_protobuf/
message.rs

1use core::error::Error;
2
3use crate::ConversionError;
4
5/// Extracts an infallible result without introducing a potential panic.
6///
7/// ```
8/// use core::convert::Infallible;
9///
10/// use miden_protobuf::unwrap_infallible;
11///
12/// assert_eq!(unwrap_infallible(Ok::<_, Infallible>(42)), 42);
13/// ```
14///
15/// Fallible results are rejected at compile time:
16///
17/// ```compile_fail,E0308
18/// use miden_protobuf::unwrap_infallible;
19///
20/// unwrap_infallible("42".parse::<u32>());
21/// ```
22pub fn unwrap_infallible<T>(result: Result<T, core::convert::Infallible>) -> T {
23    match result {
24        Ok(value) => value,
25        Err(impossible) => match impossible {},
26    }
27}
28
29/// Decodes a wire message or oneof without constructing its verified domain counterpart.
30///
31/// Derived implementations produce schema-shaped records. Atomic messages can select an existing
32/// deserialized type instead, using its `TryFrom` implementation. Such adapters should check the
33/// representation only, leaving application invariants to [`Verify`] or [`VerifyWith`].
34pub trait DecodeMessage: Sized {
35    type Decoded: TryFrom<Self, Error = ConversionError>;
36
37    fn decode_fields(self) -> Result<Self::Decoded, ConversionError> {
38        self.try_into()
39    }
40}
41
42/// The decoded representation of a **wire message or oneof** `P`, not its verified domain
43/// counterpart.
44pub type Decoded<P> = <P as DecodeMessage>::Decoded;
45
46/// Checks domain invariants and constructs the verified type using ordinary Rust.
47///
48/// Verification errors belong to the domain. Unlike decoding errors, their field paths are not
49/// generated: cross-field checks need not correspond to a single wire field.
50/// Types that require external context can implement [`VerifyWith`] instead.
51pub trait Verify: Sized {
52    type Verified;
53    type Error: Error + Send + Sync + 'static;
54
55    fn verify(self) -> Result<Self::Verified, Self::Error>;
56}
57
58/// Checks domain invariants using caller-supplied context and constructs the verified type.
59///
60/// Context can be borrowed, such as a trusted parent header, or owned, such as a security level.
61/// Use a named context struct when verification needs several inputs. Implementations must
62/// document any trust requirements on the context.
63///
64/// This capability is independent of [`Verify`]: implementing it does not provide context-free
65/// verification. As with [`Verify`], errors belong to the domain and do not receive generated
66/// wire paths. Implementations are handwritten; decoding does not invoke verification.
67pub trait VerifyWith<C>: Sized {
68    type Verified;
69    type Error: Error + Send + Sync + 'static;
70
71    fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error>;
72}
73
74/// Constructs a domain object from decoded fields while skipping selected verification checks.
75///
76/// This is an explicit, handwritten capability, independent of [`Verify`] and [`VerifyWith`].
77/// Implement it only where the domain API supports unchecked construction. Construction can still
78/// fail on remaining checks or conversions; use [`core::convert::Infallible`] when it cannot fail.
79///
80/// # Warning
81///
82/// Implementations must document precisely which checks are skipped, including nested checks,
83/// and which invariants callers must ensure. The output is not guaranteed to be verified. This
84/// operation must not bypass wire decoding checks or silently discard verification errors.
85/// Skipping domain validation alone does not make this a Rust `unsafe` operation.
86pub trait BuildUnchecked: Sized {
87    type Output;
88    type Error: Error + Send + Sync + 'static;
89
90    fn build_unchecked(self) -> Result<Self::Output, Self::Error>;
91}