rustls_cert_reloadable/
lib.rs

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