Skip to content

Commit 6a1be0b

Browse files
authored
fix(rust/signed-doc): Modify the DocumentRef structure (#355)
* fix(signed-doc): wip modify document ref Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): wip doc locator Signed-off-by: bkioshn <[email protected]> * fix(catalyst-types): add more derive to uuidv7 Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): new doc ref structure Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): docrefs to value Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): restructure doctypes Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): format Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): linter Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): remove problem report in encoder Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): linter Signed-off-by: bkioshn <[email protected]> * fix(rust/signed-doc): Apply new document ref and fix validation rules (#368) * fix(signed-doc): wip apply new doc ref Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): apply new doc ref and implement validation rule for doc ref Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): revert doc type change Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): remove problem report in encoder Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): metadata decode Signed-off-by: bkioshn <[email protected]> * chore(signed-doc): revert change Signed-off-by: bkioshn <[email protected]> * test(signed-doc): add docref to decoding test Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): format Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): refactor and improvement Signed-off-by: bkioshn <[email protected]> * fix(signed-doc): refactor Signed-off-by: bkioshn <[email protected]> * test(signed-doc): fix content test Signed-off-by: bkioshn <[email protected]> * test(signed-doc): fix content test Signed-off-by: bkioshn <[email protected]> --------- Signed-off-by: bkioshn <[email protected]> --------- Signed-off-by: bkioshn <[email protected]>
1 parent 8d6b5c9 commit 6a1be0b

File tree

25 files changed

+1759
-452
lines changed

25 files changed

+1759
-452
lines changed

rust/catalyst-types/src/uuid/uuid_v7.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use uuid::Uuid;
1010
use super::{decode_cbor_uuid, encode_cbor_uuid, CborContext, UuidError, INVALID_UUID};
1111

1212
/// Type representing a `UUIDv7`.
13-
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, serde::Serialize)]
13+
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Hash, serde::Serialize)]
1414
pub struct UuidV7(Uuid);
1515

