1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use crate::storage::{Storage, StoreError, StoreHandle, Storing};

/// Used to manage store handles
///
/// # Example
///
///```
/// use serde::{Deserialize, Serialize};
/// use storage::{manager::StorageManager, Storage, StoreHandle, Storing, StoringType};
///
/// #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
/// pub struct MyStore {
///    pub count: u32,
/// }
///
/// impl Storing for MyStore {
///     fn store_type() -> StoringType {
///            StoringType::Data
///      }
/// }
///
/// // Initialize the Storage with the defaults
/// let storage = Storage::new("com.github.mazynoah.storage".to_owned());
///
/// // Create a handle for managing the store data.
/// let handle = StoreHandle::<MyStore>::new("manager");
///
/// // Use `StorageManager` to manage the handle's change.
/// let mut manager =
///    StorageManager::new(&storage, handle).expect("Failed to create StorageManager");
///
/// // Get a mutable reference to the store
/// let counter = manager.get_store_mut();
///
/// counter.count = 75;
///
/// // Save the data to the storage
/// manager.save().expect("Failed to save count to storage");
///
/// let counter = manager.get_store();
///
/// println!("Count: {}", counter.count);
///
///```
#[derive(Debug, Clone)]
pub struct StorageManager<T: Storing> {
    store: Storage,
    handle: StoreHandle<T>,
}

impl<T: Storing> StorageManager<T> {
    /// Creates a new `StorageManager` by reading the store data from the provided `Storage` into the `StoreHandle`.
    ///
    /// This function attempts to read the store data from the storage.
    ///
    ///
    /// # Example
    ///
    /// ```
    /// let storage = Storage::new(&app);
    /// let handle = StoreHandle::<MyStore>::new("my_store_id");
    /// let manager = StorageManager::new(&storage, handle).expect("Failed to create StorageManager");
    /// ```
    pub fn new(storage: &Storage, mut handle: StoreHandle<T>) -> Result<Self, StoreError> {
        storage.read(&mut handle)?;

        Ok(Self {
            store: storage.clone(),
            handle,
        })
    }

    /// Returns a reference to the stored data.
    pub fn get_store(&self) -> &T {
        self.handle.get_store()
    }

    /// Returns a reference to the stored data.
    pub fn get_store_mut(&mut self) -> &mut T {
        self.handle.get_store_mut()
    }

    /// Reads the stored data from the storage.
    /// This allows to get changes external to the application
    pub fn get_store_alive(&mut self) -> Result<&T, StoreError> {
        self.store.read(&mut self.handle)?;
        Ok(self.handle.get_store())
    }

    /// This method is used to modify the store.
    ///
    /// # Example
    ///
    /// ```
    /// let storage = Storage::new(&app);
    /// let handle = StoreHandle::<MyStore>::new("my_store_id");
    /// let manager = StorageManager::new(&storage, handle).expect("Failed to create StorageManager");
    ///
    /// manager.modify_store(|store| store.some_field = 25).expect("Failed to write store modifications");
    /// ```
    pub fn modify_store<F>(&mut self, mut change: F) -> Result<(), StoreError>
    where
        F: FnMut(&mut T),
    {
        let store = self.handle.get_store_mut();
        change(store);
        self.save()
    }

    /// This method is used to modify the store without committing changes to disk.
    ///
    /// # Example
    ///
    /// ```
    /// let storage = Storage::new(&app);
    /// let handle = StoreHandle::<MyStore>::new("my_store_id");
    /// let manager = StorageManager::new(&storage, handle).expect("Failed to create StorageManager");
    ///
    /// manager.modify_store_uncommitted(|store| store.some_field = 25);
    ///
    /// manager.save().expect("Failed to save modifications");
    /// ```
    pub fn modify_store_uncommitted<F>(&mut self, mut change: F)
    where
        F: FnMut(&mut T),
    {
        let store = self.handle.get_store_mut();
        change(store);
    }

    /// This method writes the current state of the store to the storage.
    pub fn save(&mut self) -> Result<(), StoreError> {
        self.store.write(&mut self.handle)
    }
}