wnfs_common/
storable.rs

1//! Defines the [`Storable`] trait, which defines the `.load` and `.store` functions
2//! that are implemented for most WNFS structures, such as `PublicFile`, `PublicDirectory`,
3//! `PublicNode`, `HamtForest` etc.
4use crate::{
5    BlockStore, CODEC_DAG_CBOR,
6    utils::{Arc, CondSend, CondSync},
7};
8use anyhow::{Result, bail};
9use async_once_cell::OnceCell;
10use bytes::Bytes;
11use cid::Cid;
12use futures::Future;
13use serde::{Serialize, de::DeserializeOwned};
14
15//--------------------------------------------------------------------------------------------------
16// Macros
17//--------------------------------------------------------------------------------------------------
18
19#[macro_export]
20macro_rules! impl_storable_from_serde {
21    ( $( $ty:ty $( : < $( $generics:ident ),+ > )? ),+ ) => {
22        $(
23            impl $( < $( $generics ),+ > )? $crate::Storable for $ty $( where $( $generics: ::serde::Serialize + ::serde::de::DeserializeOwned + Clone + $crate::utils::CondSync ),+  )?{
24                type Serializable = $ty;
25
26                async fn to_serializable(&self, _store: &impl $crate::BlockStore) -> ::anyhow::Result<Self::Serializable> {
27                    Ok(self.clone())
28                }
29
30                async fn from_serializable(_cid: Option<&$crate::Cid>, serializable: Self::Serializable) -> ::anyhow::Result<Self> {
31                    Ok(serializable)
32                }
33            }
34        )+
35    };
36}
37
38//--------------------------------------------------------------------------------------------------
39// Type Definitions
40//--------------------------------------------------------------------------------------------------
41
42/// The trait that defines how to store something in a blockstore.
43///
44/// This works via a two-tiered system, where the actual in-memory representation
45/// (the struct that implements this trait) is not the same as the at-rest
46/// representation of itself.
47/// The at-rest representation is given by the `Serializable` associated type.
48///
49/// Commonly, the `Serializable` type implements serde's `Serialize` and `Deserialize`
50/// traits and thus can automatically be used without having to implement `StoreIpld`
51/// and `LoadIpld` yourself. In that case, the default implementation will use
52/// `serde_ipld_dagcbor`.
53///
54/// This trait also optionally supports memoizing serialization via the `persisted_as` function.
55/// You can add a field `persisted_as: OnceCell<Cid>` to your in-memory representation and
56/// return it in the `persisted_as` function and any `store` calls will automatically populate
57/// that cache.
58/// If you do so, remember to initialize the `OnceCell` if a `Cid` is passed in the
59/// `from_serializable` call, such that a `store` call right after a `load` call is practically
60/// free.
61pub trait Storable: Sized {
62    /// The at-rest representation of this storable type.
63    type Serializable: StoreIpld + LoadIpld + CondSync;
64
65    /// Turn the current type into the at-rest representation of this type.
66    fn to_serializable(
67        &self,
68        store: &impl BlockStore,
69    ) -> impl Future<Output = Result<Self::Serializable>> + CondSend;
70
71    /// Take an at-rest representation of this type and turn it into the in-memory representation.
72    /// You can use the `cid` parameter to populate a cache.
73    fn from_serializable(
74        cid: Option<&Cid>,
75        serializable: Self::Serializable,
76    ) -> impl Future<Output = Result<Self>> + CondSend;
77
78    /// Return a serialization cache, if it exists.
79    /// By default, this always returns `None`.
80    fn persisted_as(&self) -> Option<&OnceCell<Cid>> {
81        None
82    }
83
84    /// Store this data type in a given `BlockStore`.
85    ///
86    /// This will short-circuit by using the `persisted_as` once-cell, if available.
87    fn store(&self, store: &impl BlockStore) -> impl Future<Output = Result<Cid>> + CondSend
88    where
89        Self: CondSync,
90    {
91        let store_future = async {
92            let (bytes, codec) = self.to_serializable(store).await?.encode_ipld()?;
93            Ok(store.put_block(bytes, codec).await?)
94        };
95
96        async {
97            if let Some(persisted_as) = self.persisted_as() {
98                persisted_as.get_or_try_init(store_future).await.cloned()
99            } else {
100                store_future.await
101            }
102        }
103    }
104
105    /// Try to load a value of this type from a CID.
106    ///
107    /// This will pass on the CID to the `from_serializable` function so it can
108    /// populate a cache in some cases.
109    fn load(cid: &Cid, store: &impl BlockStore) -> impl Future<Output = Result<Self>> + CondSend {
110        async {
111            let bytes = store.get_block(cid).await?;
112            let serializable = Self::Serializable::decode_ipld(cid, bytes)?;
113            Self::from_serializable(Some(cid), serializable).await
114        }
115    }
116}
117
118pub trait StoreIpld {
119    fn encode_ipld(&self) -> Result<(Bytes, u64)>;
120}
121
122pub trait LoadIpld: Sized {
123    fn decode_ipld(cid: &Cid, bytes: Bytes) -> Result<Self>;
124}
125
126impl<T: Serialize> StoreIpld for T {
127    fn encode_ipld(&self) -> Result<(Bytes, u64)> {
128        let bytes = serde_ipld_dagcbor::to_vec(self)?;
129        Ok((bytes.into(), CODEC_DAG_CBOR))
130    }
131}
132
133impl<T: DeserializeOwned + Sized> LoadIpld for T {
134    fn decode_ipld(cid: &Cid, bytes: Bytes) -> Result<Self> {
135        let codec = cid.codec();
136        let dag_cbor: u64 = CODEC_DAG_CBOR;
137        if codec != dag_cbor {
138            bail!("Expected dag-cbor codec, but got {codec:X} in CID {cid}");
139        }
140        Ok(serde_ipld_dagcbor::from_slice(bytes.as_ref())?)
141    }
142}
143
144//--------------------------------------------------------------------------------------------------
145// Implementations
146//--------------------------------------------------------------------------------------------------
147
148// We need to choose *one* blanket implementation, and unfortunately
149// you can't `impl Storable for Arc<MyType>` outside of this module,
150// because that'd be an orphan instance. So instead we're providing a
151// macro and implement the `Arc<T>` instance generically here.
152
153// #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
154// #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
155// impl<T: StoreIpld + LoadIpld + CondSync + Clone> Storable for T {
156//     type Serializable = T;
157
158//     async fn to_serializable(&self, _store: &impl BlockStore) -> Result<Self::Serializable> {
159//         Ok(self.clone())
160//     }
161
162//     async fn from_serializable(serializable: Self::Serializable) -> Result<Self> {
163//         Ok(serializable)
164//     }
165// }
166
167impl<T: Storable + CondSync> Storable for Arc<T> {
168    type Serializable = T::Serializable;
169
170    async fn to_serializable(&self, store: &impl BlockStore) -> Result<Self::Serializable> {
171        self.as_ref().to_serializable(store).await
172    }
173
174    async fn from_serializable(
175        cid: Option<&Cid>,
176        serializable: Self::Serializable,
177    ) -> Result<Self> {
178        Ok(Arc::new(T::from_serializable(cid, serializable).await?))
179    }
180
181    fn persisted_as(&self) -> Option<&OnceCell<Cid>> {
182        self.as_ref().persisted_as()
183    }
184}
185
186impl_storable_from_serde! { [u8; 0], [u8; 1], [u8; 2], [u8; 4], [u8; 8], [u8; 16], [u8; 32] }
187impl_storable_from_serde! { usize, u128, u64, u32, u16, u8, isize, i128, i64, i32, i16, i8 }
188impl_storable_from_serde! { String }
189impl_storable_from_serde! {
190    (A,): <A>,
191    (A, B): <A, B>,
192    (A, B, C): <A, B, C>,
193    (A, B, C, D): <A, B, C, D>,
194    (A, B, C, D, E): <A, B, C, D, E>,
195    (A, B, C, D, E, F): <A, B, C, D, E, F>,
196    (A, B, C, D, E, F, G): <A, B, C, D, E, F, G>,
197    (A, B, C, D, E, F, G, H): <A, B, C, D, E, F, G, H>,
198    (A, B, C, D, E, F, G, H, I): <A, B, C, D, E, F, G, H, I>,
199    (A, B, C, D, E, F, G, H, I, J): <A, B, C, D, E, F, G, H, I, J>,
200    (A, B, C, D, E, F, G, H, I, J, K): <A, B, C, D, E, F, G, H, I, J, K>
201}