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, 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
76 impl ValueTryAs for Value {
try_as_integer(self) -> Result<Integer>77 fn try_as_integer(self) -> Result<Integer> {
78 if let Value::Integer(i) = self {
79 Ok(i)
80 } else {
81 cbor_type_error(&self, "int")
82 }
83 }
84
try_as_bytes(self) -> Result<Vec<u8>>85 fn try_as_bytes(self) -> Result<Vec<u8>> {
86 if let Value::Bytes(b) = self {
87 Ok(b)
88 } else {
89 cbor_type_error(&self, "bstr")
90 }
91 }
92
try_as_nonempty_bytes(self) -> Result<Vec<u8>>93 fn try_as_nonempty_bytes(self) -> Result<Vec<u8>> {
94 let v = self.try_as_bytes()?;
95 if v.is_empty() {
96 return Err(CoseError::UnexpectedItem("empty bstr", "non-empty bstr"));
97 }
98 Ok(v)
99 }
100
try_as_array(self) -> Result<Vec<Self>>101 fn try_as_array(self) -> Result<Vec<Self>> {
102 if let Value::Array(a) = self {
103 Ok(a)
104 } else {
105 cbor_type_error(&self, "array")
106 }
107 }
108
try_as_array_then_convert<F, T>(self, f: F) -> Result<Vec<T>> where F: Fn(Value) -> Result<T>,109 fn try_as_array_then_convert<F, T>(self, f: F) -> Result<Vec<T>>
110 where
111 F: Fn(Value) -> Result<T>,
112 {
113 self.try_as_array()?
114 .into_iter()
115 .map(f)
116 .collect::<Result<Vec<_>, _>>()
117 }
118
try_as_map(self) -> Result<Vec<(Self, Self)>>119 fn try_as_map(self) -> Result<Vec<(Self, Self)>> {
120 if let Value::Map(a) = self {
121 Ok(a)
122 } else {
123 cbor_type_error(&self, "map")
124 }
125 }
126
try_as_tag(self) -> Result<(u64, Box<Value>)>127 fn try_as_tag(self) -> Result<(u64, Box<Value>)> {
128 if let Value::Tag(a, v) = self {
129 Ok((a, v))
130 } else {
131 cbor_type_error(&self, "tag")
132 }
133 }
134 }
135
136 /// Convert each item of an iterator to CBOR, and wrap the lot in
137 /// a [`Value::Array`]
to_cbor_array<C>(c: C) -> Result<Value> where C: IntoIterator, C::Item: AsCborValue,138 pub fn to_cbor_array<C>(c: C) -> Result<Value>
139 where
140 C: IntoIterator,
141 C::Item: AsCborValue,
142 {
143 Ok(Value::Array(
144 c.into_iter()
145 .map(|e| e.to_cbor_value())
146 .collect::<Result<Vec<_>, _>>()?,
147 ))
148 }
149
150 /// Check for an expected error.
151 #[cfg(test)]
expect_err<T: core::fmt::Debug, E: core::fmt::Debug + core::fmt::Display>( result: Result<T, E>, err_msg: &str, )152 pub fn expect_err<T: core::fmt::Debug, E: core::fmt::Debug + core::fmt::Display>(
153 result: Result<T, E>,
154 err_msg: &str,
155 ) {
156 use alloc::format;
157 match result {
158 Ok(_) => {
159 assert!(
160 result.is_err(),
161 "expected error containing '{}', got success {:?}",
162 err_msg,
163 result
164 );
165 }
166 Err(err) => {
167 assert!(
168 format!("{:?}", err).contains(err_msg),
169 "unexpected error {:?}, doesn't contain '{}' (Debug impl)",
170 err,
171 err_msg
172 );
173 assert!(
174 format!("{}", err).contains(err_msg),
175 "unexpected error {:?}, doesn't contain '{}' (Display impl)",
176 err,
177 err_msg
178 );
179 }
180 }
181 }
182
183 // Macros to reduce boilerplate when creating `CoseSomethingBuilder` structures.
184
185 /// Add `new()` and `build()` methods to the builder.
186 macro_rules! builder {
187 ( $otype: ty ) => {
188 /// Constructor for builder.
189 pub fn new() -> Self {
190 Self(<$otype>::default())
191 }
192 /// Build the completed object.
193 pub fn build(self) -> $otype {
194 self.0
195 }
196 };
197 }
198
199 /// Add a setter function for a field to the builder.
200 macro_rules! builder_set {
201 ( $name:ident: $ftype:ty ) => {
202 /// Set the associated field.
203 #[must_use]
204 pub fn $name(mut self, $name: $ftype) -> Self {
205 self.0.$name = $name;
206 self
207 }
208 };
209 }
210
211 /// Add a setter function for an optional field to the builder.
212 macro_rules! builder_set_optional {
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 = Some($name);
218 self
219 }
220 };
221 }
222
223 /// Add a setter function that fills out a `ProtectedHeader` from `Header` contents.
224 macro_rules! builder_set_protected {
225 ( $name:ident ) => {
226 /// Set the associated field.
227 #[must_use]
228 pub fn $name(mut self, hdr: $crate::Header) -> Self {
229 self.0.$name = $crate::ProtectedHeader {
230 original_data: None,
231 header: hdr,
232 };
233 self
234 }
235 };
236 }
237