use noosphere_collections::hamt::Hash as HamtHash;
use serde::{Deserialize, Serialize};
use std::{fmt::Display, hash::Hash, ops::Deref};
macro_rules! string_coherent {
($wrapper:ty) => {
impl Deref for $wrapper {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Hash for $wrapper {
fn hash<H>(&self, hasher: &mut H)
where
H: std::hash::Hasher,
{
Hash::hash(&self.0, hasher)
}
}
impl HamtHash for $wrapper {
fn hash<H>(&self, hasher: &mut H)
where
H: std::hash::Hasher,
{
Hash::hash(&self.0, hasher)
}
}
impl From<&str> for $wrapper {
fn from(value: &str) -> Self {
Self(value.to_owned())
}
}
impl From<String> for $wrapper {
fn from(value: String) -> Self {
Self(value)
}
}
impl From<$wrapper> for String {
fn from(value: $wrapper) -> Self {
value.0
}
}
impl<'a> From<&'a $wrapper> for &'a str {
fn from(value: &'a $wrapper) -> Self {
&value.0
}
}
impl PartialEq<String> for $wrapper {
fn eq(&self, other: &String) -> bool {
&self.0 == other
}
}
impl PartialEq<$wrapper> for String {
fn eq(&self, other: &$wrapper) -> bool {
self == &other.0
}
}
impl PartialEq<str> for $wrapper {
fn eq(&self, other: &str) -> bool {
&self.0 == other
}
}
impl PartialEq<$wrapper> for str {
fn eq(&self, other: &$wrapper) -> bool {
self == &other.0
}
}
impl PartialEq<&str> for $wrapper {
fn eq(&self, other: &&str) -> bool {
&self.0 == *other
}
}
impl<'a> PartialEq<$wrapper> for &'a str {
fn eq(&self, other: &$wrapper) -> bool {
**self == *other.0
}
}
impl PartialEq for $wrapper {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for $wrapper {}
impl Display for $wrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}
impl AsRef<[u8]> for $wrapper {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
};
}
#[repr(transparent)]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialOrd, Ord)]
pub struct Did(pub String);
string_coherent!(Did);
#[repr(transparent)]
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialOrd, Ord)]
pub struct Jwt(pub String);
string_coherent!(Jwt);
#[repr(transparent)]
#[derive(Default, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, PartialOrd, Ord)]
pub struct Mnemonic(pub String);
#[cfg(test)]
mod tests {
use libipld_cbor::DagCborCodec;
use noosphere_storage::{block_deserialize, block_serialize};
use serde::{Deserialize, Serialize};
use crate::data::Did;
#[test]
fn it_serializes_a_did_transparently_as_a_string() {
#[derive(Serialize, Deserialize)]
struct FooDid {
foo: Did,
}
#[derive(Serialize, Deserialize)]
struct FooString {
foo: String,
}
let string_value = String::from("foobar");
let (did_cid, did_block) = block_serialize::<DagCborCodec, _>(&FooDid {
foo: Did(string_value.clone()),
})
.unwrap();
let (string_cid, string_block) = block_serialize::<DagCborCodec, _>(&FooString {
foo: string_value.clone(),
})
.unwrap();
assert_eq!(did_cid, string_cid);
assert_eq!(did_block, string_block);
let did_from_string = block_deserialize::<DagCborCodec, FooDid>(&string_block).unwrap();
let string_from_did = block_deserialize::<DagCborCodec, FooString>(&did_block).unwrap();
assert_eq!(did_from_string.foo, Did(string_value.clone()));
assert_eq!(string_from_did.foo, string_value);
}
#[test]
fn it_enables_comparison_to_string_types() {
let did_str = "did:key:z6MkoE19WHXJzpLqkxbGP7uXdJX38sWZNUWwyjcuCmjhPpUP";
let did_string = String::from(did_str);
let did = Did::from(did_str);
assert_eq!(did, did_str);
assert_eq!(did_str, did);
assert_eq!(did, did_string);
assert_eq!(did_string, did);
assert_eq!(&did, did_str);
assert_eq!(did_str, &did);
assert_eq!(&did, &did_string);
assert_eq!(&did_string, &did);
}
}