reloadable_state/
lib.rs

1//! A abstract reloadable state.
2
3use std::sync::Arc;
4
5use arc_swap::ArcSwap;
6use tokio::sync::Mutex;
7
8pub use reloadable_core as core;
9
10/// A generic reloadable shared state.
11pub struct Reloadable<T, R> {
12    /// The value.
13    value: ArcSwap<T>,
14    /// The reloader.
15    loader: Mutex<R>,
16}
17
18impl<T, L> Reloadable<T, L> {
19    /// Create a new [`Reloadable`] with a specified initial value.
20    pub fn new(loader: L, initial_value: Arc<T>) -> Self {
21        let loader = Mutex::new(loader);
22        let value = ArcSwap::new(initial_value);
23        Self { loader, value }
24    }
25
26    /// Get the currently loaded value.
27    pub fn get(&self) -> Arc<T> {
28        self.value.load_full()
29    }
30
31    /// Store new value and return the old one.
32    pub fn set(&self, value: Arc<T>) -> Arc<T> {
33        self.value.swap(value)
34    }
35}
36
37impl<T, L> Reloadable<T, L>
38where
39    L: reloadable_core::Loader<Value = T>,
40{
41    /// Load the initial value and create a new [`Reloadable`].
42    pub async fn init_load(mut loader: L) -> Result<(Self, Arc<T>), L::Error> {
43        let loaded = loader.load().await?;
44        let loaded = Arc::new(loaded);
45        let reloadable = Self::new(loader, Arc::clone(&loaded));
46        Ok((reloadable, loaded))
47    }
48
49    /// Reload the value, store it and return the newly loaded value.
50    ///
51    /// If loader fails with an error, the stored value doesn't change.
52    pub async fn reload(&self) -> Result<Arc<T>, L::Error> {
53        let mut loader = self.loader.lock().await;
54        let reloaded = loader.load().await?;
55        let reloaded = Arc::new(reloaded);
56        drop(self.set(Arc::clone(&reloaded)));
57        Ok(reloaded)
58    }
59}
60
61impl<T, R> std::fmt::Debug for Reloadable<T, R> {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        f.debug_struct("Reloadable").finish_non_exhaustive()
64    }
65}