forked from ucan-wg/rs-ucan
/
cid.rs
142 lines (118 loc) · 3.78 KB
/
cid.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//! Utilities for [`Cid`]s
use crate::ipld;
use libipld_core::{cid::Cid, ipld::Ipld};
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen_derive::TryFromJsValue;
#[cfg(feature = "test_utils")]
use proptest::prelude::*;
#[cfg(feature = "test_utils")]
use crate::test_utils::SomeCodec;
#[cfg(feature = "test_utils")]
use crate::test_utils::SomeMultihash;
/// A newtype wrapper around a [`Cid`]
///
/// This is largely to attach traits to [`Cid`]s, such as [`wasm_bindgen`] conversions.
#[cfg(not(target_arch = "wasm32"))]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct Newtype {
pub cid: Cid,
}
/// A newtype wrapper around a [`Cid`]
///
/// This is largely to attach traits to [`Cid`]s, such as [`wasm_bindgen`] conversions.
#[cfg(target_arch = "wasm32")]
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[wasm_bindgen]
pub struct Newtype {
#[wasm_bindgen(skip)]
pub cid: Cid,
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
extern "C" {
/// This is here because the TryFromJsValue derivation macro
/// doesn't automatically support `Option<T>`.
///
/// [https://docs.rs/wasm-bindgen-derive/0.2.1/wasm_bindgen_derive/#optional-arguments]
#[wasm_bindgen(typescript_type = "Newtype | undefined")]
pub type OptionNewtype;
}
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen]
impl Newtype {
/// Parse a [`Newtype`] from a string
pub fn from_string(cid_string: String) -> Result<Newtype, JsError> {
Newtype::try_from(cid_string).map_err(|e| JsError::new(&format!("{}", e)))
}
pub fn try_from_js_value(js: &JsValue) -> Result<Newtype, JsError> {
match &js.as_string() {
Some(s) => Newtype::from_string(s.clone()),
None => Err(JsError::new("Expected a string")),
}
}
}
impl Newtype {
/// Convert the [`Cid`] to a string
pub fn to_string(&self) -> String {
self.cid.to_string()
}
}
impl TryFrom<String> for Newtype {
type Error = <Cid as TryFrom<String>>::Error;
fn try_from(cid_string: String) -> Result<Self, Self::Error> {
Cid::try_from(cid_string).map(Into::into)
}
}
impl From<Newtype> for Cid {
fn from(wrapper: Newtype) -> Self {
wrapper.cid
}
}
impl From<Cid> for Newtype {
fn from(cid: Cid) -> Self {
Self { cid }
}
}
impl TryFrom<Ipld> for Newtype {
type Error = NotACid;
fn try_from(ipld: Ipld) -> Result<Self, Self::Error> {
match ipld {
Ipld::Link(cid) => Ok(Newtype { cid }),
other => Err(NotACid(other.into())),
}
}
}
impl TryFrom<&Ipld> for Newtype {
type Error = NotACid;
fn try_from(ipld: &Ipld) -> Result<Self, Self::Error> {
match ipld {
Ipld::Link(cid) => Ok(Newtype { cid: *cid }),
other => Err(NotACid(other.clone().into())),
}
}
}
// #[cfg(not(target_arch = "wasm32"))]
#[derive(Debug, PartialEq, Clone, Error, Serialize, Deserialize)]
#[error("Not a CID: {0:?}")]
pub struct NotACid(pub ipld::Newtype);
#[cfg(feature = "test_utils")]
impl Arbitrary for Newtype {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
// Very much faking it
any::<([u8; 32], SomeMultihash, SomeCodec)>()
.prop_map(|(hash_bytes, hasher, codec)| {
let multihash =
multihash::MultihashGeneric::wrap(hasher.0.into(), &hash_bytes.as_slice())
.expect("Sha2_256 should always successfully encode a hash");
let cid = Cid::new_v1(codec.0.into(), multihash);
Newtype { cid }
})
.boxed()
}
}