Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions rust/signed_doc/src/metadata/collaborators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,11 @@ impl<'de> serde::Deserialize<'de> for Collaborators {
.map_err(serde::de::Error::custom)
}
}

impl serde::Serialize for Collaborators {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
let iter = self.0.iter().map(ToString::to_string);
serializer.collect_seq(iter)
}
}
15 changes: 10 additions & 5 deletions rust/signed_doc/src/metadata/content_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use std::{
str::FromStr,
};

use serde::{de, Deserialize, Deserializer};

/// IANA `CoAP` Content Encoding.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ContentEncoding {
Expand Down Expand Up @@ -64,11 +62,18 @@ impl FromStr for ContentEncoding {
}
}

impl<'de> Deserialize<'de> for ContentEncoding {
impl<'de> serde::Deserialize<'de> for ContentEncoding {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
where D: serde::Deserializer<'de> {
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(de::Error::custom)
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}

impl serde::Serialize for ContentEncoding {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
self.to_string().serialize(serializer)
}
}

Expand Down
14 changes: 10 additions & 4 deletions rust/signed_doc/src/metadata/content_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use std::{
str::FromStr,
};

use serde::{de, Deserialize, Deserializer};
use strum::VariantArray;

/// Payload Content Type.
Expand Down Expand Up @@ -54,11 +53,18 @@ impl FromStr for ContentType {
}
}

impl<'de> Deserialize<'de> for ContentType {
impl<'de> serde::Deserialize<'de> for ContentType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
where D: serde::Deserializer<'de> {
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(de::Error::custom)
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}

impl serde::Serialize for ContentType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
self.to_string().serialize(serializer)
}
}

Expand Down
34 changes: 12 additions & 22 deletions rust/signed_doc/src/metadata/doc_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,27 +457,17 @@ mod tests {
cbor_doc_type
}

#[test]
fn test_deserialize_single_uuid_normal() {
let uuid = uuid::Uuid::new_v4().to_string();
let json = json!(uuid);
let dt: DocType = serde_json::from_value(json).unwrap();

assert_eq!(dt.0.len(), 1);
assert_eq!(dt.0.first().unwrap().to_string(), uuid);
}

#[test]
fn test_deserialize_multiple_uuids() {
let uuid1 = uuid::Uuid::new_v4().to_string();
let uuid2 = uuid::Uuid::new_v4().to_string();
let json = json!([uuid1.clone(), uuid2.clone()]);

let dt: DocType = serde_json::from_value(json).unwrap();
let actual =
dt.0.iter()
.map(std::string::ToString::to_string)
.collect::<Vec<_>>();
assert_eq!(actual, vec![uuid1, uuid2]);
#[test_case(
serde_json::json!(UuidV4::new()) ;
"Document type old format"
)]
#[test_case(
serde_json::json!([UuidV4::new(), UuidV4::new()]) ;
"Document type new format"
)]
fn test_json_valid_serde(json: serde_json::Value) {
let refs: DocType = serde_json::from_value(json).unwrap();
let json_from_refs = serde_json::to_value(&refs).unwrap();
assert_eq!(refs, serde_json::from_value(json_from_refs).unwrap());
}
}
4 changes: 2 additions & 2 deletions rust/signed_doc/src/metadata/document_refs/doc_locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const CID_MAP_KEY: &str = "cid";
const DOC_LOC_MAP_ITEM: u64 = 1;

/// Document locator, no size limit.
#[derive(Clone, Debug, Default, PartialEq, Hash, Eq, serde::Serialize)]
#[derive(Clone, Debug, Default, PartialEq, Hash, Eq)]
pub struct DocLocator(Vec<u8>);

impl DocLocator {
Expand All @@ -41,7 +41,7 @@ impl From<Vec<u8>> for DocLocator {

impl Display for DocLocator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "cid: 0x{}", hex::encode(self.0.as_slice()))
write!(f, "0x{}", hex::encode(self.0.as_slice()))
}
}

Expand Down
2 changes: 1 addition & 1 deletion rust/signed_doc/src/metadata/document_refs/doc_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::doc_locator::DocLocator;
const DOC_REF_ARR_ITEM: u64 = 3;

