1pub mod car_stream;
5pub mod car_util;
6
7use crate::utils::multihash::prelude::*;
8use anyhow::Context as _;
9use cid::Cid;
10use fvm_ipld_blockstore::Blockstore;
11use fvm_ipld_encoding::CborStore;
12use fvm_ipld_encoding::{DAG_CBOR, to_vec};
13#[allow(clippy::disallowed_types)]
14use multihash_codetable::Code;
15
16use serde::ser::Serialize;
17
18pub trait BlockstoreExt: Blockstore {
20 #[allow(clippy::disallowed_types)]
22 fn bulk_put<'a, S, V>(&self, values: V, code: Code) -> anyhow::Result<Vec<Cid>>
23 where
24 Self: Sized,
25 S: Serialize + 'a,
26 V: IntoIterator<Item = &'a S>,
27 {
28 let keyed_objects = values
29 .into_iter()
30 .map(|value| {
31 let bytes = to_vec(value)?;
32 let cid = Cid::new_v1(DAG_CBOR, code.digest(&bytes));
33 Ok((cid, bytes))
34 })
35 .collect::<anyhow::Result<Vec<_>>>()?;
36
37 let cids = keyed_objects
38 .iter()
39 .map(|(cid, _)| cid.to_owned())
40 .collect();
41
42 self.put_many_keyed(keyed_objects)?;
43
44 Ok(cids)
45 }
46
47 fn get_required(&self, cid: &Cid) -> anyhow::Result<Vec<u8>> {
49 self.get(cid)?
50 .with_context(|| format!("Entry not found in block store: cid={cid}"))
51 }
52}
53
54impl<T: fvm_ipld_blockstore::Blockstore> BlockstoreExt for T {}
55
56pub trait CborStoreExt: CborStore {
58 #[allow(clippy::disallowed_types)]
65 fn default_code() -> Code {
66 Code::Blake2b256
67 }
68
69 fn put_cbor_default<S: serde::ser::Serialize>(&self, obj: &S) -> anyhow::Result<Cid> {
71 self.put_cbor(obj, Self::default_code())
72 }
73
74 fn get_cbor_required<T>(&self, cid: &Cid) -> anyhow::Result<T>
76 where
77 T: serde::de::DeserializeOwned,
78 {
79 self.get_cbor(cid)?.with_context(|| {
80 format!(
81 "Entry not found in cbor store: cid={cid}, type={}",
82 std::any::type_name::<T>()
83 )
84 })
85 }
86}
87
88impl<T: CborStore> CborStoreExt for T {}