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);