Skip to main content

oasis_cbor/
encode.rs

1//! CBOR encoding.
2use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
3
4use impl_trait_for_tuples::impl_for_tuples;
5
6use crate::{SimpleValue, Value};
7
8/// Trait for types that can be encoded into CBOR.
9pub trait Encode {
10    /// Whether the value is equal to the empty value for the type.
11    fn is_empty(&self) -> bool {
12        false
13    }
14
15    /// Encode the type into a CBOR Value.
16    fn into_cbor_value(self) -> Value;
17}
18
19/// Trait for types that always encode as CBOR maps.
20pub trait EncodeAsMap: Encode {
21    /// Encode the type into a CBOR Map.
22    fn into_cbor_value_map(self) -> Value
23    where
24        Self: Sized,
25    {
26        self.into_cbor_value()
27    }
28
29    /// Encode the type into a CBOR Map, returning the map items.
30    fn into_cbor_map(self) -> Vec<(Value, Value)>
31    where
32        Self: Sized,
33    {
34        match self.into_cbor_value() {
35            Value::Map(items) => items,
36            _ => vec![],
37        }
38    }
39}
40
41#[impl_for_tuples(1, 10)]
42impl Encode for Tuple {
43    fn is_empty(&self) -> bool {
44        for_tuples!( #( Tuple.is_empty() )&* );
45    }
46
47    #[allow(clippy::vec_init_then_push)]
48    fn into_cbor_value(self) -> Value {
49        let mut values = vec![];
50        for_tuples!( #( values.push(Tuple.into_cbor_value()); )* );
51        Value::Array(values)
52    }
53}
54
55macro_rules! impl_uint {
56    ($name:ty) => {
57        impl Encode for $name {
58            fn is_empty(&self) -> bool {
59                *self == 0
60            }
61
62            fn into_cbor_value(self) -> Value {
63                Value::Unsigned(self as u64)
64            }
65        }
66
67        impl Encode for &$name {
68            fn is_empty(&self) -> bool {
69                **self == 0
70            }
71
72            fn into_cbor_value(self) -> Value {
73                Encode::into_cbor_value(*self)
74            }
75        }
76    };
77}
78
79macro_rules! impl_int {
80    ($name:ty) => {
81        impl Encode for $name {
82            fn is_empty(&self) -> bool {
83                *self == 0
84            }
85
86            fn into_cbor_value(self) -> Value {
87                Value::integer(self as i64)
88            }
89        }
90
91        impl Encode for &$name {
92            fn is_empty(&self) -> bool {
93                **self == 0
94            }
95
96            fn into_cbor_value(self) -> Value {
97                Encode::into_cbor_value(*self)
98            }
99        }
100    };
101}
102
103impl_uint!(u8);
104impl_uint!(u16);
105impl_uint!(u32);
106impl_uint!(u64);
107impl_int!(i8);
108impl_int!(i16);
109impl_int!(i32);
110impl_int!(i64);
111
112impl Encode for u128 {
113    fn is_empty(&self) -> bool {
114        *self == 0
115    }
116
117    fn into_cbor_value(self) -> Value {
118        Value::ByteString(self.to_be_bytes()[self.leading_zeros() as usize / 8..].to_vec())
119    }
120}
121
122impl Encode for &u128 {
123    fn is_empty(&self) -> bool {
124        **self == 0
125    }
126
127    fn into_cbor_value(self) -> Value {
128        Encode::into_cbor_value(*self)
129    }
130}
131
132impl Encode for bool {
133    fn is_empty(&self) -> bool {
134        !*self
135    }
136
137    fn into_cbor_value(self) -> Value {
138        if self {
139            Value::Simple(SimpleValue::TrueValue)
140        } else {
141            Value::Simple(SimpleValue::FalseValue)
142        }
143    }
144}
145
146impl Encode for String {
147    fn is_empty(&self) -> bool {
148        String::is_empty(self)
149    }
150
151    fn into_cbor_value(self) -> Value {
152        Value::TextString(self)
153    }
154}
155
156impl Encode for &str {
157    fn is_empty(&self) -> bool {
158        str::is_empty(self)
159    }
160
161    fn into_cbor_value(self) -> Value {
162        Value::TextString(self.to_string())
163    }
164}
165
166impl Encode for char {
167    fn into_cbor_value(self) -> Value {
168        Value::Unsigned(self as u64)
169    }
170    fn is_empty(&self) -> bool {
171        *self == '\x00'
172    }
173}
174
175impl<T: Encode> Encode for Vec<T> {
176    default fn is_empty(&self) -> bool {
177        Vec::is_empty(self)
178    }
179
180    default fn into_cbor_value(self) -> Value {
181        Value::Array(self.into_iter().map(Encode::into_cbor_value).collect())
182    }
183}
184
185impl Encode for Vec<u8> {
186    fn into_cbor_value(self) -> Value {
187        Value::ByteString(self)
188    }
189}
190
191impl<T: Encode, const N: usize> Encode for [T; N] {
192    default fn into_cbor_value(self) -> Value {
193        Value::Array(
194            IntoIterator::into_iter(self)
195                .map(Encode::into_cbor_value)
196                .collect(),
197        )
198    }
199}
200
201impl<const N: usize> Encode for [u8; N] {
202    fn into_cbor_value(self) -> Value {
203        Value::ByteString(self.into())
204    }
205}
206
207impl<T: Encode> Encode for Option<T> {
208    fn is_empty(&self) -> bool {
209        self.is_none()
210    }
211
212    fn into_cbor_value(self) -> Value {
213        match self {
214            Some(v) => Encode::into_cbor_value(v),
215            None => Value::Simple(SimpleValue::NullValue),
216        }
217    }
218}
219
220impl Encode for Value {
221    fn is_empty(&self) -> bool {
222        matches!(
223            self,
224            Value::Simple(SimpleValue::NullValue | SimpleValue::Undefined)
225        )
226    }
227
228    fn into_cbor_value(self) -> Value {
229        self
230    }
231}
232
233impl<K: Encode, V: Encode> Encode for BTreeMap<K, V> {
234    fn is_empty(&self) -> bool {
235        BTreeMap::is_empty(self)
236    }
237
238    fn into_cbor_value(self) -> Value {
239        Value::Map(
240            self.into_iter()
241                .map(|(k, v)| (k.into_cbor_value(), v.into_cbor_value()))
242                .collect(),
243        )
244    }
245}
246
247impl<K: Encode, V: Encode> EncodeAsMap for BTreeMap<K, V> {}
248
249impl<V: Encode> Encode for BTreeSet<V> {
250    fn is_empty(&self) -> bool {
251        BTreeSet::is_empty(self)
252    }
253
254    fn into_cbor_value(self) -> Value {
255        Value::Array(self.into_iter().map(Encode::into_cbor_value).collect())
256    }
257}
258
259impl<K: Encode, V: Encode> Encode for HashMap<K, V> {
260    fn is_empty(&self) -> bool {
261        HashMap::is_empty(self)
262    }
263
264    fn into_cbor_value(self) -> Value {
265        Value::Map(
266            self.into_iter()
267                .map(|(k, v)| (k.into_cbor_value(), v.into_cbor_value()))
268                .collect(),
269        )
270    }
271}
272
273impl<K: Encode, V: Encode> EncodeAsMap for HashMap<K, V> {}
274
275impl<V: Encode> Encode for HashSet<V> {
276    fn is_empty(&self) -> bool {
277        HashSet::is_empty(self)
278    }
279
280    fn into_cbor_value(self) -> Value {
281        Value::Array(self.into_iter().map(Encode::into_cbor_value).collect())
282    }
283}
284
285impl Encode for () {
286    fn is_empty(&self) -> bool {
287        true
288    }
289
290    fn into_cbor_value(self) -> Value {
291        Value::Simple(SimpleValue::NullValue)
292    }
293}