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