1use cid::Cid;
5use core::fmt::Debug;
6use serde_repr::{Deserialize_repr, Serialize_repr};
7use std::fmt::Display;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize_repr, Deserialize_repr)]
12#[non_exhaustive]
13#[repr(u64)]
14pub enum KnownMultiCodec {
15 Identity = 0x0,
18
19 Sha1 = 0x11,
22 Sha2256 = 0x12,
25 Sha2512 = 0x13,
28 Sha3512 = 0x14,
31 Sha3384 = 0x15,
34 Sha3256 = 0x16,
37 Sha3224 = 0x17,
40 Shake128 = 0x18,
43 Shake256 = 0x19,
46 Keccak224 = 0x1a,
50 Keccak256 = 0x1b,
53 Keccak384 = 0x1c,
56 Keccak512 = 0x1d,
59 Blake3 = 0x1e,
63 Sha2384 = 0x20,
67
68 Raw = 0x55,
72
73 DagPb = 0x70,
77 DagCbor = 0x71,
81
82 DagJson = 0x0129,
86
87 CoEncryptedBlock = 0x301000,
89
90 CoReference = 0x301001,
92}
93impl KnownMultiCodec {
94 pub fn multi_codec(&self) -> MultiCodec {
95 MultiCodec::Known(*self)
96 }
97}
98impl TryFrom<u64> for KnownMultiCodec {
99 type Error = u64;
100
101 fn try_from(value: u64) -> Result<Self, Self::Error> {
102 serde_json::from_value(value.into()).map_err(|_| value)
103 }
104}
105impl From<KnownMultiCodec> for u64 {
106 fn from(value: KnownMultiCodec) -> Self {
107 value as u64
108 }
109}
110impl PartialEq<u64> for KnownMultiCodec {
111 fn eq(&self, other: &u64) -> bool {
112 (*self) as u64 == *other
113 }
114}
115
116#[derive(Copy, Clone)]
120#[non_exhaustive]
121#[repr(u64)]
122pub enum MultiCodec {
123 Known(KnownMultiCodec),
124 Unknown(u64),
125}
126impl Ord for MultiCodec {
127 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
128 self.codec().cmp(&other.codec())
129 }
130}
131impl PartialOrd for MultiCodec {
132 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
133 Some(self.cmp(other))
134 }
135}
136impl Eq for MultiCodec {}
137impl PartialEq for MultiCodec {
138 fn eq(&self, other: &Self) -> bool {
139 self.codec() == other.codec()
140 }
141}
142impl PartialEq<KnownMultiCodec> for MultiCodec {
143 fn eq(&self, other: &KnownMultiCodec) -> bool {
144 self == &other.multi_codec()
145 }
146}
147impl PartialEq<u64> for MultiCodec {
148 fn eq(&self, other: &u64) -> bool {
149 &self.codec() == other
150 }
151}
152impl<'de> serde::Deserialize<'de> for MultiCodec {
153 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
154 where
155 D: serde::Deserializer<'de>,
156 {
157 Ok(MultiCodec::from(u64::deserialize(deserializer)?))
158 }
159}
160impl serde::Serialize for MultiCodec {
161 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
162 where
163 S: serde::Serializer,
164 {
165 serializer.serialize_u64((*self).into())
166 }
167}
168impl MultiCodec {
169 pub fn with_codec(codec: impl Into<MultiCodec>, cid: &Cid) -> Result<&Cid, MultiCodecError> {
171 let codec = codec.into();
172 let actual_codec: MultiCodec = cid.codec().into();
173 if actual_codec == codec {
174 Ok(cid)
175 } else {
176 Err(MultiCodecError::new(*cid, codec, actual_codec))
177 }
178 }
179
180 pub fn is_any_codec<C: Into<MultiCodec>>(codecs: impl IntoIterator<Item = C>, cid: &Cid) -> Option<&Cid> {
182 let actual_codec: MultiCodec = cid.codec().into();
183 if codecs.into_iter().map(Into::into).any(|c| c == actual_codec) {
184 Some(cid)
185 } else {
186 None
187 }
188 }
189
190 pub fn with_cbor(cid: &Cid) -> Result<&Cid, MultiCodecError> {
192 Self::is_any_codec([KnownMultiCodec::DagCbor, KnownMultiCodec::CoReference], cid).ok_or_else(|| {
193 MultiCodecError::new(*cid, MultiCodec::Known(KnownMultiCodec::DagCbor), MultiCodec::from(cid))
194 })
195 }
196
197 pub fn is_cbor(cid: impl Into<MultiCodec>) -> bool {
199 matches!(
200 cid.into(),
201 MultiCodec::Known(KnownMultiCodec::DagCbor) | MultiCodec::Known(KnownMultiCodec::CoReference)
202 )
203 }
204
205 pub fn is(actual: impl Into<MultiCodec>, expect: impl Into<MultiCodec>) -> bool {
206 actual.into() == expect.into()
207 }
208
209 pub fn codec(&self) -> u64 {
210 (*self).into()
211 }
212}
213impl Display for MultiCodec {
214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215 match self {
216 Self::Known(m) => write!(f, "{:?}", m),
217 Self::Unknown(c) => write!(f, "{:#x}", c),
218 }
219 }
220}
221impl Debug for MultiCodec {
222 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
223 match self {
224 Self::Known(m) => write!(f, "{:?} ({:#x})", m, self.codec()),
225 Self::Unknown(c) => write!(f, "{:#x}", c),
226 }
227 }
228}
229impl From<KnownMultiCodec> for MultiCodec {
230 fn from(value: KnownMultiCodec) -> Self {
231 MultiCodec::Known(value)
232 }
233}
234impl From<MultiCodec> for u64 {
235 fn from(val: MultiCodec) -> Self {
236 match val {
237 MultiCodec::Known(v) => v.into(),
238 MultiCodec::Unknown(v) => v,
239 }
240 }
241}
242impl From<u64> for MultiCodec {
243 fn from(value: u64) -> MultiCodec {
244 match KnownMultiCodec::try_from(value) {
245 Ok(v) => MultiCodec::Known(v),
246 Err(v) => MultiCodec::Unknown(v),
247 }
248 }
249}
250impl From<&Cid> for MultiCodec {
251 fn from(value: &Cid) -> MultiCodec {
252 Self::from(value.codec())
253 }
254}
255impl From<Cid> for MultiCodec {
256 fn from(value: Cid) -> Self {
257 Self::from(value.codec())
258 }
259}
260
261#[derive(Debug, thiserror::Error)]
266#[error("Expected {} codec to be {} got {}", .0.0, .0.1, .0.2)]
267pub struct MultiCodecError(Box<(Cid, MultiCodec, MultiCodec)>);
268impl MultiCodecError {
269 pub fn new(cid: Cid, expected: MultiCodec, actual: MultiCodec) -> Self {
270 Self(Box::new((cid, expected, actual)))
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::MultiCodec;
277 use crate::{BlockSerializer, CoReference, KnownMultiCodec};
278 use serde::{Deserialize, Serialize};
279
280 #[test]
281 fn test_eq() {
282 assert_eq!(MultiCodec::Known(KnownMultiCodec::DagCbor), MultiCodec::Known(KnownMultiCodec::DagCbor));
283 assert_eq!(MultiCodec::Unknown(0x71u64), MultiCodec::Known(KnownMultiCodec::DagCbor));
284 assert_ne!(MultiCodec::Unknown(0x72u64), MultiCodec::Known(KnownMultiCodec::DagCbor));
285 }
286
287 #[test]
288 fn test_from_u64_known() {
289 assert!(matches!(MultiCodec::from(0x71u64), MultiCodec::Known(KnownMultiCodec::DagCbor)));
290 }
291
292 #[test]
293 fn test_from_u64_unknown() {
294 assert!(matches!(MultiCodec::from(0xdeadbeefu64), MultiCodec::Unknown(0xdeadbeefu64)));
295 }
296
297 #[test]
298 fn test_into_u64_known() {
299 assert_eq!(MultiCodec::from(KnownMultiCodec::DagCbor).codec(), 0x71u64);
300 }
301
302 #[test]
303 fn test_into_u64_unknown() {
304 assert_eq!(MultiCodec::from(0xdeadbeefu64).codec(), 0xdeadbeefu64);
305 }
306
307 #[test]
308 fn test_serde() {
309 #[derive(Debug, PartialEq, Serialize, Deserialize)]
310 struct Test {
311 codec: MultiCodec,
312 }
313
314 assert_eq!(serde_json::to_string(&Test { codec: KnownMultiCodec::DagCbor.into() }).unwrap(), "{\"codec\":113}");
316 assert_eq!(serde_json::to_string(&Test { codec: 0xdeadbeefu64.into() }).unwrap(), "{\"codec\":3735928559}");
317
318 assert_eq!(
320 serde_json::from_str::<Test>("{\"codec\":113}").unwrap(),
321 Test { codec: MultiCodec::Known(KnownMultiCodec::DagCbor) }
322 );
323 assert_eq!(
324 serde_json::from_str::<Test>("{\"codec\":3735928559}").unwrap(),
325 Test { codec: MultiCodec::Unknown(0xdeadbeefu64) }
326 );
327 }
328
329 #[test]
330 fn test_cid() {
331 let block = BlockSerializer::new_codec(KnownMultiCodec::CoReference)
332 .serialize(&CoReference::Weak(1))
333 .unwrap();
334 assert_eq!(block.cid().to_string(), "baga2bqabdyqe2tf374ji3ixvay5hqmwyymxxpgjtxmqfijehizup5f5pypp6bda");
335 }
336}