Skip to content

Commit aca802a

Browse files
committed
refactor Metadata decoding
1 parent 40acd23 commit aca802a

File tree

5 files changed

+73
-112
lines changed

5 files changed

+73
-112
lines changed

rust/signed_doc/src/metadata/content_type.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ pub enum ContentType {
1717
Json,
1818
}
1919

20-
impl Default for ContentType {
21-
fn default() -> Self {
22-
Self::Json
23-
}
24-
}
25-
2620
impl Display for ContentType {
2721
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
2822
match self {

rust/signed_doc/src/metadata/document_id.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ use super::UuidV7;
99
pub struct DocumentId(UuidV7);
1010

1111
impl DocumentId {
12-
/// Generates a zeroed out `UUIDv7` that can never be valid.
13-
pub fn invalid() -> Self {
14-
Self(UuidV7::invalid())
15-
}
16-
1712
/// Returns the `uuid::Uuid` type.
1813
#[must_use]
1914
pub fn uuid(&self) -> uuid::Uuid {

rust/signed_doc/src/metadata/document_type.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@ use super::UuidV4;
99
pub struct DocumentType(UuidV4);
1010

1111
impl DocumentType {
12-
/// Generates a zeroed out `UUIDv4` that can never be valid.
13-
pub fn invalid() -> Self {
14-
Self(UuidV4::invalid())
15-
}
16-
1712
/// Returns the `uuid::Uuid` type.
1813
#[must_use]
1914
pub fn uuid(&self) -> uuid::Uuid {

rust/signed_doc/src/metadata/document_version.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,6 @@ use super::UuidV7;
88
pub struct DocumentVersion(UuidV7);
99

1010
impl DocumentVersion {
11-
/// Generates a zeroed out `UUIDv7` that can never be valid.
12-
pub fn invalid() -> Self {
13-
Self(UuidV7::invalid())
14-
}
15-
1611
/// Returns the `uuid::Uuid` type.
1712
#[must_use]
1813
pub fn uuid(&self) -> uuid::Uuid {

rust/signed_doc/src/metadata/mod.rs

Lines changed: 73 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ pub struct Metadata {
3535
/// Document Version `UUIDv7`.
3636
ver: DocumentVersion,
3737
/// Document Payload Content Type.
38-
#[serde(default, rename = "content-type")]
38+
#[serde(rename = "content-type")]
3939
content_type: ContentType,
4040
/// Document Payload Content Encoding.
41-
#[serde(default, rename = "content-encoding")]
41+
#[serde(rename = "content-encoding")]
4242
content_encoding: Option<ContentEncoding>,
4343
/// Additional Metadata Fields.
4444
#[serde(flatten)]
@@ -90,131 +90,113 @@ impl Display for Metadata {
9090
}
9191
}
9292

93-
impl Default for Metadata {
94-
fn default() -> Self {
95-
Self {
96-
doc_type: DocumentType::invalid(),
97-
id: DocumentId::invalid(),
98-
ver: DocumentVersion::invalid(),
99-
content_type: ContentType::default(),
100-
content_encoding: None,
101-
extra: AdditionalFields::default(),
102-
}
103-
}
104-
}
105-
10693
impl TryFrom<&coset::ProtectedHeader> for Metadata {
10794
type Error = crate::error::Error;
10895

109-
#[allow(clippy::too_many_lines)]
11096
fn try_from(protected: &coset::ProtectedHeader) -> Result<Self, Self::Error> {
111-
let mut metadata = Metadata::default();
11297
let mut errors = Vec::new();
11398

114-
match protected.header.content_type.as_ref() {
115-
Some(iana_content_type) => {
116-
match ContentType::try_from(iana_content_type) {
117-
Ok(content_type) => metadata.content_type = content_type,
118-
Err(e) => {
119-
errors.push(anyhow!("Invalid Document Content-Type: {e}"));
120-
},
121-
}
122-
},
123-
None => {
124-
errors.push(anyhow!(
125-
"COSE document protected header `content-type` field is missing"
126-
));
127-
},
99+
let mut content_type = None;
100+
if let Some(value) = protected.header.content_type.as_ref() {
101+
match ContentType::try_from(value) {
102+
Ok(ct) => content_type = Some(ct),
103+
Err(e) => errors.push(anyhow!("Invalid Document Content-Type: {e}")),
104+
}
105+
} else {
106+
errors.push(anyhow!(
107+
"Invalid COSE protected header, missing Content-Type field"
108+
));
128109
}
129110

111+
let mut content_encoding = None;
130112
if let Some(value) = cose_protected_header_find(
131113
protected,
132114
|key| matches!(key, coset::Label::Text(label) if label.eq_ignore_ascii_case(CONTENT_ENCODING_KEY)),
133115
) {
134116
match ContentEncoding::try_from(value) {
135-
Ok(encoding) => {
136-
metadata.content_encoding = Some(encoding);
137-
},
138-
Err(e) => {
139-
errors.push(anyhow!("Invalid Document Content Encoding: {e}"));
140-
},
117+
Ok(ce) => content_encoding = Some(ce),
118+
Err(e) => errors.push(anyhow!("Invalid Document Content Encoding: {e}")),
141119
}
142120
} else {
143121
errors.push(anyhow!(
144-
"Invalid COSE document protected header '{CONTENT_ENCODING_KEY}' is missing"
122+
"Invalid COSE protected header, missing Content-Encoding field"
145123
));
146124
}
147125

148-
if let Some(doc_type) = cose_protected_header_find(protected, |key| {
126+
let mut doc_type = None;
127+
if let Some(value) = cose_protected_header_find(protected, |key| {
149128
key == &coset::Label::Text("type".to_string())
150129
}) {
151-
match UuidV4::try_from(doc_type) {
152-
Ok(doc_type_uuid) => {
153-
metadata.doc_type = doc_type_uuid.into();
154-
},
155-
Err(e) => {
156-
errors.push(anyhow!("Document `type` is invalid: {e}"));
157-
},
130+
match UuidV4::try_from(value) {
131+
Ok(uuid) => doc_type = Some(uuid),
132+
Err(e) => errors.push(anyhow!("Document `type` is invalid: {e}")),
158133
}
159134
} else {
160135
errors.push(anyhow!(
161136
"Invalid COSE protected header, missing `type` field"
162137
));
163138
}
164139

165-
match cose_protected_header_find(protected, |key| {
140+
let mut id = None;
141+
if let Some(value) = cose_protected_header_find(protected, |key| {
166142
key == &coset::Label::Text("id".to_string())
167143
}) {
168-
Some(doc_id) => {
169-
match UuidV7::try_from(doc_id) {
170-
Ok(doc_id_uuid) => {
171-
metadata.id = doc_id_uuid.into();
172-
},
173-
Err(e) => {
174-
errors.push(anyhow!("Document `id` is invalid: {e}"));
175-
},
176-
}
177-
},
178-
None => errors.push(anyhow!("Invalid COSE protected header, missing `id` field")),
179-
};
144+
match UuidV7::try_from(value) {
145+
Ok(uuid) => id = Some(uuid),
146+
Err(e) => errors.push(anyhow!("Document `id` is invalid: {e}")),
147+
}
148+
} else {
149+
errors.push(anyhow!("Invalid COSE protected header, missing `id` field"));
150+
}
180151

181-
match cose_protected_header_find(protected, |key| {
152+
let mut ver = None;
153+
if let Some(value) = cose_protected_header_find(protected, |key| {
182154
key == &coset::Label::Text("ver".to_string())
183155
}) {
184-
Some(doc_ver) => {
185-
match UuidV7::try_from(doc_ver) {
186-
Ok(doc_ver_uuid) => {
187-
if doc_ver_uuid.uuid() < metadata.id.uuid() {
188-
errors.push(anyhow!(
189-
"Document Version {doc_ver_uuid} cannot be smaller than Document ID {}", metadata.id
190-
));
191-
} else {
192-
metadata.ver = doc_ver_uuid.into();
193-
}
194-
},
195-
Err(e) => {
196-
errors.push(anyhow!(
197-
"Invalid COSE protected header `ver` field, err: {e}"
198-
));
199-
},
200-
}
201-
},
202-
None => {
203-
errors.push(anyhow!(
204-
"Invalid COSE protected header, missing `ver` field"
205-
));
206-
},
156+
match UuidV7::try_from(value) {
157+
Ok(uuid) => ver = Some(uuid),
158+
Err(e) => errors.push(anyhow!("Document `ver` is invalid: {e}")),
159+
}
160+
} else {
161+
errors.push(anyhow!(
162+
"Invalid COSE protected header, missing `ver` field"
163+
));
207164
}
208165

209-
match AdditionalFields::try_from(protected) {
210-
Ok(extra) => metadata.extra = extra,
211-
Err(e) => errors.extend(e),
212-
};
166+
let extra = AdditionalFields::try_from(protected).map_or_else(
167+
|e| {
168+
errors.extend(e);
169+
None
170+
},
171+
Some,
172+
);
173+
174+
match (content_type, content_encoding, id, doc_type, ver, extra) {
175+
(
176+
Some(content_type),
177+
content_encoding,
178+
Some(id),
179+
Some(doc_type),
180+
Some(ver),
181+
Some(extra),
182+
) => {
183+
if ver < id {
184+
errors.push(anyhow!(
185+
"Document Version {ver} cannot be smaller than Document ID {id}",
186+
));
187+
return Err(crate::error::Error(errors));
188+
}
213189

214-
if errors.is_empty() {
215-
Ok(metadata)
216-
} else {
217-
Err(errors.into())
190+
Ok(Self {
191+
doc_type: doc_type.into(),
192+
id: id.into(),
193+
ver: ver.into(),
194+
content_encoding,
195+
content_type,
196+
extra,
197+
})
198+
},
199+
_ => Err(crate::error::Error(errors)),
218200
}
219201
}
220202
}

0 commit comments

Comments
 (0)