bc_envelope/base/
envelope_encodable.rs

1use std::collections::{HashMap, HashSet};
2
3#[cfg(any(feature = "encrypt", feature = "compress"))]
4use anyhow::{Error, Result};
5#[cfg(feature = "compress")]
6use bc_components::Compressed;
7#[cfg(feature = "encrypt")]
8use bc_components::EncryptedMessage;
9use bc_components::{
10    Digest, EncryptedKey, PrivateKeyBase, PrivateKeys, PublicKeys, Reference, SSKRShare, Salt, SealedMessage, Signature, ARID, URI, UUID, XID
11};
12use dcbor::prelude::*;
13
14use crate::{Assertion, Envelope};
15
16/// A trait for types that can be encoded as a Gordian Envelope.
17///
18/// This trait defines the interface for converting a value into an envelope.
19/// Types implementing this trait can be used directly with envelope construction
20/// functions without explicit conversion.
21///
22/// There are numerous built-in implementations for common types including:
23/// - Primitive types (numbers, strings, booleans)
24/// - CBOR values
25/// - Cryptographic types from `bc-components` (digests, keys, etc.)
26/// - Assertions
27/// - Other envelopes
28///
29/// # Example
30///
31/// ```
32/// # use bc_envelope::prelude::*;
33///
34/// // String implements EnvelopeEncodable
35/// let e1 = "Hello".into_envelope();
36///
37/// // Numbers implement EnvelopeEncodable
38/// let e2 = 42.into_envelope();
39///
40/// // Using in envelope construction
41/// let envelope = Envelope::new("subject")
42///     .add_assertion("name", "Alice")  // Uses EnvelopeEncodable for both predicate and object
43///     .add_assertion("age", 30);       // Uses EnvelopeEncodable for the numeric object
44/// ```
45pub trait EnvelopeEncodable {
46    /// Converts this value into a Gordian Envelope.
47    ///
48    /// This is the core method of the trait, converting the implementing type
49    /// into an envelope representation. Most implementations will convert the
50    /// value to a leaf envelope containing the value.
51    ///
52    /// # Returns
53    ///
54    /// A new envelope containing the value.
55    fn into_envelope(self) -> Envelope;
56
57    /// Converts a reference to this value into a Gordian Envelope.
58    ///
59    /// This is a convenience method that clones the value before converting it.
60    /// It is implemented automatically for any type that implements `Clone`.
61    ///
62    /// # Returns
63    ///
64    /// A new envelope containing a clone of the value.
65    fn to_envelope(&self) -> Envelope
66    where
67        Self: Clone,
68    {
69        self.clone().into_envelope()
70    }
71}
72
73/// Generic implementation for any type that can be converted into an Envelope.
74///
75/// This implementation allows any type that implements `Into<Envelope>` to
76/// automatically implement `EnvelopeEncodable`. This is a powerful way to
77/// provide envelope encoding capabilities to a wide range of types.
78impl<T> EnvelopeEncodable for T
79where
80    T: Into<Envelope> + Clone,
81{
82    /// Converts the value into an envelope by using its `Into<Envelope>` implementation.
83    fn into_envelope(self) -> Envelope {
84        self.into()
85    }
86}
87
88/// Implementation of `EnvelopeEncodable` for `Assertion`.
89///
90/// This implementation converts an assertion into an envelope with the assertion
91/// as its subject.
92impl EnvelopeEncodable for Assertion {
93    /// Creates an envelope with this assertion as its subject.
94    fn into_envelope(self) -> Envelope {
95        Envelope::new_with_assertion(self)
96    }
97}
98
99/// TryFrom implementation to convert an encrypted message into an envelope.
100///
101/// This conversion is only available when the `encrypt` feature is enabled.
102#[cfg(feature = "encrypt")]
103impl TryFrom<EncryptedMessage> for Envelope {
104    type Error = Error;
105
106    /// Attempts to create an envelope with an encrypted message as its subject.
107    ///
108    /// This uses the specialized envelope constructor for encrypted content.
109    fn try_from(value: EncryptedMessage) -> Result<Self> {
110        Envelope::new_with_encrypted(value)
111    }
112}
113
114/// TryFrom implementation to convert compressed data into an envelope.
115///
116/// This conversion is only available when the `compress` feature is enabled.
117#[cfg(feature = "compress")]
118impl TryFrom<Compressed> for Envelope {
119    type Error = Error;
120
121    /// Attempts to create an envelope with compressed data as its subject.
122    ///
123    /// This uses the specialized envelope constructor for compressed content.
124    fn try_from(compressed: Compressed) -> Result<Self> {
125        Envelope::new_with_compressed(compressed)
126    }
127}
128
129/// Implementation of `EnvelopeEncodable` for `CBOR`.
130///
131/// This allows CBOR values to be directly encoded as envelope leaf nodes.
132impl EnvelopeEncodable for CBOR {
133    /// Creates a leaf envelope containing this CBOR value.
134    fn into_envelope(self) -> Envelope {
135        Envelope::new_leaf(self)
136    }
137}
138
139/// Implementation of `EnvelopeEncodable` for `String`.
140///
141/// This allows Rust strings to be directly encoded as envelope leaf nodes.
142impl EnvelopeEncodable for String {
143    /// Creates a leaf envelope containing this string.
144    fn into_envelope(self) -> Envelope {
145        Envelope::new_leaf(self)
146    }
147}
148
149/// Implementation of `EnvelopeEncodable` for `&str`.
150///
151/// This allows string slices to be directly encoded as envelope leaf nodes.
152impl EnvelopeEncodable for &str {
153    /// Creates a leaf envelope containing this string slice.
154    fn into_envelope(self) -> Envelope {
155        Envelope::new_leaf(self)
156    }
157}
158
159impl<T> EnvelopeEncodable for Vec<T>
160where
161    T: CBOREncodable,
162{
163    fn into_envelope(self) -> Envelope {
164        Envelope::new(CBOR::from(self))
165    }
166}
167
168impl<K, V> EnvelopeEncodable for HashMap<K, V>
169where
170    K: CBOREncodable,
171    V: CBOREncodable,
172{
173    fn into_envelope(self) -> Envelope {
174        Envelope::new(CBOR::from(self))
175    }
176}
177
178impl<T> EnvelopeEncodable for HashSet<T>
179where
180    T: CBOREncodable,
181{
182    fn into_envelope(self) -> Envelope {
183        Envelope::new(CBOR::from(self))
184    }
185}
186
187impl EnvelopeEncodable for Map {
188    fn into_envelope(self) -> Envelope {
189        Envelope::new(CBOR::from(self))
190    }
191}
192
193impl EnvelopeEncodable for Set {
194    fn into_envelope(self) -> Envelope {
195        Envelope::new(CBOR::from(self))
196    }
197}
198
199/// Macro for implementing `EnvelopeEncodable` for a series of types.
200///
201/// This macro generates implementations that convert values to leaf envelopes.
202/// It's used to reduce repetition when implementing for primitive types and
203/// common data structures.
204macro_rules! impl_envelope_encodable {
205    ($type:ty) => {
206        impl From<$type> for Envelope {
207            /// Converts this value into an envelope.
208            fn from(value: $type) -> Self {
209                Envelope::new_leaf(value)
210            }
211        }
212    };
213}
214
215// Numeric types
216impl_envelope_encodable!(u8);
217impl_envelope_encodable!(u16);
218impl_envelope_encodable!(u32);
219impl_envelope_encodable!(u64);
220impl_envelope_encodable!(usize);
221impl_envelope_encodable!(i8);
222impl_envelope_encodable!(i16);
223impl_envelope_encodable!(i32);
224impl_envelope_encodable!(i64);
225
226// Boolean type
227impl_envelope_encodable!(bool);
228
229// Floating point types
230impl_envelope_encodable!(f64);
231impl_envelope_encodable!(f32);
232
233// CBOR types
234impl_envelope_encodable!(dcbor::ByteString);
235impl_envelope_encodable!(dcbor::Date);
236
237// Cryptographic types
238impl_envelope_encodable!(PublicKeys);
239impl_envelope_encodable!(PrivateKeys);
240impl_envelope_encodable!(PrivateKeyBase);
241impl_envelope_encodable!(SealedMessage);
242impl_envelope_encodable!(EncryptedKey);
243impl_envelope_encodable!(Signature);
244impl_envelope_encodable!(SSKRShare);
245impl_envelope_encodable!(Digest);
246impl_envelope_encodable!(Salt);
247
248// Identifier types
249impl_envelope_encodable!(ARID);
250impl_envelope_encodable!(URI);
251impl_envelope_encodable!(UUID);
252impl_envelope_encodable!(XID);
253impl_envelope_encodable!(Reference);