1616
impl UuidV7 {

rust/signed_doc/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ pub use catalyst_types::{
2323
pub use content::Content;
2424
use coset::{CborSerializable, TaggedCborSerializable};
2525
use decode_context::{CompatibilityPolicy, DecodeContext};
26-
pub use metadata::{ContentEncoding, ContentType, DocType, DocumentRef, Metadata, Section};
26+
pub use metadata::{
27+
ContentEncoding, ContentType, DocLocator, DocType, DocumentRef, DocumentRefs, Metadata, Section,
28+
};
2729
use minicbor::{decode, encode, Decode, Decoder, Encode};
2830
pub use signature::{CatalystId, Signatures};
2931

rust/signed_doc/src/metadata/document_ref.rs

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
//! Document Locator, where a document can be located.
2+
//! A [CBOR Encoded IPLD Content Identifier](https://github.com/ipld/cid-cbor/)
3+
//! or also known as [IPFS CID](https://docs.ipfs.tech/concepts/content-addressing/#what-is-a-cid).
4+
5+
use std::fmt::Display;
6+
7+
use catalyst_types::problem_report::ProblemReport;
8+
use coset::cbor::Value;
9+
use minicbor::{Decode, Decoder, Encode};
10+
11+
/// CBOR tag of IPLD content identifiers (CIDs).
12+
const CID_TAG: u64 = 42;
13+
14+
/// CID map key.
15+
const CID_MAP_KEY: &str = "cid";
16+
17+
/// Document locator number of map item.
18+
const DOC_LOC_MAP_ITEM: u64 = 1;
19+
20+
/// Document locator, no size limit.
21+
#[derive(Clone, Debug, Default, PartialEq, Hash, Eq, serde::Serialize)]
22+
pub struct DocLocator(Vec<u8>);
23+
24+
impl DocLocator {
25+
#[must_use]
26+
/// Length of the document locator.
27+
pub fn len(&self) -> usize {
28+
self.0.len()
29+
}
30+
31+
#[must_use]
32+
/// Is the document locator empty.
33+
pub fn is_empty(&self) -> bool {
34+
self.0.is_empty()
35+
}
36+
}
37+
38+
impl From<Vec<u8>> for DocLocator {
39+
fn from(value: Vec<u8>) -> Self {
40+
DocLocator(value)
41+
}
42+
}
43+
44+
impl Display for DocLocator {
45+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46+
write!(f, "cid: 0x{}", hex::encode(self.0.as_slice()))
47+
}
48+
}
49+
50+
impl From<DocLocator> for Value {
51+
fn from(value: DocLocator) -> Self {
52+
Value::Map(vec![(
53+
Value::Text(CID_MAP_KEY.to_string()),
54+
Value::Tag(CID_TAG, Box::new(Value::Bytes(value.0.clone()))),
55+
)])
56+
}
57+
}
58+
59+
// document_locator = { "cid" => cid }
60+
impl Decode<'_, ProblemReport> for DocLocator {
61+
fn decode(
62+
d: &mut Decoder, report: &mut ProblemReport,
63+
) -> Result<Self, minicbor::decode::Error> {
64+
const CONTEXT: &str = "DocLocator decoding";
65+
66+
let len = d.map()?.ok_or_else(|| {
67+
report.invalid_value("Map", "Invalid length", "Valid length", CONTEXT);
68+
minicbor::decode::Error::message(format!("{CONTEXT}: expected valid map length"))
69+
})?;
70+
71+
if len != DOC_LOC_MAP_ITEM {
72+
report.invalid_value(
73+
"Map length",
74+
&len.to_string(),
75+
&DOC_LOC_MAP_ITEM.to_string(),
76+
CONTEXT,
77+
);
78+
return Err(minicbor::decode::Error::message(format!(
79+
"{CONTEXT}: expected map length {DOC_LOC_MAP_ITEM}, found {len}"
80+
)));
81+
}
82+
83+
let key = d.str().map_err(|e| {
84+
report.invalid_value("Key", "Not a string", "String", CONTEXT);
85+
e.with_message(format!("{CONTEXT}: expected string"))
86+
})?;
87+
88+
if key != "cid" {
89+
report.invalid_value("Key", key, "'cid'", CONTEXT);
90+
return Err(minicbor::decode::Error::message(format!(
91+
"{CONTEXT}: expected key 'cid', found '{key}'"
92+
)));
93+
}
94+
95+
let tag = d.tag().map_err(|e| {
96+
report.invalid_value("CBOR tag", "Invalid tag", "Valid tag", CONTEXT);
97+
e.with_message(format!("{CONTEXT}: expected tag"))
98+
})?;
99+
100+
if tag.as_u64() != CID_TAG {
101+
report.invalid_value("CBOR tag", &tag.to_string(), &CID_TAG.to_string(), CONTEXT);
102+
return Err(minicbor::decode::Error::message(format!(
103+
"{CONTEXT}: expected tag {CID_TAG}, found {tag}",
104+
)));
105+
}
106+
107+
// No length limit
108+
let cid_bytes = d.bytes().map_err(|e| {
109+
report.invalid_value("CID bytes", "Invalid bytes", "Valid bytes", CONTEXT);
110+
e.with_message(format!("{CONTEXT}: expected bytes"))
111+
})?;
112+
113+
Ok(DocLocator(cid_bytes.to_vec()))
114+
}
115+
}
116+
117+
impl Encode<()> for DocLocator {
118+
fn encode<W: minicbor::encode::Write>(
119+
&self, e: &mut minicbor::Encoder<W>, (): &mut (),
120+
) -> Result<(), minicbor::encode::Error<W::Error>> {
121+
e.map(DOC_LOC_MAP_ITEM)?;
122+
e.str(CID_MAP_KEY)?;
123+
e.tag(minicbor::data::Tag::new(CID_TAG))?;
124+
e.bytes(&self.0)?;
125+
Ok(())
126+
}
127+
}
128+
129+
#[cfg(test)]
130+
mod tests {
131+
132+
use minicbor::{Decoder, Encoder};
133+
134+
use super::*;
135+
136+
#[test]
137+
fn test_doc_locator_encode_decode() {
138+
let mut report = ProblemReport::new("Test doc locator");
139+
let locator = DocLocator(vec![1, 2, 3, 4]);
140+
let mut buffer = Vec::new();
141+
let mut encoder = Encoder::new(&mut buffer);
142+
locator.encode(&mut encoder, &mut ()).unwrap();
143+
let mut decoder = Decoder::new(&buffer);
144+
let decoded_doc_loc = DocLocator::decode(&mut decoder, &mut report).unwrap();
145+
assert_eq!(locator, decoded_doc_loc);
146+
}
147+
148+
// Empty doc locator should not fail
149+
#[test]
150+
fn test_doc_locator_encode_decode_empty() {
151+
let mut report = ProblemReport::new("Test doc locator empty");
152+
let locator = DocLocator(vec![]);
153+
let mut buffer = Vec::new();
154+
let mut encoder = Encoder::new(&mut buffer);
155+
locator.encode(&mut encoder, &mut ()).unwrap();
156+
let mut decoder = Decoder::new(&buffer);
157+
let decoded_doc_loc = DocLocator::decode(&mut decoder, &mut report).unwrap();
158+
assert_eq!(locator, decoded_doc_loc);
159+
}
160+
161+
#[test]
162+
#[allow(clippy::indexing_slicing)]
163+
fn test_doc_locator_to_value() {
164+
let data = vec![1, 2, 3, 4];
165+
let locator = DocLocator(data.clone());
166+
let value: Value = locator.into();
167+
let map = value.into_map().unwrap();
168+
assert_eq!(map.len(), usize::try_from(DOC_LOC_MAP_ITEM).unwrap());
169+
let key = map[0].0.clone().into_text().unwrap();
170+
assert_eq!(key, CID_MAP_KEY);
171+
let (tag, value) = map[0].1.clone().into_tag().unwrap();
172+
assert_eq!(tag, CID_TAG);
173+
assert_eq!(value.into_bytes().unwrap(), data);
174+
}
175+
}

0 commit comments

Comments
 (0)