1
//! Object-safe, type-safe wrappers for [`StateMgr`].
2

            
3
use crate::{Result, StateMgr};
4
use serde::{de::DeserializeOwned, Serialize};
5
use std::marker::PhantomData;
6
use std::sync::Arc;
7

            
8
/// A handle to a storage system that stores objects of a single
9
/// type to a single location.
10
///
11
/// To get an object of this type, call [`StateMgr::create_handle`].
12
///
13
/// Unlike StateMgr, this trait is object-safe.
14
pub trait StorageHandle<T: Serialize + DeserializeOwned> {
15
    /// Try to load the object from storage.
16
    ///
17
    /// If no object exists, return Ok(None).
18
    fn load(&self) -> Result<Option<T>>;
19

            
20
    /// Try to store a value into storage.
21
    fn store(&self, val: &T) -> Result<()>;
22

            
23
    /// Return true if we have the lock; see [`StateMgr::can_store`].
24
    fn can_store(&self) -> bool;
25
}
26

            
27
/// Type wrapper for a reference-counted `dyn` [`StorageHandle`].
28
///
29
/// Most users of this crate will want to access storage via a handle
30
/// of this kind, so that they don't have to parameterize over
31
/// [`StateMgr`].  The cost of using a fat pointer here should be
32
/// pretty small compared to the overhead of persistent storage in
33
/// general.
34
pub type DynStorageHandle<T> = Arc<dyn StorageHandle<T> + Send + Sync + 'static>;
35

            
36
/// Concrete implementation of [`StorageHandle`].
37
#[derive(Debug)]
38
pub(crate) struct StorageHandleImpl<M, T> {
39
    /// An underlying [`StateMgr`] to use.
40
    ///
41
    /// The type `M` should probably implement Clone, since we store it
42
    /// here and don't give it back.
43
    mgr: M,
44
    /// The key to use when loading and storing from the [`StateMgr`].
45
    key: String,
46
    /// A zero-sized type to please the type checker, which will otherwise
47
    /// complain about the absence of anything in the struct that uses T.
48
    ///
49
    /// This uses `fn(T) -> T` to ensure that the type T is mentioned and
50
    /// has the correct variance, without forcing this type to have
51
    /// the same `Send`/`Sync` status as T.
52
    phantom: PhantomData<fn(T) -> T>,
53
}
54

            
55
impl<M, T> StorageHandle<T> for StorageHandleImpl<M, T>
56
where
57
    M: StateMgr,
58
    T: Serialize + DeserializeOwned + 'static,
59
{
60
39
    fn load(&self) -> Result<Option<T>> {
61
39
        self.mgr.load(&self.key)
62
39
    }
63
10
    fn store(&self, val: &T) -> Result<()> {
64
10
        self.mgr.store(&self.key, val)
65
10
    }
66
11
    fn can_store(&self) -> bool {
67
11
        self.mgr.can_store()
68
11
    }
69
}
70

            
71
impl<M, T> StorageHandleImpl<M, T>
72
where
73
    M: Send + Sync + 'static,
74
    T: Serialize + DeserializeOwned + 'static,
75
{
76
    /// Construct a new StorageHandleImpl.
77
33
    pub(crate) fn new(mgr: M, key: String) -> StorageHandleImpl<M, T> {
78
33
        StorageHandleImpl {
79
33
            mgr,
80
33
            key,
81
33
            phantom: PhantomData,
82
33
        }
83
33
    }
84
}