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 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}