twine_lib/twine/
any_twine.rs1use super::TwineBlock;
2use super::{Strand, Tixel, Twine};
3use crate::as_cid::AsCid;
4use crate::crypto::{assert_cid, get_hasher};
5use crate::errors::VerificationError;
6use crate::twine::Tagged;
7use crate::Cid;
8use core::str;
9use ipld_core::codec::Codec;
10use multihash_codetable::{Code, Multihash};
11use serde_ipld_dagjson::codec::DagJsonCodec;
12use std::convert::TryFrom;
13use std::fmt::Display;
15
16#[derive(Debug, PartialEq, Eq, Hash, Clone)]
21pub enum AnyTwine {
22 Strand(Strand),
24 Tixel(Tixel),
26}
27
28impl AnyTwine {
29 pub fn cid(&self) -> Cid {
31 match self {
32 Self::Strand(s) => s.cid(),
33 Self::Tixel(t) => t.cid(),
34 }
35 }
36
37 pub fn strand_cid(&self) -> Cid {
42 match self {
43 Self::Strand(s) => s.cid(),
44 Self::Tixel(t) => t.strand_cid(),
45 }
46 }
47
48 pub fn content_hash(&self) -> Multihash {
50 match self {
51 Self::Strand(s) => s.content_hash(),
52 Self::Tixel(t) => t.content_hash(),
53 }
54 }
55
56 pub fn is_strand(&self) -> bool {
58 matches!(self, Self::Strand(_))
59 }
60
61 pub fn is_tixel(&self) -> bool {
63 matches!(self, Self::Tixel(_))
64 }
65
66 pub fn unwrap_tixel(&self) -> Tixel {
68 match self {
69 Self::Tixel(t) => t.clone(),
70 _ => panic!("Expected Tixel, found Strand"),
71 }
72 }
73
74 pub fn unwrap_strand(&self) -> Strand {
76 match self {
77 Self::Strand(s) => s.clone(),
78 _ => panic!("Expected Strand, found Tixel"),
79 }
80 }
81
82 fn assert_cid(&self, expected: &Cid) -> Result<(), VerificationError> {
83 assert_cid(expected, &self.cid())
84 }
85
86 pub fn from_tagged_dag_json_array<S: AsRef<str>>(
88 json: S,
89 ) -> Result<Vec<Self>, VerificationError> {
90 let arr: Vec<Tagged<Self>> = DagJsonCodec::decode_from_slice(json.as_ref().as_bytes())?;
91 Ok(arr.into_iter().map(|t| t.unpack()).collect())
92 }
93}
94
95impl PartialEq<Tixel> for AnyTwine {
96 fn eq(&self, other: &Tixel) -> bool {
97 match self {
98 Self::Tixel(t) => *t == *other,
99 _ => false,
100 }
101 }
102}
103
104impl PartialEq<AnyTwine> for Tixel {
105 fn eq(&self, other: &AnyTwine) -> bool {
106 other == self
107 }
108}
109
110impl PartialEq<Strand> for AnyTwine {
111 fn eq(&self, other: &Strand) -> bool {
112 match self {
113 Self::Strand(s) => *s == *other,
114 _ => false,
115 }
116 }
117}
118
119impl PartialEq<AnyTwine> for Strand {
120 fn eq(&self, other: &AnyTwine) -> bool {
121 other == self
122 }
123}
124
125impl TryFrom<AnyTwine> for Tixel {
126 type Error = VerificationError;
127
128 fn try_from(t: AnyTwine) -> Result<Self, Self::Error> {
129 match t {
130 AnyTwine::Tixel(t) => Ok(t),
131 _ => Err(VerificationError::WrongType {
132 expected: "Tixel".to_string(),
133 found: "Strand".to_string(),
134 }),
135 }
136 }
137}
138
139impl TryFrom<AnyTwine> for Strand {
140 type Error = VerificationError;
141
142 fn try_from(s: AnyTwine) -> Result<Self, Self::Error> {
143 match s {
144 AnyTwine::Strand(s) => Ok(s),
145 _ => Err(VerificationError::WrongType {
146 expected: "Strand".to_string(),
147 found: "Tixel".to_string(),
148 }),
149 }
150 }
151}
152
153impl From<Strand> for AnyTwine {
154 fn from(s: Strand) -> Self {
155 Self::Strand(s)
156 }
157}
158
159impl From<Twine> for AnyTwine {
160 fn from(t: Twine) -> Self {
161 Self::Tixel(t.tixel().clone())
162 }
163}
164
165impl From<Tixel> for AnyTwine {
166 fn from(t: Tixel) -> Self {
167 Self::Tixel(t)
168 }
169}
170
171impl AsCid for AnyTwine {
172 fn as_cid(&self) -> &Cid {
173 match self {
174 Self::Strand(s) => s.as_cid(),
175 Self::Tixel(t) => t.as_cid(),
176 }
177 }
178}
179
180impl From<AnyTwine> for Cid {
181 fn from(t: AnyTwine) -> Self {
182 match t {
183 AnyTwine::Strand(s) => s.cid(),
184 AnyTwine::Tixel(t) => t.cid(),
185 }
186 }
187}
188
189impl TwineBlock for AnyTwine {
190 fn cid(&self) -> &Cid {
191 self.as_cid()
192 }
193 fn from_tagged_dag_json<S: Display>(json: S) -> Result<Self, VerificationError> {
197 let str_json = json.to_string();
198 let tixel = Tixel::from_tagged_dag_json(&str_json);
200 if tixel.is_ok() {
201 return Ok(Self::Tixel(tixel.unwrap().into()));
202 }
203 let strand = Strand::from_tagged_dag_json(&str_json);
205 if strand.is_ok() {
206 return Ok(Self::Strand(strand.unwrap().into()));
207 }
208 let msg = format!(
209 "Undecodable structure:\n{}\n{}",
210 tixel.err().unwrap(),
211 strand.err().unwrap()
212 );
213 Err(VerificationError::InvalidTwineFormat(msg))
214 }
215
216 fn from_bytes_unchecked(hasher: Code, bytes: Vec<u8>) -> Result<Self, VerificationError> {
218 let tixel = Tixel::from_bytes_unchecked(hasher, bytes.clone());
219 if tixel.is_ok() {
220 return Ok(Self::Tixel(tixel.unwrap().into()));
221 }
222 let strand = Strand::from_bytes_unchecked(hasher, bytes);
223 if strand.is_ok() {
224 return Ok(Self::Strand(strand.unwrap().into()));
225 }
226 let msg = format!(
227 "Undecodable structure because:\n{}\n{}",
228 tixel.err().unwrap(),
229 strand.err().unwrap()
230 );
231 Err(VerificationError::InvalidTwineFormat(msg))
232 }
233
234 fn from_block<T: AsRef<[u8]>>(cid: Cid, bytes: T) -> Result<Self, VerificationError> {
238 let hasher = get_hasher(&cid)?;
239 let twine = Self::from_bytes_unchecked(hasher, bytes.as_ref().to_vec())?;
240 twine.assert_cid(&cid)?;
241 Ok(twine)
242 }
243
244 fn tagged_dag_json(&self) -> String {
246 match self {
247 Self::Strand(s) => s.tagged_dag_json(),
248 Self::Tixel(t) => t.tagged_dag_json(),
249 }
250 }
251
252 fn bytes(&self) -> std::sync::Arc<[u8]> {
254 match self {
255 Self::Strand(s) => s.bytes(),
256 Self::Tixel(t) => t.bytes(),
257 }
258 }
259
260 fn content_bytes(&self) -> std::sync::Arc<[u8]> {
261 match self {
262 Self::Strand(s) => s.content_bytes(),
263 Self::Tixel(t) => t.content_bytes(),
264 }
265 }
266}
267
268impl Display for AnyTwine {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 match self {
271 Self::Strand(s) => write!(f, "{}", s),
272 Self::Tixel(t) => write!(f, "{}", t),
273 }
274 }
275}