• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Types and macros for communication between HAL and TA
2 
3 #![no_std]
4 extern crate alloc;
5 
6 use alloc::{
7     format,
8     string::{String, ToString},
9     vec::Vec,
10 };
11 use coset::TaggedCborSerializable;
12 
13 /// Re-export of crate used for CBOR encoding.
14 pub use ciborium as cbor;
15 /// Re-export of crate used for COSE encoding.
16 pub use coset;
17 
18 pub mod keymint;
19 pub mod legacy;
20 pub mod rpc;
21 pub mod secureclock;
22 pub mod sharedsecret;
23 pub mod types;
24 pub use types::*;
25 
26 #[cfg(test)]
27 mod tests;
28 
29 /// Macro that emits an implementation of `TryFrom<i32>` for an enum type that has
30 /// `[derive(N)]` attached to it.
31 #[macro_export]
32 macro_rules! try_from_n {
33     { $ename:ident } => {
34         impl core::convert::TryFrom<i32> for $ename {
35             type Error = $crate::ValueNotRecognized;
36             fn try_from(value: i32) -> Result<Self, Self::Error> {
37                 Self::n(value).ok_or($crate::ValueNotRecognized)
38             }
39         }
40     };
41 }
42 
43 /// Function that mimics `vec![<val>; <len>]` but which detects allocation failure with the given
44 /// error.
vec_try_fill_with_alloc_err<T: Clone, E>( elem: T, len: usize, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>45 pub fn vec_try_fill_with_alloc_err<T: Clone, E>(
46     elem: T,
47     len: usize,
48     alloc_err: fn() -> E,
49 ) -> Result<Vec<T>, E> {
50     let mut v = alloc::vec::Vec::new();
51     v.try_reserve(len).map_err(|_e| alloc_err())?;
52     v.resize(len, elem);
53     Ok(v)
54 }
55 
56 /// Function that mimics `vec![x1, x2, x3, x4]` but which detects allocation failure with the given
57 /// error.
vec_try4_with_alloc_err<T: Clone, E>( x1: T, x2: T, x3: T, x4: T, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>58 pub fn vec_try4_with_alloc_err<T: Clone, E>(
59     x1: T,
60     x2: T,
61     x3: T,
62     x4: T,
63     alloc_err: fn() -> E,
64 ) -> Result<Vec<T>, E> {
65     let mut v = alloc::vec::Vec::new();
66     match v.try_reserve(4) {
67         Err(_e) => Err(alloc_err()),
68         Ok(_) => {
69             v.push(x1);
70             v.push(x2);
71             v.push(x3);
72             v.push(x4);
73             Ok(v)
74         }
75     }
76 }
77 
78 /// Function that mimics `vec![x1, x2, x3]` but which detects allocation failure with the given
79 /// error.
vec_try3_with_alloc_err<T: Clone, E>( x1: T, x2: T, x3: T, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>80 pub fn vec_try3_with_alloc_err<T: Clone, E>(
81     x1: T,
82     x2: T,
83     x3: T,
84     alloc_err: fn() -> E,
85 ) -> Result<Vec<T>, E> {
86     let mut v = alloc::vec::Vec::new();
87     match v.try_reserve(3) {
88         Err(_e) => Err(alloc_err()),
89         Ok(_) => {
90             v.push(x1);
91             v.push(x2);
92             v.push(x3);
93             Ok(v)
94         }
95     }
96 }
97 
98 /// Function that mimics `vec![x1, x2]` but which detects allocation failure with the given error.
vec_try2_with_alloc_err<T: Clone, E>( x1: T, x2: T, alloc_err: fn() -> E, ) -> Result<Vec<T>, E>99 pub fn vec_try2_with_alloc_err<T: Clone, E>(
100     x1: T,
101     x2: T,
102     alloc_err: fn() -> E,
103 ) -> Result<Vec<T>, E> {
104     let mut v = alloc::vec::Vec::new();
105     match v.try_reserve(2) {
106         Err(_e) => Err(alloc_err()),
107         Ok(_) => {
108             v.push(x1);
109             v.push(x2);
110             Ok(v)
111         }
112     }
113 }
114 
115 /// Function that mimics `vec![x1]` but which detects allocation failure with the given error.
vec_try1_with_alloc_err<T: Clone, E>(x1: T, alloc_err: fn() -> E) -> Result<Vec<T>, E>116 pub fn vec_try1_with_alloc_err<T: Clone, E>(x1: T, alloc_err: fn() -> E) -> Result<Vec<T>, E> {
117     let mut v = alloc::vec::Vec::new();
118     match v.try_reserve(1) {
119         Err(_e) => Err(alloc_err()),
120         Ok(_) => {
121             v.push(x1);
122             Ok(v)
123         }
124     }
125 }
126 
127 /// Macro that mimics `vec!` but which detects allocation failure.
128 #[macro_export]
129 macro_rules! vec_try {
130     { $elem:expr ; $len:expr } => {
131         $crate::vec_try_fill_with_alloc_err($elem, $len, || $crate::CborError::AllocationFailed)
132     };
133     { $x1:expr, $x2:expr, $x3:expr, $x4:expr $(,)? } => {
134         $crate::vec_try4_with_alloc_err($x1, $x2, $x3, $x4, || $crate::CborError::AllocationFailed)
135     };
136     { $x1:expr, $x2:expr, $x3:expr $(,)? } => {
137         $crate::vec_try3_with_alloc_err($x1, $x2, $x3, || $crate::CborError::AllocationFailed)
138     };
139     { $x1:expr, $x2:expr $(,)? } => {
140         $crate::vec_try2_with_alloc_err($x1, $x2, || $crate::CborError::AllocationFailed)
141     };
142     { $x1:expr $(,)? } => {
143         $crate::vec_try1_with_alloc_err($x1, || $crate::CborError::AllocationFailed)
144     };
145 }
146 
147 /// Marker structure indicating that the EOF was encountered when reading CBOR data.
148 #[derive(Debug)]
149 pub struct EndOfFile;
150 
151 /// Error type for failures in encoding or decoding CBOR types.
152 pub enum CborError {
153     /// CBOR decoding failure.
154     DecodeFailed(cbor::de::Error<EndOfFile>),
155     /// CBOR encoding failure.
156     EncodeFailed,
157     /// CBOR input had extra data.
158     ExtraneousData,
159     /// Integer value outside expected range.
160     OutOfRangeIntegerValue,
161     /// Integer value that doesn't match expected set of allowed enum values.
162     NonEnumValue,
163     /// Unexpected CBOR item encountered (got, want).
164     UnexpectedItem(&'static str, &'static str),
165     /// Value conversion failure.
166     InvalidValue,
167     /// Allocation failure.
168     AllocationFailed,
169 }
170 
171 // Can only implement `Into` due to orphan trait rule.
172 #[allow(clippy::from_over_into)]
173 impl Into<coset::CoseError> for CborError {
into(self) -> coset::CoseError174     fn into(self) -> coset::CoseError {
175         match self {
176             CborError::DecodeFailed(inner) => coset::CoseError::DecodeFailed(match inner {
177                 cbor::de::Error::Io(_io) => cbor::de::Error::Io(coset::EndOfFile),
178                 cbor::de::Error::Syntax(v) => cbor::de::Error::Syntax(v),
179                 cbor::de::Error::Semantic(sz, msg) => cbor::de::Error::Semantic(sz, msg),
180                 cbor::de::Error::RecursionLimitExceeded => cbor::de::Error::RecursionLimitExceeded,
181             }),
182             CborError::EncodeFailed => coset::CoseError::EncodeFailed,
183             CborError::ExtraneousData => coset::CoseError::ExtraneousData,
184             CborError::OutOfRangeIntegerValue => coset::CoseError::OutOfRangeIntegerValue,
185             CborError::NonEnumValue => coset::CoseError::OutOfRangeIntegerValue,
186             CborError::UnexpectedItem(got, want) => coset::CoseError::UnexpectedItem(got, want),
187             CborError::InvalidValue => coset::CoseError::EncodeFailed,
188             CborError::AllocationFailed => coset::CoseError::EncodeFailed,
189         }
190     }
191 }
192 
193 impl<T> From<cbor::de::Error<T>> for CborError {
from(e: cbor::de::Error<T>) -> Self194     fn from(e: cbor::de::Error<T>) -> Self {
195         // Make sure we use our [`EndOfFile`] marker.
196         use cbor::de::Error::{Io, RecursionLimitExceeded, Semantic, Syntax};
197         let e = match e {
198             Io(_) => Io(EndOfFile),
199             Syntax(x) => Syntax(x),
200             Semantic(a, b) => Semantic(a, b),
201             RecursionLimitExceeded => RecursionLimitExceeded,
202         };
203         CborError::DecodeFailed(e)
204     }
205 }
206 
207 impl<T> From<cbor::ser::Error<T>> for CborError {
from(_e: cbor::ser::Error<T>) -> Self208     fn from(_e: cbor::ser::Error<T>) -> Self {
209         CborError::EncodeFailed
210     }
211 }
212 
213 impl From<cbor::value::Error> for CborError {
from(_e: cbor::value::Error) -> Self214     fn from(_e: cbor::value::Error) -> Self {
215         CborError::InvalidValue
216     }
217 }
218 
219 impl From<core::num::TryFromIntError> for CborError {
from(_: core::num::TryFromIntError) -> Self220     fn from(_: core::num::TryFromIntError) -> Self {
221         CborError::OutOfRangeIntegerValue
222     }
223 }
224 
225 impl From<coset::CoseError> for CborError {
from(e: coset::CoseError) -> Self226     fn from(e: coset::CoseError) -> Self {
227         match e {
228             coset::CoseError::DecodeFailed(inner) => CborError::DecodeFailed(match inner {
229                 cbor::de::Error::Io(_io) => cbor::de::Error::Io(EndOfFile),
230                 cbor::de::Error::Syntax(v) => cbor::de::Error::Syntax(v),
231                 cbor::de::Error::Semantic(sz, msg) => cbor::de::Error::Semantic(sz, msg),
232                 cbor::de::Error::RecursionLimitExceeded => cbor::de::Error::RecursionLimitExceeded,
233             }),
234             coset::CoseError::EncodeFailed => CborError::EncodeFailed,
235             coset::CoseError::ExtraneousData => CborError::ExtraneousData,
236             coset::CoseError::OutOfRangeIntegerValue => CborError::OutOfRangeIntegerValue,
237             coset::CoseError::UnregisteredIanaValue => CborError::NonEnumValue,
238             coset::CoseError::UnregisteredIanaNonPrivateValue => CborError::NonEnumValue,
239             coset::CoseError::UnexpectedItem(got, want) => CborError::UnexpectedItem(got, want),
240             coset::CoseError::DuplicateMapKey => {
241                 CborError::UnexpectedItem("dup map key", "unique keys")
242             }
243         }
244     }
245 }
246 
247 impl core::fmt::Debug for CborError {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result248     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249         match self {
250             CborError::DecodeFailed(de) => write!(f, "decode CBOR failure: {:?}", de),
251             CborError::EncodeFailed => write!(f, "encode CBOR failure"),
252             CborError::ExtraneousData => write!(f, "extraneous data in CBOR input"),
253             CborError::OutOfRangeIntegerValue => write!(f, "out of range integer value"),
254             CborError::NonEnumValue => write!(f, "integer not a valid enum value"),
255             CborError::UnexpectedItem(got, want) => write!(f, "got {}, expected {}", got, want),
256             CborError::InvalidValue => write!(f, "invalid CBOR value"),
257             CborError::AllocationFailed => write!(f, "allocation failed"),
258         }
259     }
260 }
261 
262 /// Return an error indicating that an unexpected CBOR type was encountered.
cbor_type_error<T>(value: &cbor::value::Value, want: &'static str) -> Result<T, CborError>263 pub fn cbor_type_error<T>(value: &cbor::value::Value, want: &'static str) -> Result<T, CborError> {
264     use cbor::value::Value;
265     let got = match value {
266         Value::Integer(_) => "int",
267         Value::Bytes(_) => "bstr",
268         Value::Text(_) => "tstr",
269         Value::Array(_) => "array",
270         Value::Map(_) => "map",
271         Value::Tag(_, _) => "tag",
272         Value::Float(_) => "float",
273         Value::Bool(_) => "bool",
274         Value::Null => "null",
275         _ => "unknown",
276     };
277     Err(CborError::UnexpectedItem(got, want))
278 }
279 
280 /// Read a [`cbor::value::Value`] from a byte slice, failing if any extra data remains after the
281 /// `Value` has been read.
read_to_value(mut slice: &[u8]) -> Result<cbor::value::Value, CborError>282 pub fn read_to_value(mut slice: &[u8]) -> Result<cbor::value::Value, CborError> {
283     let value = cbor::de::from_reader(&mut slice)?;
284     if slice.is_empty() {
285         Ok(value)
286     } else {
287         Err(CborError::ExtraneousData)
288     }
289 }
290 
291 /// Trait for types that can be converted to/from a [`cbor::value::Value`].
292 pub trait AsCborValue: Sized {
293     /// Convert a [`cbor::value::Value`] into an instance of the type.
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>294     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>;
295 
296     /// Convert the object into a [`cbor::value::Value`], consuming it along the way.
to_cbor_value(self) -> Result<cbor::value::Value, CborError>297     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError>;
298 
299     /// Create an object instance from serialized CBOR data in a slice.
from_slice(slice: &[u8]) -> Result<Self, CborError>300     fn from_slice(slice: &[u8]) -> Result<Self, CborError> {
301         Self::from_cbor_value(read_to_value(slice)?)
302     }
303 
304     /// Serialize this object to a vector, consuming it along the way.
into_vec(self) -> Result<Vec<u8>, CborError>305     fn into_vec(self) -> Result<Vec<u8>, CborError> {
306         let mut data = Vec::new();
307         cbor::ser::into_writer(&self.to_cbor_value()?, &mut data)?;
308         Ok(data)
309     }
310 
311     /// Return the name used for this type in a CDDL schema, or `None` if this type does not have a
312     /// simple CDDL name. (For example, type `Vec<i64>` maps to a schema `(+ int)` but doesn't
313     /// have a name.)
cddl_typename() -> Option<String>314     fn cddl_typename() -> Option<String> {
315         None
316     }
317 
318     /// Return the CDDL schema for this type, or None if this type is primitive (e.g. `int`, `bool`,
319     /// `bstr`).
cddl_schema() -> Option<String>320     fn cddl_schema() -> Option<String> {
321         None
322     }
323 
324     /// Return a way to refer to this type in CDDL; prefer the CDDL type name if available,
325     /// use the explicit schema if not.
cddl_ref() -> String326     fn cddl_ref() -> String {
327         if let Some(item_name) = Self::cddl_typename() {
328             item_name
329         } else if let Some(item_schema) = Self::cddl_schema() {
330             item_schema
331         } else {
332             panic!("type with unknown CDDL")
333         }
334     }
335 }
336 
337 // Implement the local `AsCborValue` trait for `coset::CoseEncrypt0` ensuring/requiring
338 // use of the relevant CBOR tag.
339 impl AsCborValue for coset::CoseEncrypt0 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>340     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
341         match value {
342             cbor::value::Value::Tag(tag, inner_value) if tag == coset::CoseEncrypt0::TAG => {
343                 <coset::CoseEncrypt0 as coset::AsCborValue>::from_cbor_value(*inner_value)
344                     .map_err(|e| e.into())
345             }
346             cbor::value::Value::Tag(_, _) => Err(CborError::UnexpectedItem("tag", "tag 16")),
347             _ => cbor_type_error(&value, "tag 16"),
348         }
349     }
to_cbor_value(self) -> Result<cbor::value::Value, CborError>350     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
351         Ok(cbor::value::Value::Tag(
352             coset::CoseEncrypt0::TAG,
353             alloc::boxed::Box::new(coset::AsCborValue::to_cbor_value(self)?),
354         ))
355     }
cddl_schema() -> Option<String>356     fn cddl_schema() -> Option<String> {
357         Some(format!("#6.{}(Cose_Encrypt0)", coset::CoseEncrypt0::TAG))
358     }
359 }
360 
361 /// An `Option<T>` encodes as `( ? t )`, where `t` is whatever `T` encodes as in CDDL.
362 impl<T: AsCborValue> AsCborValue for Option<T> {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>363     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
364         let mut arr = match value {
365             cbor::value::Value::Array(a) => a,
366             _ => return Err(CborError::UnexpectedItem("non-arr", "arr")),
367         };
368         match arr.len() {
369             0 => Ok(None),
370             1 => Ok(Some(<T>::from_cbor_value(arr.remove(0))?)),
371             _ => Err(CborError::UnexpectedItem("arr len >1", "arr len 0/1")),
372         }
373     }
374 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>375     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
376         match self {
377             Some(t) => Ok(cbor::value::Value::Array(vec_try![t.to_cbor_value()?]?)),
378             None => Ok(cbor::value::Value::Array(Vec::new())),
379         }
380     }
381 
cddl_schema() -> Option<String>382     fn cddl_schema() -> Option<String> {
383         Some(format!("[? {}]", <T>::cddl_ref()))
384     }
385 }
386 
387 /// A `Vec<T>` encodes as `( * t )`, where `t` is whatever `T` encodes as in CDDL.
388 impl<T: AsCborValue> AsCborValue for Vec<T> {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>389     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
390         let arr = match value {
391             cbor::value::Value::Array(a) => a,
392             _ => return cbor_type_error(&value, "arr"),
393         };
394         let results: Result<Vec<_>, _> = arr.into_iter().map(<T>::from_cbor_value).collect();
395         results
396     }
397 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>398     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
399         let values: Result<Vec<_>, _> = self.into_iter().map(|v| v.to_cbor_value()).collect();
400         Ok(cbor::value::Value::Array(values?))
401     }
402 
cddl_schema() -> Option<String>403     fn cddl_schema() -> Option<String> {
404         Some(format!("[* {}]", <T>::cddl_ref()))
405     }
406 }
407 
408 impl AsCborValue for Vec<u8> {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>409     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
410         match value {
411             cbor::value::Value::Bytes(bstr) => Ok(bstr),
412             _ => cbor_type_error(&value, "bstr"),
413         }
414     }
415 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>416     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
417         Ok(cbor::value::Value::Bytes(self))
418     }
419 
cddl_typename() -> Option<String>420     fn cddl_typename() -> Option<String> {
421         Some("bstr".to_string())
422     }
423 }
424 
425 impl<const N: usize> AsCborValue for [u8; N] {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>426     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
427         let data = match value {
428             cbor::value::Value::Bytes(bstr) => bstr,
429             _ => return cbor_type_error(&value, "bstr"),
430         };
431         data.try_into()
432             .map_err(|_e| CborError::UnexpectedItem("bstr other size", "bstr specific size"))
433     }
434 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>435     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
436         let mut v = alloc::vec::Vec::new();
437         if v.try_reserve(self.len()).is_err() {
438             return Err(CborError::AllocationFailed);
439         }
440         v.extend_from_slice(&self);
441         Ok(cbor::value::Value::Bytes(v))
442     }
443 
cddl_typename() -> Option<String>444     fn cddl_typename() -> Option<String> {
445         Some(format!("bstr .size {}", N))
446     }
447 }
448 
449 impl AsCborValue for String {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>450     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
451         match value {
452             cbor::value::Value::Text(s) => Ok(s),
453             _ => cbor_type_error(&value, "tstr"),
454         }
455     }
456 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>457     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
458         Ok(cbor::value::Value::Text(self))
459     }
460 
cddl_typename() -> Option<String>461     fn cddl_typename() -> Option<String> {
462         Some("tstr".to_string())
463     }
464 }
465 
466 impl AsCborValue for u64 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>467     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
468         match value {
469             cbor::value::Value::Integer(i) => {
470                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
471             }
472             v => crate::cbor_type_error(&v, "u64"),
473         }
474     }
475 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>476     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
477         Ok(cbor::value::Value::Integer(self.into()))
478     }
479 
cddl_typename() -> Option<String>480     fn cddl_typename() -> Option<String> {
481         Some("int".to_string())
482     }
483 }
484 
485 impl AsCborValue for i64 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>486     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
487         match value {
488             cbor::value::Value::Integer(i) => {
489                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
490             }
491             v => crate::cbor_type_error(&v, "i64"),
492         }
493     }
494 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>495     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
496         Ok(cbor::value::Value::Integer(self.into()))
497     }
498 
cddl_typename() -> Option<String>499     fn cddl_typename() -> Option<String> {
500         Some("int".to_string())
501     }
502 }
503 
504 impl AsCborValue for u32 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>505     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
506         match value {
507             cbor::value::Value::Integer(i) => {
508                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
509             }
510             v => crate::cbor_type_error(&v, "u32"),
511         }
512     }
513 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>514     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
515         Ok(cbor::value::Value::Integer(self.into()))
516     }
517 
cddl_typename() -> Option<String>518     fn cddl_typename() -> Option<String> {
519         Some("int".to_string())
520     }
521 }
522 
523 impl AsCborValue for bool {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>524     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
525         match value {
526             cbor::value::Value::Bool(b) => Ok(b),
527             v => crate::cbor_type_error(&v, "bool"),
528         }
529     }
to_cbor_value(self) -> Result<cbor::value::Value, CborError>530     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
531         Ok(cbor::value::Value::Bool(self))
532     }
533 
cddl_typename() -> Option<String>534     fn cddl_typename() -> Option<String> {
535         Some("bool".to_string())
536     }
537 }
538 
539 impl AsCborValue for () {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>540     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
541         match value {
542             cbor::value::Value::Null => Ok(()),
543             v => crate::cbor_type_error(&v, "null"),
544         }
545     }
to_cbor_value(self) -> Result<cbor::value::Value, CborError>546     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
547         Ok(cbor::value::Value::Null)
548     }
549 
cddl_typename() -> Option<String>550     fn cddl_typename() -> Option<String> {
551         Some("null".to_string())
552     }
553 }
554 
555 impl AsCborValue for i32 {
from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError>556     fn from_cbor_value(value: cbor::value::Value) -> Result<Self, CborError> {
557         match value {
558             cbor::value::Value::Integer(i) => {
559                 i.try_into().map_err(|_| crate::CborError::OutOfRangeIntegerValue)
560             }
561             v => crate::cbor_type_error(&v, "i64"),
562         }
563     }
564 
to_cbor_value(self) -> Result<cbor::value::Value, CborError>565     fn to_cbor_value(self) -> Result<cbor::value::Value, CborError> {
566         Ok(cbor::value::Value::Integer(self.into()))
567     }
568 
cddl_typename() -> Option<String>569     fn cddl_typename() -> Option<String> {
570         Some("int".to_string())
571     }
572 }
573