1 //! This module defines a helper for parsing fields in a CBOR map.
2
3 use coset::{cbor::value::Value, AsCborValue, CoseEncrypt, CoseError, CoseMac0, CoseSign1};
4 use thiserror::Error;
5
6 #[derive(Error, Debug)]
7 pub enum FieldValueError {
8 #[error("expected a value for field {0}, but none was found")]
9 Missing(&'static str),
10 #[error("expected bytes for field {0}, but found `{1:?}`")]
11 NotBytes(&'static str, Value),
12 #[error("expected string for field {0}, but found `{1:?}`")]
13 NotString(&'static str, Value),
14 #[error("expected null for field {0}, but found `{1:?}`")]
15 NotNull(&'static str, Value),
16 #[error("expected u32 for field {0}, but found `{1:?}`")]
17 NotU32(&'static str, Value),
18 #[error("expected i64 for field {0}, but found `{1:?}`")]
19 NotI64(&'static str, Value),
20 #[error("expected u64 for field {0}, but found `{1:?}`")]
21 NotU64(&'static str, Value),
22 #[error("expected map for field {0}, but found `{1:?}`")]
23 NotMap(&'static str, Value),
24 #[error("expected array for field {0}, but found `{1:?}`")]
25 NotArray(&'static str, Value),
26 #[error("unable to parse field {0} as COSE_Sign1: `{1:?}`")]
27 CoseSign1ParseError(&'static str, CoseError),
28 #[error("unable to parse field {0} as COSE_Encrypt: `{1:?}`")]
29 CoseEncryptParseError(&'static str, CoseError),
30 #[error("unable to parse field {0} as COSE_Mac0: `{1:?}`")]
31 CoseMac0ParseError(&'static str, CoseError),
32 #[error("field {0} may be set only once; encountered multiple values: `{1:?}`, `{2:?}`")]
33 DuplicateField(&'static str, Value, Value),
34 }
35
36 pub(super) struct FieldValue {
37 name: &'static str,
38 value: Option<Value>,
39 }
40
41 impl FieldValue {
new(name: &'static str) -> Self42 pub fn new(name: &'static str) -> Self {
43 Self { name, value: None }
44 }
45
from_value(name: &'static str, value: Value) -> Self46 pub fn from_value(name: &'static str, value: Value) -> Self {
47 Self { name, value: Some(value) }
48 }
49
from_optional_value(name: &'static str, value: Option<Value>) -> Self50 pub fn from_optional_value(name: &'static str, value: Option<Value>) -> Self {
51 Self { name, value }
52 }
53
set_once(&mut self, value: Value) -> Result<(), FieldValueError>54 pub fn set_once(&mut self, value: Value) -> Result<(), FieldValueError> {
55 match &self.value {
56 None => {
57 self.value = Some(value);
58 Ok(())
59 }
60 Some(previous) => {
61 Err(FieldValueError::DuplicateField(self.name, previous.clone(), value))
62 }
63 }
64 }
65
is_bytes(&self) -> bool66 pub fn is_bytes(&self) -> bool {
67 self.value.as_ref().map_or(false, |v| v.is_bytes())
68 }
69
into_optional_bytes(self) -> Result<Option<Vec<u8>>, FieldValueError>70 pub fn into_optional_bytes(self) -> Result<Option<Vec<u8>>, FieldValueError> {
71 self.value
72 .map(|v| match v {
73 Value::Bytes(b) => Ok(b),
74 _ => Err(FieldValueError::NotBytes(self.name, v)),
75 })
76 .transpose()
77 }
78
into_bytes(self) -> Result<Vec<u8>, FieldValueError>79 pub fn into_bytes(self) -> Result<Vec<u8>, FieldValueError> {
80 require_present(self.name, self.into_optional_bytes())
81 }
82
into_optional_string(self) -> Result<Option<String>, FieldValueError>83 pub fn into_optional_string(self) -> Result<Option<String>, FieldValueError> {
84 self.value
85 .map(|v| match v {
86 Value::Text(s) => Ok(s),
87 _ => Err(FieldValueError::NotString(self.name, v)),
88 })
89 .transpose()
90 }
91
into_string(self) -> Result<String, FieldValueError>92 pub fn into_string(self) -> Result<String, FieldValueError> {
93 require_present(self.name, self.into_optional_string())
94 }
95
into_cose_encrypt(self) -> Result<CoseEncrypt, FieldValueError>96 pub fn into_cose_encrypt(self) -> Result<CoseEncrypt, FieldValueError> {
97 require_present(self.name, self.into_optional_cose_encrypt())
98 }
99
into_optional_cose_encrypt(self) -> Result<Option<CoseEncrypt>, FieldValueError>100 pub fn into_optional_cose_encrypt(self) -> Result<Option<CoseEncrypt>, FieldValueError> {
101 self.value
102 .map(|v| match v {
103 Value::Array(_) => CoseEncrypt::from_cbor_value(v)
104 .map_err(|e| FieldValueError::CoseEncryptParseError(self.name, e)),
105 _ => Err(FieldValueError::NotArray(self.name, v)),
106 })
107 .transpose()
108 }
109
into_cose_mac0(self) -> Result<CoseMac0, FieldValueError>110 pub fn into_cose_mac0(self) -> Result<CoseMac0, FieldValueError> {
111 require_present(self.name, self.into_optional_cose_mac0())
112 }
113
into_optional_cose_mac0(self) -> Result<Option<CoseMac0>, FieldValueError>114 pub fn into_optional_cose_mac0(self) -> Result<Option<CoseMac0>, FieldValueError> {
115 self.value
116 .map(|v| match v {
117 Value::Array(_) => CoseMac0::from_cbor_value(v)
118 .map_err(|e| FieldValueError::CoseMac0ParseError(self.name, e)),
119 _ => Err(FieldValueError::NotArray(self.name, v)),
120 })
121 .transpose()
122 }
123
into_cose_sign1(self) -> Result<CoseSign1, FieldValueError>124 pub fn into_cose_sign1(self) -> Result<CoseSign1, FieldValueError> {
125 require_present(self.name, self.into_optional_cose_sign1())
126 }
127
into_optional_cose_sign1(self) -> Result<Option<CoseSign1>, FieldValueError>128 pub fn into_optional_cose_sign1(self) -> Result<Option<CoseSign1>, FieldValueError> {
129 self.value
130 .map(|v| match v {
131 Value::Array(_) => CoseSign1::from_cbor_value(v)
132 .map_err(|e| FieldValueError::CoseSign1ParseError(self.name, e)),
133 _ => Err(FieldValueError::NotArray(self.name, v)),
134 })
135 .transpose()
136 }
137
into_array(self) -> Result<Vec<Value>, FieldValueError>138 pub fn into_array(self) -> Result<Vec<Value>, FieldValueError> {
139 require_present(self.name, self.into_optional_array())
140 }
141
into_optional_array(self) -> Result<Option<Vec<Value>>, FieldValueError>142 pub fn into_optional_array(self) -> Result<Option<Vec<Value>>, FieldValueError> {
143 self.value
144 .map(|v| match v {
145 Value::Array(v) => Ok(v),
146 _ => Err(FieldValueError::NotArray(self.name, v)),
147 })
148 .transpose()
149 }
150
into_map(self) -> Result<Vec<(Value, Value)>, FieldValueError>151 pub fn into_map(self) -> Result<Vec<(Value, Value)>, FieldValueError> {
152 require_present(self.name, self.into_optional_map())
153 }
154
into_optional_map(self) -> Result<Option<Vec<(Value, Value)>>, FieldValueError>155 pub fn into_optional_map(self) -> Result<Option<Vec<(Value, Value)>>, FieldValueError> {
156 self.value
157 .map(|v| match v {
158 Value::Map(v) => Ok(v),
159 _ => Err(FieldValueError::NotMap(self.name, v)),
160 })
161 .transpose()
162 }
163
is_null(&self) -> Result<bool, FieldValueError>164 pub fn is_null(&self) -> Result<bool, FieldValueError> {
165 // If there's no value, return false; if there is a null value, return true; anything else
166 // is an error.
167 self.value
168 .as_ref()
169 .map(|v| match *v {
170 Value::Null => Ok(true),
171 _ => Err(FieldValueError::NotNull(self.name, v.clone())),
172 })
173 .unwrap_or(Ok(false))
174 }
175
is_integer(&self) -> bool176 pub fn is_integer(&self) -> bool {
177 self.value.as_ref().map_or(false, |v| v.is_integer())
178 }
179
into_u32(self) -> Result<u32, FieldValueError>180 pub fn into_u32(self) -> Result<u32, FieldValueError> {
181 require_present(self.name, self.into_optional_u32())
182 }
183
into_optional_u32(self) -> Result<Option<u32>, FieldValueError>184 pub fn into_optional_u32(self) -> Result<Option<u32>, FieldValueError> {
185 self.value
186 .map(|v| {
187 let value =
188 if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
189 value.ok_or(FieldValueError::NotU32(self.name, v))
190 })
191 .transpose()
192 }
193
into_optional_i64(self) -> Result<Option<i64>, FieldValueError>194 pub fn into_optional_i64(self) -> Result<Option<i64>, FieldValueError> {
195 self.value
196 .map(|v| {
197 let value =
198 if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
199 value.ok_or(FieldValueError::NotI64(self.name, v))
200 })
201 .transpose()
202 }
203
into_u64(self) -> Result<u64, FieldValueError>204 pub fn into_u64(self) -> Result<u64, FieldValueError> {
205 require_present(self.name, self.into_optional_u64())
206 }
207
into_optional_u64(self) -> Result<Option<u64>, FieldValueError>208 pub fn into_optional_u64(self) -> Result<Option<u64>, FieldValueError> {
209 self.value
210 .map(|v| {
211 let value =
212 if let Value::Integer(i) = v { i128::from(i).try_into().ok() } else { None };
213 value.ok_or(FieldValueError::NotU64(self.name, v))
214 })
215 .transpose()
216 }
217 }
218
require_present<T>( name: &'static str, value: Result<Option<T>, FieldValueError>, ) -> Result<T, FieldValueError>219 fn require_present<T>(
220 name: &'static str,
221 value: Result<Option<T>, FieldValueError>,
222 ) -> Result<T, FieldValueError> {
223 value.and_then(|opt| opt.ok_or(FieldValueError::Missing(name)))
224 }
225