1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//! Defines the [`Storable`] trait, which defines the `.load` and `.store` functions
//! that are implemented for most WNFS structures, such as `PublicFile`, `PublicDirectory`,
//! `PublicNode`, `HamtForest` etc.
use crate::{
    utils::{Arc, CondSync},
    BlockStore,
};
use anyhow::{bail, Result};
use async_once_cell::OnceCell;
use async_trait::async_trait;
use bytes::Bytes;
use libipld::{cbor::DagCborCodec, Cid};
use serde::{de::DeserializeOwned, Serialize};

//--------------------------------------------------------------------------------------------------
// Macros
//--------------------------------------------------------------------------------------------------

#[macro_export]
macro_rules! impl_storable_from_serde {
    ( $( $ty:ty $( : < $( $generics:ident ),+ > )? ),+ ) => {
        $(
            #[cfg_attr(not(target_arch = "wasm32"), ::async_trait::async_trait)]
            #[cfg_attr(target_arch = "wasm32", ::async_trait::async_trait(?Send))]
            impl $( < $( $generics ),+ > )? $crate::Storable for $ty $( where $( $generics: ::serde::Serialize + ::serde::de::DeserializeOwned + Clone + $crate::utils::CondSync ),+  )?{
                type Serializable = $ty;

                async fn to_serializable(&self, _store: &impl $crate::BlockStore) -> ::anyhow::Result<Self::Serializable> {
                    Ok(self.clone())
                }

                async fn from_serializable(_cid: Option<&$crate::libipld::Cid>, serializable: Self::Serializable) -> ::anyhow::Result<Self> {
                    Ok(serializable)
                }
            }
        )+
    };
}

pub use impl_storable_from_serde;

//--------------------------------------------------------------------------------------------------
// Type Definitions
//--------------------------------------------------------------------------------------------------

/// The trait that defines how to store something in a blockstore.
///
/// This works via a two-tiered system, where the actual in-memory representation
/// (the struct that implements this trait) is not the same as the at-rest
/// representation of itself.
/// The at-rest representation is given by the `Serializable` associated type.
///
/// Commonly, the `Serializable` type implements serde's `Serialize` and `Deserialize`
/// traits and thus can automatically be used without having to implement `StoreIpld`
/// and `LoadIpld` yourself. In that case, the default implementation will use
/// `serde_ipld_dagcbor`.
///
/// This trait also optionally supports memoizing serialization via the `persisted_as` function.
/// You can add a field `persisted_as: OnceCell<Cid>` to your in-memory representation and
/// return it in the `persisted_as` function and any `store` calls will automatically populate
/// that cache.
/// If you do so, remember to initialize the `OnceCell` if a `Cid` is passed in the
/// `from_serializable` call, such that a `store` call right after a `load` call is practically
/// free.
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
pub trait Storable: Sized {
    /// The at-rest representation of this storable type.
    type Serializable: StoreIpld + LoadIpld + CondSync;

    /// Turn the current type into the at-rest representation of this type.
    async fn to_serializable(&self, store: &impl BlockStore) -> Result<Self::Serializable>;

    /// Take an at-rest representation of this type and turn it into the in-memory representation.
    /// You can use the `cid` parameter to populate a cache.
    async fn from_serializable(cid: Option<&Cid>, serializable: Self::Serializable)
        -> Result<Self>;

    /// Return a serialization cache, if it exists.
    /// By default, this always returns `None`.
    fn persisted_as(&self) -> Option<&OnceCell<Cid>> {
        None
    }

    /// Store this data type in a given `BlockStore`.
    ///
    /// This will short-circuit by using the `persisted_as` once-cell, if available.
    async fn store(&self, store: &impl BlockStore) -> Result<Cid> {
        let store_future = async {
            let (bytes, codec) = self.to_serializable(store).await?.encode_ipld()?;
            store.put_block(bytes, codec).await
        };

        if let Some(persisted_as) = self.persisted_as() {
            persisted_as.get_or_try_init(store_future).await.cloned()
        } else {
            store_future.await
        }
    }

