1use crate::prelude::*;
4
5#[derive(Component, Debug, Resource)]
14pub struct Persistent<R: Resource + Serialize + DeserializeOwned> {
15 pub(crate) name: String,
16 pub(crate) format: StorageFormat,
17 pub(crate) storage: Storage,
18 pub(crate) resource: Option<R>,
19 pub(crate) default: Option<Box<R>>,
20 pub(crate) revert_to_default_on_deserialization_errors: bool,
21}
22
23impl<R: Resource + Serialize + DeserializeOwned> Persistent<R> {
24 pub fn builder() -> PersistentBuilder<R> {
26 PersistentBuilder {
27 name: None,
28 format: None,
29 path: None,
30 loaded: true,
31 default: None,
32 revertible: false,
33 revert_to_default_on_deserialization_errors: false,
34 }
35 }
36
37 pub fn new(
44 name: impl ToString,
45 format: StorageFormat,
46 storage: Storage,
47 loaded: bool,
48 default: R,
49 revertible: bool,
50 revert_to_default_on_deserialization_errors: bool,
51 ) -> Result<Persistent<R>, PersistenceError> {
52 if revert_to_default_on_deserialization_errors && !revertible {
53 panic!(
54 "revert to default on deserialization errors \
55 is set for a non-revertible persistent resource"
56 );
57 }
58
59 let name = name.to_string();
60
61 if !storage.occupied() {
62 storage.initialize().map_err(|error| {
65 log::error!(
67 "failed to create the parent directory for {} at {}: {}",
68 name,
69 storage,
70 error,
71 );
72 error
73 })?;
74
75 storage
76 .write(&name, format, &default)
77 .map(|_| {
78 log::info!("saved default {} to {}", name, storage);
79 })
80 .map_err(|error| {
81 if !error.is_serde() {
83 log::error!("failed to save default {} to {}: {}", name, storage, error);
84 } else {
85 log::error!(
86 "failed to save default {} to {} due to a serialization error",
87 name,
88 storage,
89 );
90 }
91 error
92 })?;
93
94 let resource = if loaded {
95 let serialized = format.serialize(&name, &default).inspect_err(|_| {
100 log::error!("failed to clone default {} due to a serialization error", name);
101 })?;
102 let reconstructed = format.deserialize(&name, &serialized).inspect_err(|_| {
103 log::error!("failed to clone default {} due to a deserialization error", name);
104 })?;
105
106 Some(reconstructed)
107 } else {
108 None
109 };
110 let default = if revertible { Some(Box::new(default)) } else { None };
111
112 return Ok(Persistent {
113 name,
114 format,
115 storage,
116 resource,
117 default,
118 revert_to_default_on_deserialization_errors,
119 });
120 }
121
122 let default = if revertible { Some(Box::new(default)) } else { None };
123
124 if !loaded {
125 return Ok(Persistent {
126 name,
127 format,
128 storage,
129 resource: None,
130 default,
131 revert_to_default_on_deserialization_errors,
132 });
133 }
134
135 let resource = match storage.read(&name, format) {
136 Ok(resource) => resource,
137 Err(error) => {
138 if !error.is_serde() {
139 log::error!("failed to load {} from {}: {}", name, storage, error);
140 } else {
141 log::error!(
142 "failed to load {} from {} due to a deserialization error",
143 name,
144 storage,
145 );
146
147 if revert_to_default_on_deserialization_errors {
148 log::info!(
149 "attempting to revert {} to default in {} automatically",
150 name,
151 storage,
152 );
153
154 let mut result = Persistent {
155 name,
156 format,
157 storage,
158 resource: None,
159 default,
160 revert_to_default_on_deserialization_errors,
161 };
162 if result.revert_to_default().is_err() {
163 return Err(error);
165 }
166 if loaded && result.revert_to_default_in_memory().is_err() {
167 return Err(error);
169 }
170
171 return Ok(result);
172 }
173 }
174 return Err(error);
175 },
176 };
177
178 log::info!("loaded {} from {}", name, storage);
179
180 Ok(Persistent {
181 name,
182 format,
183 storage,
184 resource: Some(resource),
185 default,
186 revert_to_default_on_deserialization_errors,
187 })
188 }
189}
190
191impl<R: Resource + Serialize + DeserializeOwned> Persistent<R> {
192 pub fn name(&self) -> &str {
194 &self.name
195 }
196
197 pub fn format(&self) -> StorageFormat {
199 self.format
200 }
201
202 pub fn storage(&self) -> &Storage {
204 &self.storage
205 }
206
207 pub fn is_revertible(&self) -> bool {
209 self.default.is_some()
210 }
211
212 pub fn is_loaded(&self) -> bool {
214 self.resource.is_some()
215 }
216
217 pub fn is_unloaded(&self) -> bool {
219 self.resource.is_none()
220 }
221
222 pub fn get(&self) -> &R {
228 if let Some(resource) = &self.resource {
229 resource
230 } else {
231 panic!("tried to get unloaded {}", self.name);
232 }
233 }
234
235 pub fn get_mut(&mut self) -> &mut R {
241 if let Some(resource) = &mut self.resource {
242 resource
243 } else {
244 panic!("tried to get unloaded {} mutably", self.name);
245 }
246 }
247
248 pub fn try_get(&self) -> Option<&R> {
250 self.resource.as_ref()
251 }
252
253 pub fn try_get_mut(&mut self) -> Option<&mut R> {
255 self.resource.as_mut()
256 }
257}
258
259impl<R: Resource + Serialize + DeserializeOwned> Persistent<R> {
260 pub fn set(&mut self, new_resource: R) -> Result<(), PersistenceError> {
264 self.resource = Some(new_resource);
265 self.persist()
266 }
267
268 pub fn update(&mut self, updater: impl Fn(&mut R)) -> Result<(), PersistenceError> {
276 if let Some(resource) = self.resource.as_mut() {
277 updater(resource);
278 self.persist()
279 } else {
280 panic!("tried to update unloaded {}", self.name);
281 }
282 }
283
284 pub fn unload(&mut self) -> Result<(), PersistenceError> {
292 if self.resource.is_some() {
293 self.persist().inspect_err(|_| {
294 log::error!(
295 "failed to unload {} due to not being able to persist it before unloading",
296 self.name,
297 );
298 })?;
299 self.resource = None;
300 log::info!("unloaded {}", self.name);
301 }
302 Ok(())
303 }
304
305 pub fn unload_without_persisting(&mut self) {
309 if self.resource.is_some() {
310 self.resource = None;
311 log::info!("unloaded {} without persisting", self.name);
312 }
313 }
314
315 pub fn reload(&mut self) -> Result<(), PersistenceError> {
319 match self.storage.read(&self.name, self.format) {
320 Ok(resource) => self.resource = Some(resource),
321 Err(error) => {
322 if !error.is_serde() {
323 log::error!("failed to reload {} from {}: {}", self.name, self.storage, error);
324 } else {
325 log::error!(
326 "failed to reload {} from {} due to a deserialization error",
327 self.storage,
328 self.name,
329 );
330
331 if self.revert_to_default_on_deserialization_errors {
332 log::info!(
333 "attempting to revert {} to default in {} automatically",
334 self.name,
335 self.storage,
336 );
337 if self.revert_to_default().is_err() {
338 return Err(error);
340 }
341 return Ok(());
342 }
343 }
344 return Err(error);
345 },
346 }
347 log::info!("reloaded {} from {}", self.name, self.storage);
348 Ok(())
349 }
350
351 pub fn revert_to_default(&mut self) -> Result<(), PersistenceError> {
359 if !self.is_revertible() {
360 panic!("tried to revert non-revertible {}", self.name);
361 }
362
363 self.storage
364 .write(&self.name, self.format, self.default.as_ref().unwrap())
365 .map(|_| {
366 log::info!("reverted {} to default in {}", self.name, self.storage);
367 })
368 .map_err(|error| {
369 if !error.is_serde() {
371 log::error!(
372 "failed to revert {} to default in {}: {}",
373 self.name,
374 self.storage,
375 error,
376 );
377 } else {
378 log::error!(
379 "failed to revert {} to default in {} due to a serialization error",
380 self.name,
381 self.storage,
382 );
383 }
384 error
385 })?;
386
387 if self.is_loaded() {
388 self.revert_to_default_in_memory()?;
389 }
390
391 Ok(())
392 }
393
394 pub fn revert_to_default_in_memory(&mut self) -> Result<(), PersistenceError> {
400 if !self.is_revertible() {
401 panic!("tried to revert non-revertible {}", self.name);
402 }
403
404 let serialized = self
409 .format
410 .serialize(&self.name, self.default.as_ref().unwrap())
411 .inspect_err(|_| {
412 log::error!(
413 "failed to revert {} to default in memory due to a serialization error",
414 self.name,
415 );
416 })?;
417 let reconstructed = self.format.deserialize(&self.name, &serialized).inspect_err(|_| {
418 log::error!(
419 "failed to revert {} to default in memory due to a deserialization error",
420 self.name,
421 );
422 })?;
423
424 self.resource = Some(reconstructed);
425 log::info!("reverted {} to default in memory", self.name);
426 Ok(())
427 }
428}
429
430impl<R: Resource + Serialize + DeserializeOwned> Persistent<R> {
431 pub fn persist(&self) -> Result<(), PersistenceError> {
437 if let Some(resource) = &self.resource {
438 self.storage
439 .write(&self.name, self.format, resource)
440 .map(|_| {
441 log::info!("saved new {} to {}", self.name, self.storage);
442 })
443 .map_err(|error| {
444 if !error.is_serde() {
446 log::error!(
447 "failed to save new {} to {}: {}",
448 self.name,
449 self.storage,
450 error,
451 );
452 } else {
453 log::error!(
454 "failed to save new {} to {} due to a serialization error",
455 self.name,
456 self.storage,
457 );
458 }
459 error
460 })
461 } else {
462 panic!("tried to save unloaded {}", self.name);
463 }
464 }
465}
466
467impl<R: Resource + Serialize + DeserializeOwned> Deref for Persistent<R> {
468 type Target = R;
469
470 fn deref(&self) -> &R {
471 self.get()
472 }
473}
474
475impl<R: Resource + Serialize + DeserializeOwned> DerefMut for Persistent<R> {
476 fn deref_mut(&mut self) -> &mut R {
477 self.get_mut()
478 }
479}