Skip to main content

nectar_primitives/store/
typed.rs

1//! Typed chunk storage traits.
2//!
3//! `ChunkGet`, `ChunkPut`, and `ChunkHas` are async and carry `MaybeSend`/
4//! `MaybeSync` bounds so a store may be `!Send` on wasm.
5
6use std::future::Future;
7
8use super::maybe_send::{MaybeSend, MaybeSync};
9use crate::bmt::DEFAULT_BODY_SIZE;
10use crate::chunk::{AnyChunk, ChunkAddress};
11
12/// Async chunk retrieval (primary API).
13pub trait ChunkGet<const BODY_SIZE: usize = DEFAULT_BODY_SIZE>: MaybeSend + MaybeSync {
14    /// Error type for get operations.
15    type Error: std::error::Error + Send + Sync + 'static;
16
17    /// Get a chunk by address.
18    fn get(
19        &self,
20        address: &ChunkAddress,
21    ) -> impl Future<Output = Result<AnyChunk<BODY_SIZE>, Self::Error>> + MaybeSend;
22}
23
24impl<T: ChunkGet<BS> + ?Sized, const BS: usize> ChunkGet<BS> for &T {
25    type Error = T::Error;
26
27    fn get(
28        &self,
29        address: &ChunkAddress,
30    ) -> impl Future<Output = Result<AnyChunk<BS>, Self::Error>> + MaybeSend {
31        (**self).get(address)
32    }
33}
34
35/// Async chunk existence check (primary API).
36pub trait ChunkHas<const BODY_SIZE: usize = DEFAULT_BODY_SIZE>: MaybeSend + MaybeSync {
37    /// Check if a chunk exists.
38    fn has(&self, address: &ChunkAddress) -> impl Future<Output = bool> + MaybeSend;
39}
40
41impl<T: ChunkHas<BS> + ?Sized, const BS: usize> ChunkHas<BS> for &T {
42    fn has(&self, address: &ChunkAddress) -> impl Future<Output = bool> + MaybeSend {
43        (**self).has(address)
44    }
45}
46
47/// Async chunk storage (primary API, `&self`).
48///
49/// Implementors should use interior mutability (e.g. `Mutex`, `RwLock`).
50pub trait ChunkPut<const BODY_SIZE: usize = DEFAULT_BODY_SIZE>: MaybeSend + MaybeSync {
51    /// Error type for put operations.
52    type Error: std::error::Error + Send + Sync + 'static;
53
54    /// Store a chunk.
55    fn put(
56        &self,
57        chunk: AnyChunk<BODY_SIZE>,
58    ) -> impl Future<Output = Result<(), Self::Error>> + MaybeSend;
59}
60
61impl<T: ChunkPut<BS> + ?Sized, const BS: usize> ChunkPut<BS> for &T {
62    type Error = T::Error;
63
64    fn put(
65        &self,
66        chunk: AnyChunk<BS>,
67    ) -> impl Future<Output = Result<(), Self::Error>> + MaybeSend {
68        (**self).put(chunk)
69    }
70}
71
72#[cfg(target_arch = "wasm32")]
73mod wasm_send_sync_proof {
74    // A store that is neither Send nor Sync (raw pointer marker) must still
75    // satisfy ChunkGet on wasm32, proving the MaybeSend + MaybeSync relaxation.
76    use super::*;
77
78    struct NotSendSync(core::marker::PhantomData<*const ()>);
79
80    impl<const BS: usize> ChunkGet<BS> for NotSendSync {
81        type Error = std::io::Error;
82        async fn get(&self, _addr: &ChunkAddress) -> Result<AnyChunk<BS>, Self::Error> {
83            unreachable!()
84        }
85    }
86
87    fn _assert<const BS: usize, S: ChunkGet<BS>>() {}
88
89    #[allow(dead_code)]
90    fn _proof() {
91        _assert::<{ DEFAULT_BODY_SIZE }, NotSendSync>()
92    }
93}