    /// Try to load a value of this type from a CID.
    ///
    /// This will pass on the CID to the `from_serializable` function so it can
    /// populate a cache in some cases.
    async fn load(cid: &Cid, store: &impl BlockStore) -> Result<Self> {
        let bytes = store.get_block(cid).await?;
        let serializable = Self::Serializable::decode_ipld(cid, bytes)?;
        Self::from_serializable(Some(cid), serializable).await
    }
}

pub trait StoreIpld {
    fn encode_ipld(&self) -> Result<(Bytes, u64)>;
}

pub trait LoadIpld: Sized {
    fn decode_ipld(cid: &Cid, bytes: Bytes) -> Result<Self>;
}

impl<T: Serialize> StoreIpld for T {
    fn encode_ipld(&self) -> Result<(Bytes, u64)> {
        let bytes = serde_ipld_dagcbor::to_vec(self)?;
        Ok((bytes.into(), DagCborCodec.into()))
    }
}

impl<T: DeserializeOwned + Sized> LoadIpld for T {
    fn decode_ipld(cid: &Cid, bytes: Bytes) -> Result<Self> {
        let codec = cid.codec();
        let dag_cbor: u64 = DagCborCodec.into();
        if codec != dag_cbor {
            bail!("Expected dag-cbor codec, but got {codec:X} in CID {cid}");
        }
        Ok(serde_ipld_dagcbor::from_slice(bytes.as_ref())?)
    }
}

//--------------------------------------------------------------------------------------------------
// Implementations
//--------------------------------------------------------------------------------------------------

// We need to choose *one* blanket implementation, and unfortunately
// you can't `impl Storable for Arc<MyType>` outside of this module,
// because that'd be an orphan instance. So instead we're providing a
// macro and implement the `Arc<T>` instance generically here.

// #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
// #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
// impl<T: StoreIpld + LoadIpld + CondSync + Clone> Storable for T {
//     type Serializable = T;

//     async fn to_serializable(&self, _store: &impl BlockStore) -> Result<Self::Serializable> {
//         Ok(self.clone())
//     }

//     async fn from_serializable(serializable: Self::Serializable) -> Result<Self> {
//         Ok(serializable)
//     }
// }

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl<T: Storable + CondSync> Storable for Arc<T> {
    type Serializable = T::Serializable;

    async fn to_serializable(&self, store: &impl BlockStore) -> Result<Self::Serializable> {
        self.as_ref().to_serializable(store).await
    }

    async fn from_serializable(
        cid: Option<&Cid>,
        serializable: Self::Serializable,
    ) -> Result<Self> {
        Ok(Arc::new(T::from_serializable(cid, serializable).await?))
    }

    fn persisted_as(&self) -> Option<&OnceCell<Cid>> {
        self.as_ref().persisted_as()
    }
}

impl_storable_from_serde! { [u8; 0], [u8; 1], [u8; 2], [u8; 4], [u8; 8], [u8; 16], [u8; 32] }
impl_storable_from_serde! { usize, u128, u64, u32, u16, u8, isize, i128, i64, i32, i16, i8 }
impl_storable_from_serde! { String }
impl_storable_from_serde! {
    (A,): <A>,
    (A, B): <A, B>,
    (A, B, C): <A, B, C>,
    (A, B, C, D): <A, B, C, D>,
    (A, B, C, D, E): <A, B, C, D, E>,
    (A, B, C, D, E, F): <A, B, C, D, E, F>,
    (A, B, C, D, E, F, G): <A, B, C, D, E, F, G>,
    (A, B, C, D, E, F, G, H): <A, B, C, D, E, F, G, H>,
    (A, B, C, D, E, F, G, H, I): <A, B, C, D, E, F, G, H, I>,
    (A, B, C, D, E, F, G, H, I, J): <A, B, C, D, E, F, G, H, I, J>,
    (A, B, C, D, E, F, G, H, I, J, K): <A, B, C, D, E, F, G, H, I, J, K>
}