noosphere_storage/
block.rs1use std::io::Cursor;
2
3use anyhow::{anyhow, Result};
4use async_trait::async_trait;
5use cid::{
6 multihash::{Code, MultihashDigest},
7 Cid,
8};
9use libipld_core::{
10 codec::References,
11 serde::{from_ipld, to_ipld},
12};
13use libipld_core::{
14 codec::{Codec, Decode, Encode},
15 ipld::Ipld,
16};
17use noosphere_common::{ConditionalSend, ConditionalSync};
18use serde::{de::DeserializeOwned, Serialize};
19
20#[cfg(doc)]
21use serde::Deserialize;
22
23#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
29#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
30pub trait BlockStore: Clone + ConditionalSync {
31 #[allow(unused_variables)]
37 async fn put_links<C>(&mut self, cid: &Cid, block: &[u8]) -> Result<()>
38 where
39 C: Codec + Default,
40 Ipld: References<C>,
41 {
42 Ok(())
43 }
44
45 async fn put_block(&mut self, cid: &Cid, block: &[u8]) -> Result<()>;
47
48 async fn get_block(&self, cid: &Cid) -> Result<Option<Vec<u8>>>;
50
51 async fn put<C, T>(&mut self, data: T) -> Result<Cid>
55 where
56 C: Codec + Default,
57 T: Encode<C> + ConditionalSend,
58 Ipld: References<C>,
59 {
60 let codec = C::default();
61 let block = codec.encode(&data)?;
62 let cid = Cid::new_v1(codec.into(), Code::Blake3_256.digest(&block));
63
64 self.put_block(&cid, &block).await?;
65 self.put_links::<C>(&cid, &block).await?;
66
67 Ok(cid)
68 }
69
70 async fn get<C, T>(&self, cid: &Cid) -> Result<Option<T>>
74 where
75 C: Codec + Default,
76 T: Decode<C>,
77 {
78 let codec = C::default();
79 let block = self.get_block(cid).await?;
80
81 Ok(match block {
82 Some(bytes) => Some(T::decode(codec, &mut Cursor::new(bytes))?),
83 None => None,
84 })
85 }
86
87 async fn save<C, T>(&mut self, data: T) -> Result<Cid>
92 where
93 C: Codec + Default,
94 T: Serialize + ConditionalSend,
95 Ipld: Encode<C> + References<C>,
96 {
97 self.put::<C, Ipld>(to_ipld(data)?).await
98 }
99
100 async fn load<C, T>(&self, cid: &Cid) -> Result<T>
105 where
106 C: Codec + Default,
107 T: DeserializeOwned + ConditionalSend,
108 u64: From<C>,
109 Ipld: Decode<C>,
110 {
111 let codec = u64::from(C::default());
112
113 if cid.codec() != codec {
114 return Err(anyhow!(
115 "Incorrect codec; expected {}, but CID refers to {}",
116 codec,
117 cid.codec()
118 ));
119 }
120
121 Ok(match self.get::<C, Ipld>(cid).await? {
122 Some(ipld) => from_ipld(ipld)?,
123 None => return Err(anyhow!("No block found for {}", cid)),
124 })
125 }
126
127 async fn require_block(&self, cid: &Cid) -> Result<Vec<u8>> {
130 match self.get_block(cid).await? {
131 Some(block) => Ok(block),
132 None => Err(anyhow!("Block {cid} was required but not found")),
133 }
134 }
135
136 async fn flush(&self) -> Result<()> {
138 Ok(())
139 }
140}