co_primitives/types/
link.rs1use crate::CoCid;
5use cid::Cid;
6use either::Either;
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9use std::{
10 any::type_name,
11 fmt::{Debug, Display},
12 hash::Hash,
13 marker::PhantomData,
14};
15
16pub trait Linkable<T> {
17 fn value(&self) -> Either<Cid, T>;
18}
19
20#[derive(Serialize, Deserialize)]
22#[serde(into = "Cid", from = "Cid")]
23pub struct Link<T> {
24 #[serde(skip)]
25 _type: PhantomData<T>,
26 cid: Cid,
27}
28impl<T> Ord for Link<T> {
29 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
30 self.cid.cmp(&other.cid)
31 }
32}
33impl<T> Eq for Link<T> {}
34impl<T> PartialOrd for Link<T> {
35 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
36 Some(self.cmp(other))
37 }
38}
39impl<T> PartialEq for Link<T> {
40 fn eq(&self, other: &Self) -> bool {
41 self.cid == other.cid
42 }
43}
44impl<T> Hash for Link<T> {
45 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
46 std::hash::Hash::hash(&self.cid, state);
47 }
48}
49impl<T> Copy for Link<T> {}
50impl<T> Linkable<T> for Link<T> {
51 fn value(&self) -> Either<Cid, T> {
52 Either::Left(self.cid)
53 }
54}
55impl<T> Link<T> {
56 pub fn new(cid: Cid) -> Self {
57 Self { cid, _type: Default::default() }
58 }
59
60 pub fn cid(&self) -> &Cid {
61 &self.cid
62 }
63}
64impl<T> Clone for Link<T> {
65 fn clone(&self) -> Self {
66 *self
67 }
68}
69impl<T> From<Link<T>> for Cid {
70 fn from(val: Link<T>) -> Self {
71 val.cid
72 }
73}
74impl<T> From<Link<T>> for Option<Cid> {
75 fn from(val: Link<T>) -> Self {
76 Some(val.cid)
77 }
78}
79impl<T> From<Cid> for Link<T> {
80 fn from(value: Cid) -> Self {
81 Self::new(value)
82 }
83}
84impl<T> From<&Cid> for Link<T> {
85 fn from(value: &Cid) -> Self {
86 Self::new(*value)
87 }
88}
89impl<T> AsRef<Cid> for Link<T> {
90 fn as_ref(&self) -> &Cid {
91 &self.cid
92 }
93}
94impl<T> Debug for Link<T> {
95 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 write!(f, "Link({}: {})", type_name::<T>(), self.cid)
97 }
98}
99impl<T> Display for Link<T> {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 write!(f, "Link({}: {})", type_name::<T>(), self.cid)
102 }
103}
104
105#[derive(Serialize, Deserialize, JsonSchema)]
107#[serde(into = "Option<Cid>", from = "Option<Cid>")]
108pub struct OptionLink<T> {
109 #[serde(skip)]
110 _type: PhantomData<T>,
111 #[schemars(with = "CoCid")]
112 cid: Option<Cid>,
113}
114impl<T> Default for OptionLink<T> {
115 fn default() -> Self {
116 Self { _type: Default::default(), cid: Default::default() }
117 }
118}
119impl<T> PartialEq for OptionLink<T> {
120 fn eq(&self, other: &Self) -> bool {
121 self.cid == other.cid
122 }
123}
124impl<T> Hash for OptionLink<T> {
125 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
126 self.cid.hash(state);
127 }
128}
129impl<T> Ord for OptionLink<T> {
130 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
131 self.cid.cmp(&other.cid)
132 }
133}
134impl<T> Eq for OptionLink<T> {}
135impl<T> PartialOrd for OptionLink<T> {
136 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
137 Some(self.cmp(other))
138 }
139}
140impl<T: Default> Linkable<T> for OptionLink<T> {
141 fn value(&self) -> Either<Cid, T> {
142 match self.cid {
143 Some(cid) => Either::Left(cid),
144 None => Either::Right(T::default()),
145 }
146 }
147}
148impl<T> Copy for OptionLink<T> {}
149impl<T> OptionLink<T> {
150 pub fn new(cid: Option<Cid>) -> Self {
151 Self { cid, _type: Default::default() }
152 }
153
154 pub fn none() -> Self {
155 Self { cid: None, _type: Default::default() }
156 }
157
158 pub fn is_none(&self) -> bool {
159 self.cid.is_none()
160 }
161
162 pub fn cid(&self) -> &Option<Cid> {
163 &self.cid
164 }
165
166 pub fn set(&mut self, cid: Option<Cid>) {
167 self.cid = cid;
168 }
169
170 pub fn link(&self) -> Option<Link<T>> {
171 self.cid.map(Link::new)
172 }
173
174 pub fn unwrap(&self) -> Link<T> {
175 #[allow(clippy::unwrap_used)]
176 Link::new(self.cid.unwrap())
177 }
178
179 pub fn expect(&self, message: &str) -> Link<T> {
180 Link::new(self.cid.expect(message))
181 }
182}
183impl<T> Clone for OptionLink<T> {
184 fn clone(&self) -> Self {
185 *self
186 }
187}
188impl<T> From<OptionLink<T>> for Option<Cid> {
189 fn from(val: OptionLink<T>) -> Self {
190 val.cid
191 }
192}
193impl<T> From<Option<Cid>> for OptionLink<T> {
194 fn from(value: Option<Cid>) -> Self {
195 Self::new(value)
196 }
197}
198impl<T> From<Link<T>> for OptionLink<T> {
199 fn from(value: Link<T>) -> Self {
200 Self::new(Some(value.into()))
201 }
202}
203impl<T> From<&Option<Cid>> for OptionLink<T> {
204 fn from(value: &Option<Cid>) -> Self {
205 Self::new(*value)
206 }
207}
208impl<T> From<Cid> for OptionLink<T> {
209 fn from(value: Cid) -> Self {
210 Self::new(Some(value))
211 }
212}
213impl<T> From<&Cid> for OptionLink<T> {
214 fn from(value: &Cid) -> Self {
215 Self::new(Some(*value))
216 }
217}
218impl<T> AsRef<Option<Cid>> for OptionLink<T> {
219 fn as_ref(&self) -> &Option<Cid> {
220 &self.cid
221 }
222}
223impl<T> Debug for OptionLink<T> {
224 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225 write!(f, "Link({}: {:?})", type_name::<T>(), self.cid)
226 }
227}
228impl<T> Display for OptionLink<T> {
229 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
230 match self.cid {
231 Some(cid) => write!(f, "{} ({})", cid, type_name::<T>()),
232 None => write!(f, "None ({})", type_name::<T>()),
233 }
234 }
235}