From 883cd3ec1d11125d2addb05602a5519c5c9056e0 Mon Sep 17 00:00:00 2001 From: Tensor-Programming Date: Wed, 28 Oct 2020 13:53:49 -0400 Subject: [PATCH] Feat(core): Add manual implementation of Diff on DID. (#62) * add manual did_diff. * remove default from context. * fix clippy. * fix clippy. --- identity_core/src/did/did.rs | 7 +- identity_core/src/did/did_diff.rs | 237 ++++++++++++++++++++++++++++++ identity_core/src/did/mod.rs | 1 + 3 files changed, 240 insertions(+), 5 deletions(-) create mode 100644 identity_core/src/did/did_diff.rs diff --git a/identity_core/src/did/did.rs b/identity_core/src/did/did.rs index d34ac3f954..6e4555e8c5 100644 --- a/identity_core/src/did/did.rs +++ b/identity_core/src/did/did.rs @@ -1,5 +1,4 @@ use core::str::FromStr; -use identity_diff::Diff; use serde::{ de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, @@ -18,8 +17,7 @@ const LEADING_TOKENS: &str = "did"; type DIDTuple = (String, Option); /// a Decentralized identity structure. -#[derive(Debug, PartialEq, Default, Eq, Clone, Diff, Hash, Ord, PartialOrd)] -#[diff(from_into)] +#[derive(Debug, PartialEq, Default, Eq, Clone, Hash, Ord, PartialOrd)] pub struct DID { pub method_name: String, pub id_segments: Vec, @@ -216,8 +214,7 @@ impl Serialize for DID { } /// a DID Params struct. -#[derive(Debug, PartialEq, Eq, Clone, Default, Hash, PartialOrd, Ord, Diff, DDeserialize, DSerialize)] -#[diff(from_into)] +#[derive(Debug, PartialEq, Eq, Clone, Default, Hash, PartialOrd, Ord, DDeserialize, DSerialize)] pub struct Param { pub key: String, pub value: Option, diff --git a/identity_core/src/did/did_diff.rs b/identity_core/src/did/did_diff.rs new file mode 100644 index 0000000000..f2d416683f --- /dev/null +++ b/identity_core/src/did/did_diff.rs @@ -0,0 +1,237 @@ +use crate::did::{Param, DID}; +use identity_diff::Diff; + +use serde::{Deserialize as DDeserialize, Serialize as DSerialize}; + +#[derive(Debug, PartialEq, Default, Clone, DDeserialize, DSerialize)] +#[serde(from = "DID", into = "DID")] +pub struct DiffDID { + #[serde(skip_serializing_if = "String::is_empty")] + pub method_name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub id_segments: Option< as identity_diff::Diff>::Type>, + #[serde(skip_serializing_if = "Option::is_none")] + pub path_segments: Option<> as identity_diff::Diff>::Type>, + #[serde(skip_serializing_if = "Option::is_none")] + pub query: Option<> as identity_diff::Diff>::Type>, + #[serde(skip_serializing_if = "Option::is_none")] + pub fragment: Option< as identity_diff::Diff>::Type>, +} + +#[derive(Debug, PartialEq, Default, Clone, DSerialize, DDeserialize)] +#[serde(from = "Param", into = "Param")] +pub struct DiffParam { + #[serde(skip_serializing_if = "Option::is_none")] + pub key: Option<::Type>, + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option< as identity_diff::Diff>::Type>, +} + +impl Diff for DID { + type Type = DiffDID; + + fn diff(&self, other: &Self) -> identity_diff::Result { + let method_name = if self.method_name == other.method_name { + self.method_name.clone() + } else { + other.method_name.clone() + }; + + Ok(DiffDID { + method_name, + id_segments: if self.id_segments == other.id_segments { + None + } else { + Some(self.id_segments.diff(&other.id_segments)?) + }, + path_segments: if self.path_segments == other.path_segments || other.path_segments == None { + None + } else { + Some(self.path_segments.diff(&other.path_segments)?) + }, + query: if self.query == other.query || other.query == None { + None + } else { + Some(self.query.diff(&other.query)?) + }, + fragment: if self.fragment == other.fragment || other.fragment == None { + None + } else { + Some(self.fragment.diff(&other.fragment)?) + }, + }) + } + + fn merge(&self, diff: Self::Type) -> identity_diff::Result { + Ok(Self { + method_name: if self.method_name == diff.method_name { + self.method_name.clone() + } else { + diff.method_name + }, + id_segments: if let Some(d) = diff.id_segments { + self.id_segments.merge(d)? + } else { + self.id_segments.clone() + }, + path_segments: if let Some(d) = diff.path_segments { + self.path_segments.merge(d)? + } else { + self.path_segments.clone() + }, + query: if let Some(d) = diff.query { + self.query.merge(d)? + } else { + self.query.clone() + }, + fragment: if let Some(d) = diff.fragment { + self.fragment.merge(d)? + } else { + self.fragment.clone() + }, + }) + } + + fn into_diff(self) -> identity_diff::Result { + let Self { + method_name, + id_segments, + path_segments, + query, + fragment, + } = self; + + Ok(DiffDID { + method_name, + id_segments: Some(id_segments.into_diff()?), + path_segments: if let identity_diff::option::DiffOption::Some(_) = path_segments.clone().into_diff()? { + Some(path_segments.into_diff()?) + } else { + None + }, + query: if let identity_diff::option::DiffOption::Some(_) = query.clone().into_diff()? { + Some(query.into_diff()?) + } else { + None + }, + fragment: if let identity_diff::option::DiffOption::Some(_) = fragment.clone().into_diff()? { + Some(fragment.into_diff()?) + } else { + None + }, + }) + } + + fn from_diff(diff: Self::Type) -> identity_diff::Result { + let DiffDID { + method_name, + id_segments, + path_segments, + query, + fragment, + } = diff; + + Ok(Self { + method_name, + id_segments: >::from_diff(match id_segments { + Some(v) => v, + None => >::default().into_diff()?, + })?, + path_segments: >>::from_diff(match path_segments { + Some(v) => v, + None => >>::default().into_diff()?, + })?, + query: >>::from_diff(match query { + Some(v) => v, + None => >>::default().into_diff()?, + })?, + fragment: >::from_diff(match fragment { + Some(v) => v, + None => >::default().into_diff()?, + })?, + }) + } +} + +impl Diff for Param { + type Type = DiffParam; + + fn diff(&self, other: &Self) -> identity_diff::Result { + Ok(DiffParam { + key: if self.key == other.key { + None + } else { + Some(self.key.diff(&other.key)?) + }, + value: if self.value == other.value || other.value == None { + None + } else { + Some(self.value.diff(&other.value)?) + }, + }) + } + + fn merge(&self, diff: Self::Type) -> identity_diff::Result { + Ok(Self { + key: if let Some(d) = diff.key { + self.key.merge(d)? + } else { + self.key.clone() + }, + value: if let Some(d) = diff.value { + self.value.merge(d)? + } else { + self.value.clone() + }, + }) + } + + fn into_diff(self) -> identity_diff::Result { + let Self { key, value } = self; + + Ok(DiffParam { + key: Some(key.into_diff()?), + value: if let identity_diff::option::DiffOption::Some(_) = value.clone().into_diff()? { + Some(value.into_diff()?) + } else { + None + }, + }) + } + fn from_diff(diff: Self::Type) -> identity_diff::Result { + let DiffParam { key, value } = diff; + + Ok(Self { + key: ::from_diff(match key { + Some(v) => v, + None => ::default().into_diff()?, + })?, + value: >::from_diff(match value { + Some(v) => v, + None => >::default().into_diff()?, + })?, + }) + } +} + +impl From for DiffDID { + fn from(did: DID) -> Self { + did.into_diff().expect("Unable to convert to diff") + } +} +impl From for DID { + fn from(diff: DiffDID) -> Self { + Self::from_diff(diff).expect("Unable to convert from diff") + } +} + +impl From for DiffParam { + fn from(param: Param) -> Self { + param.into_diff().expect("Unable to convert to diff") + } +} +impl From for Param { + fn from(diff: DiffParam) -> Self { + Self::from_diff(diff).expect("Unable to convert from diff") + } +} diff --git a/identity_core/src/did/mod.rs b/identity_core/src/did/mod.rs index fcab3d2fd6..213cf44557 100644 --- a/identity_core/src/did/mod.rs +++ b/identity_core/src/did/mod.rs @@ -1,6 +1,7 @@ mod authentication; #[allow(clippy::module_inception)] mod did; +mod did_diff; mod document; mod parser; mod service;