1use std::collections::TryReserveError;
2
3use ipld_core::cid::{Cid, multihash::Multihash};
4use serde::Serialize;
5use serde_ipld_dagcbor::EncodeError;
6use sha3::{Digest, Sha3_256};
7use thiserror::Error;
8
9#[derive(Error, Debug)]
10pub enum CidGenerationError {
11 #[error("failed to DAG-CBOR encoding: {0}")]
12 Encode(#[from] EncodeError<TryReserveError>),
13 #[error("failed to parse multihash: {0}")]
14 Multihash(#[from] ipld_core::cid::multihash::Error),
15}
16
17pub fn compute_cid_cbor<T: Serialize>(value: &T) -> Result<String, CidGenerationError> {
19 let encoded = serde_ipld_dagcbor::to_vec(value)?;
20
21 let mut hasher = Sha3_256::new();
22 hasher.update(&encoded);
23 let hash = hasher.finalize();
24
25 let multihash = Multihash::wrap(CODE_SHA3_256, &hash)?;
26 let cid = Cid::new_v1(CODEC_DAG_CBOR, multihash);
27 Ok(cid.to_string())
28}
29
30const CODEC_DAG_CBOR: u64 = 0x71;
31const CODE_SHA3_256: u64 = 0x16;
32
33#[cfg(test)]
34mod tests {
35 use std::str::FromStr;
36
37 use super::*;
38
39 #[derive(Serialize)]
40 struct TestData {
41 hello: String,
42 }
43
44 #[test]
45 fn test_cid_cbor() {
46 let data = TestData {
47 hello: "world".to_string(),
48 };
49
50 let cid_str = compute_cid_cbor(&data).unwrap();
51
52 let cid = Cid::from_str(&cid_str).unwrap();
53 assert_eq!(cid.codec(), CODEC_DAG_CBOR);
54
55 let hash = cid.hash();
56 assert_eq!(hash.code(), CODE_SHA3_256);
57 }
58}