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