/// Reference to a Document.
#[derive(Clone, Debug, PartialEq, Hash, Eq, serde::Serialize)]
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub struct DocumentRef {
/// Reference to the Document Id
id: UuidV7,
Expand Down
200 changes: 106 additions & 94 deletions rust/signed_doc/src/metadata/document_refs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@

mod doc_locator;
mod doc_ref;
use std::{fmt::Display, str::FromStr};
use std::fmt::Display;

use catalyst_types::uuid::{CborContext, UuidV7};
pub use doc_locator::DocLocator;
pub use doc_ref::DocumentRef;
use minicbor::{Decode, Decoder, Encode};
use serde::{Deserialize, Deserializer};
use tracing::warn;

use crate::CompatibilityPolicy;

/// List of document reference instance.
#[derive(Clone, Debug, PartialEq, Hash, Eq, serde::Serialize)]
#[derive(Clone, Debug, PartialEq, Hash, Eq)]
pub struct DocumentRefs(Vec<DocumentRef>);

/// Document reference error.
Expand Down Expand Up @@ -139,78 +138,101 @@ impl Encode<()> for DocumentRefs {
}
}

impl<'de> Deserialize<'de> for DocumentRefs {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> {
/// Old structure deserialize as map {id, ver}
#[derive(Deserialize)]
struct OldRef {
/// "id": "uuidv7
id: String,
/// "ver": "uuidv7"
ver: String,
}
mod serde_impl {
//! `serde::Deserialize` and `serde::Serialize` trait implementations

/// New structure as deserialize as map {id, ver, cid}
#[derive(Deserialize)]
struct NewRef {
/// "id": "uuidv7"
id: String,
/// "ver": "uuidv7"
ver: String,
/// "cid": "0x..."
cid: String,
}
use std::str::FromStr;

#[derive(Deserialize)]
#[serde(untagged)]
enum DocRefInput {
/// Old structure of document reference.
Old(OldRef),
/// New structure of document reference.
New(Vec<NewRef>),
}
use super::{DocLocator, DocRefError, DocumentRef, DocumentRefs, UuidV7};

let input = DocRefInput::deserialize(deserializer)?;
let dr = match input {
DocRefInput::Old(value) => {
let id = UuidV7::from_str(&value.id).map_err(|_| {
serde::de::Error::custom(DocRefError::StringConversion(value.id.clone()))
})?;
let ver = UuidV7::from_str(&value.ver).map_err(|_| {
serde::de::Error::custom(DocRefError::StringConversion(value.ver.clone()))
})?;
/// Old structure deserialize as map {id, ver}
#[derive(serde::Deserialize)]
struct OldRef {
/// "id": "uuidv7
id: String,
/// "ver": "uuidv7"
ver: String,
}

DocumentRefs(vec![DocumentRef::new(id, ver, DocLocator::default())])
},
DocRefInput::New(value) => {
let mut dr = vec![];
for v in value {
/// New structure as deserialize as map {id, ver, cid}
#[derive(serde::Deserialize, serde::Serialize)]
struct NewRef {
/// "id": "uuidv7"
id: String,
/// "ver": "uuidv7"
ver: String,
/// "cid": "0x..."
cid: String,
}

#[derive(serde::Deserialize)]
#[serde(untagged)]
enum DocRefSerde {
/// Old structure of document reference.
Old(OldRef),
/// New structure of document reference.
New(Vec<NewRef>),
}

impl serde::Serialize for DocumentRefs {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer {
let iter = self.0.iter().map(|v| {
NewRef {
id: v.id().to_string(),
ver: v.ver().to_string(),
cid: v.doc_locator().to_string(),
}
});
serializer.collect_seq(iter)
}
}

impl<'de> serde::Deserialize<'de> for DocumentRefs {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: serde::Deserializer<'de> {
let input = DocRefSerde::deserialize(deserializer)?;
match input {
DocRefSerde::Old(v) => {
let id = UuidV7::from_str(&v.id).map_err(|_| {
serde::de::Error::custom(DocRefError::StringConversion(v.id.clone()))
})?;
let ver = UuidV7::from_str(&v.ver).map_err(|_| {
serde::de::Error::custom(DocRefError::StringConversion(v.ver.clone()))
})?;
let cid = &v.cid.strip_prefix("0x").unwrap_or(&v.cid);
let locator = hex::decode(cid).map_err(|_| {
serde::de::Error::custom(DocRefError::HexDecode(v.cid.clone()))
})?;
dr.push(DocumentRef::new(id, ver, locator.into()));
}
DocumentRefs(dr)
},
};

Ok(dr)
Ok(DocumentRefs(vec![DocumentRef::new(
id,
ver,
DocLocator::default(),
)]))
},
DocRefSerde::New(value) => {
let mut dr = vec![];
for v in value {
let id = UuidV7::from_str(&v.id).map_err(|_| {
serde::de::Error::custom(DocRefError::StringConversion(v.id.clone()))
})?;
let ver = UuidV7::from_str(&v.ver).map_err(|_| {
serde::de::Error::custom(DocRefError::StringConversion(v.ver.clone()))
})?;
let cid = &v.cid.strip_prefix("0x").unwrap_or(&v.cid);
let locator = hex::decode(cid).map_err(|_| {
serde::de::Error::custom(DocRefError::HexDecode(v.cid.clone()))
})?;
dr.push(DocumentRef::new(id, ver, locator.into()));
}
Ok(DocumentRefs(dr))
},
}
}
}
}

#[cfg(test)]
mod tests {

use minicbor::Encoder;
use serde_json::json;
use test_case::test_case;

use super::*;
Expand Down Expand Up @@ -361,45 +383,35 @@ mod tests {
assert_eq!(doc_refs.0, vec![DocumentRef::new(uuid, uuid, doc_loc)]);
}

#[test]
fn test_deserialize_old_doc_ref() {
let uuidv7 = UuidV7::new();
let json = json!(
#[test_case(
serde_json::json!(
{
"id": uuidv7.to_string(),
"ver": uuidv7.to_string(),
"id": UuidV7::new(),
"ver": UuidV7::new(),
}
);
let doc_ref: DocumentRefs = serde_json::from_value(json).unwrap();
let dr = doc_ref.doc_refs().first().unwrap();
assert_eq!(*dr.id(), uuidv7);
assert_eq!(*dr.ver(), uuidv7);
assert_eq!(dr.doc_locator().len(), 0);
}

#[test]
fn test_deserialize_new_doc_ref() {
let uuidv7 = UuidV7::new();
let data = vec![1, 2, 3, 4];
let hex_data = format!("0x{}", hex::encode(data.clone()));
let json = json!(
[{
"id": uuidv7.to_string(),
"ver": uuidv7.to_string(),
"cid": hex_data,
},
{
"id": uuidv7.to_string(),
"ver": uuidv7.to_string(),
"cid": hex_data,
},
) ;
"Document reference type old format"
)]
#[test_case(
serde_json::json!(
[
{
"id": UuidV7::new(),
"ver": UuidV7::new(),
"cid": format!("0x{}", hex::encode([1, 2, 3]))
},
{
"id": UuidV7::new(),
"ver": UuidV7::new(),
"cid": format!("0x{}", hex::encode([1, 2, 3]))
}
]
);
let doc_ref: DocumentRefs = serde_json::from_value(json).unwrap();
assert!(doc_ref.doc_refs().len() == 2);
let dr = doc_ref.doc_refs().first().unwrap();
assert_eq!(*dr.id(), uuidv7);
assert_eq!(*dr.ver(), uuidv7);
assert_eq!(*dr.doc_locator(), data.into());
) ;
"Document reference type new format"
)]
fn test_json_valid_serde(json: serde_json::Value) {
let refs: DocumentRefs = serde_json::from_value(json).unwrap();
let json_from_refs = serde_json::to_value(&refs).unwrap();
assert_eq!(refs, serde_json::from_value(json_from_refs).unwrap());
}
}
Loading