nonasync/
persistence.rs

1use std::error::Error;
2use std::fmt::Debug;
3
4pub trait CloneNoPersistence: Sized {
5    fn clone_no_persistence(&self) -> Self;
6}
7
8#[derive(Debug, Display, Error)]
9#[display(inner)]
10pub struct PersistenceError(pub Box<dyn Error + Send>);
11
12impl PersistenceError {
13    pub fn with<E: Error + Send + 'static>(e: E) -> Self { Self(Box::new(e)) }
14}
15
16pub trait PersistenceProvider<T>: Send + Sync + Debug {
17    fn load(&self) -> Result<T, PersistenceError>;
18    fn store(&self, object: &T) -> Result<(), PersistenceError>;
19}
20
21#[derive(Debug)]
22pub struct Persistence<T: Persisting> {
23    pub dirty: bool,
24    pub autosave: bool,
25    pub provider: Box<dyn PersistenceProvider<T>>,
26}
27
28impl<T: Persisting> Persistence<T> {
29    pub fn load(
30        provider: impl PersistenceProvider<T> + 'static,
31        autosave: bool,
32    ) -> Result<T, PersistenceError> {
33        let mut obj: T = provider.load()?;
34        obj.as_mut_persistence().replace(Self {
35            dirty: false,
36            autosave,
37            provider: Box::new(provider),
38        });
39        Ok(obj)
40    }
41}
42
43pub trait Persisting: Sized {
44    #[inline]
45    fn load(
46        provider: impl PersistenceProvider<Self> + 'static,
47        autosave: bool,
48    ) -> Result<Self, PersistenceError> {
49        Persistence::load(provider, autosave)
50    }
51
52    fn persistence(&self) -> Option<&Persistence<Self>>;
53
54    fn persistence_mut(&mut self) -> Option<&mut Persistence<Self>>;
55
56    fn as_mut_persistence(&mut self) -> &mut Option<Persistence<Self>>;
57
58    fn is_persisted(&self) -> bool { self.persistence().is_some() }
59
60    fn is_dirty(&self) -> bool { self.persistence().map(|p| p.dirty).unwrap_or(true) }
61
62    fn mark_dirty(&mut self) {
63        if let Some(p) = self.persistence_mut() {
64            p.dirty = true;
65        }
66        if let Some(p) = self.persistence() {
67            if p.autosave {
68                if let Err(e) = p.provider.store(self) {
69                    #[cfg(feature = "log")]
70                    log::error!(
71                        "Unable to autosave a dirty object on Persisting::mark_dirty call. \
72                         Details: {e}"
73                    );
74                    #[cfg(not(feature = "log"))]
75                    eprintln!("Unable to autosave a dirty object on Persisting::mark_dirty call. \
76                         Details: {e}")
77                }
78            }
79        }
80    }
81
82    fn is_autosave(&self) -> bool { self.persistence().map(|p| p.autosave).unwrap_or_default() }
83
84    fn set_autosave(&mut self) {
85        if let Err(e) = self.store() {
86            #[cfg(feature = "log")]
87            log::error!(
88                "Unable to autosave a dirty object on Persisting::set_autosave call. Details: {e}"
89            );
90            #[cfg(not(feature = "log"))]
91            eprintln!("Unable to autosave a dirty object on Persisting::mark_dirty call. \
92                         Details: {e}")
93        }
94    }
95
96    /// Returns whether the object was persisting before this method.
97    fn make_persistent(
98        &mut self,
99        provider: impl PersistenceProvider<Self> + 'static,
100        autosave: bool,
101    ) -> Result<bool, PersistenceError> {
102        let was_persisted = self.is_persisted();
103        self.as_mut_persistence().replace(Persistence {
104            dirty: true,
105            autosave,
106            provider: Box::new(provider),
107        });
108        self.store()?;
109        Ok(was_persisted)
110    }
111
112    fn store(&mut self) -> Result<(), PersistenceError> {
113        if self.is_dirty() {
114            if let Some(p) = self.persistence() {
115                p.provider.store(self)?;
116            }
117            if let Some(p) = self.persistence_mut() {
118                p.dirty = false;
119            }
120        }
121        Ok(())
122    }
123}