• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 //! Common internal utilities.
18 
19 use crate::{
20     cbor::value::{Integer, Value},
21     common::AsCborValue,
22     CoseError, Result,
23 };
24 use alloc::{boxed::Box, string::String, vec::Vec};
25 
26 #[cfg(test)]
27 mod tests;
28 
29 /// Return an error indicating that an unexpected CBOR type was encountered.
cbor_type_error<T>(value: &Value, want: &'static str) -> Result<T>30 pub(crate) fn cbor_type_error<T>(value: &Value, want: &'static str) -> Result<T> {
31     let got = match value {
32         Value::Integer(_) => "int",
33         Value::Bytes(_) => "bstr",
34         Value::Float(_) => "float",
35         Value::Text(_) => "tstr",
36         Value::Bool(_) => "bool",
37         Value::Null => "nul",
38         Value::Tag(_, _) => "tag",
39         Value::Array(_) => "array",
40         Value::Map(_) => "map",
41         _ => "other",
42     };
43     Err(CoseError::UnexpectedItem(got, want))
44 }
45 
46 /// Trait which augments the [`Value`] type with methods for convenient conversions to contained
47 /// types which throw a [`CoseError`] if the Value is not of the expected type.
48 pub(crate) trait ValueTryAs
49 where
50     Self: Sized,
51 {
52     /// Extractor for [`Value::Integer`]
try_as_integer(self) -> Result<Integer>53     fn try_as_integer(self) -> Result<Integer>;
54 
55     /// Extractor for [`Value::Bytes`]
try_as_bytes(self) -> Result<Vec<u8>>56     fn try_as_bytes(self) -> Result<Vec<u8>>;
57 
58     /// Extractor for [`Value::Bytes`] which also throws an error if the byte string is zero length
try_as_nonempty_bytes(self) -> Result<Vec<u8>>59     fn try_as_nonempty_bytes(self) -> Result<Vec<u8>>;
60 
61     /// Extractor for [`Value::Array`]
try_as_array(self) -> Result<Vec<Self>>62     fn try_as_array(self) -> Result<Vec<Self>>;
63 
64     /// Extractor for [`Value::Array`] which applies `f` to each item to build a new [`Vec`]
try_as_array_then_convert<F, T>(self, f: F) -> Result<Vec<T>> where F: Fn(Value) -> Result<T>65     fn try_as_array_then_convert<F, T>(self, f: F) -> Result<Vec<T>>
66     where
67         F: Fn(Value) -> Result<T>;
68 
69     /// Extractor for [`Value::Map`]
try_as_map(self) -> Result<Vec<(Self, Self)>>70     fn try_as_map(self) -> Result<Vec<(Self, Self)>>;
71 
72     /// Extractor for [`Value::Tag`]
try_as_tag(self) -> Result<(u64, Box<Value>)>73     fn try_as_tag(self) -> Result<(u64, Box<Value>)>;
74 
75     /// Extractor for [`Value::Text`]
try_as_string(self) -> Result<String>76     fn try_as_string(self) -> Result<String>;
77 }
78 
79 impl ValueTryAs for Value {
try_as_integer(self) -> Result<Integer>80     fn try_as_integer(self) -> Result<Integer> {
81         if let Value::Integer(i) = self {
82             Ok(i)
83         } else {
84             cbor_type_error(&self, "int")
85         }
86     }
87 
try_as_bytes(self) -> Result<Vec<u8>>88     fn try_as_bytes(self) -> Result<Vec<u8>> {
89         if let Value::Bytes(b) = self {
90             Ok(b)
91         } else {
92             cbor_type_error(&self, "bstr")
93         }
94     }
95 
try_as_nonempty_bytes(self) -> Result<Vec<u8>>96     fn try_as_nonempty_bytes(self) -> Result<Vec<u8>> {
97         let v = self.try_as_bytes()?;
98         if v.is_empty() {
99             return Err(CoseError::UnexpectedItem("empty bstr", "non-empty bstr"));
100         }
101         Ok(v)
102     }
103 
try_as_array(self) -> Result<Vec<Self>>104     fn try_as_array(self) -> Result<Vec<Self>> {
105         if let Value::Array(a) = self {
106             Ok(a)
107         } else {
108             cbor_type_error(&self, "array")
109         }
110     }
111 
try_as_array_then_convert<F, T>(self, f: F) -> Result<Vec<T>> where F: Fn(Value) -> Result<T>,112     fn try_as_array_then_convert<F, T>(self, f: F) -> Result<Vec<T>>
113     where
114         F: Fn(Value) -> Result<T>,
115     {
116         self.try_as_array()?
117             .into_iter()
118             .map(f)
119             .collect::<Result<Vec<_>, _>>()
120     }
121 
try_as_map(self) -> Result<Vec<(Self, Self)>>122     fn try_as_map(self) -> Result<Vec<(Self, Self)>> {
123         if let Value::Map(a) = self {
124             Ok(a)
125         } else {
126             cbor_type_error(&self, "map")
127         }
128     }
129 
try_as_tag(self) -> Result<(u64, Box<Value>)>130     fn try_as_tag(self) -> Result<(u64, Box<Value>)> {
131         if let Value::Tag(a, v) = self {
132             Ok((a, v))
133         } else {
134             cbor_type_error(&self, "tag")
135         }
136     }
137 
try_as_string(self) -> Result<String>138     fn try_as_string(self) -> Result<String> {
139         if let Value::Text(s) = self {
140             Ok(s)
141         } else {
142             cbor_type_error(&self, "tstr")
143         }
144     }
145 }
146 
147 /// Convert each item of an iterator to CBOR, and wrap the lot in
148 /// a [`Value::Array`]
to_cbor_array<C>(c: C) -> Result<Value> where C: IntoIterator, C::Item: AsCborValue,149 pub fn to_cbor_array<C>(c: C) -> Result<Value>
150 where
151     C: IntoIterator,
152     C::Item: AsCborValue,
153 {
154     Ok(Value::Array(
155         c.into_iter()
156             .map(|e| e.to_cbor_value())
157             .collect::<Result<Vec<_>, _>>()?,
158     ))
159 }
160 
161 /// Check for an expected error.
162 #[cfg(test)]
expect_err<T: core::fmt::Debug, E: core::fmt::Debug + core::fmt::Display>( result: Result<T, E>, err_msg: &str, )163 pub fn expect_err<T: core::fmt::Debug, E: core::fmt::Debug + core::fmt::Display>(
164     result: Result<T, E>,
165     err_msg: &str,
166 ) {
167     #[cfg(not(feature = "std"))]
168     use alloc::format;
169     match result {
170         Ok(_) => {
171             assert!(
172                 result.is_err(),
173                 "expected error containing '{}', got success {:?}",
174                 err_msg,
175                 result
176             );
177         }
178         Err(err) => {
179             assert!(
180                 format!("{:?}", err).contains(err_msg),
181                 "unexpected error {:?}, doesn't contain '{}' (Debug impl)",
182                 err,
183                 err_msg
184             );
185             assert!(
186                 format!("{}", err).contains(err_msg),
187                 "unexpected error {:?}, doesn't contain '{}' (Display impl)",
188                 err,
189                 err_msg
190             );
191         }
192     }
193 }
194 
195 // Macros to reduce boilerplate when creating `CoseSomethingBuilder` structures.
196 
197 /// Add `new()` and `build()` methods to the builder.
198 macro_rules! builder {
199     ( $otype: ty ) => {
200         /// Constructor for builder.
201         pub fn new() -> Self {
202             Self(<$otype>::default())
203         }
204         /// Build the completed object.
205         pub fn build(self) -> $otype {
206             self.0
207         }
208     };
209 }
210 
211 /// Add a setter function for a field to the builder.
212 macro_rules! builder_set {
213     ( $name:ident: $ftype:ty ) => {
214         /// Set the associated field.
215         #[must_use]
216         pub fn $name(mut self, $name: $ftype) -> Self {
217             self.0.$name = $name;
218             self
219         }
220     };
221 }
222 
223 /// Add a setter function for an optional field to the builder.
224 macro_rules! builder_set_optional {
225     ( $name:ident: $ftype:ty ) => {
226         /// Set the associated field.
227         #[must_use]
228         pub fn $name(mut self, $name: $ftype) -> Self {
229             self.0.$name = Some($name);
230             self
231         }
232     };
233 }
234 
235 /// Add a setter function that fills out a `ProtectedHeader` from `Header` contents.
236 macro_rules! builder_set_protected {
237     ( $name:ident ) => {
238         /// Set the associated field.
239         #[must_use]
240         pub fn $name(mut self, hdr: $crate::Header) -> Self {
241             self.0.$name = $crate::ProtectedHeader {
242                 original_data: None,
243                 header: hdr,
244             };
245             self
246         }
247     };
248 }
249