encrypt_config/
config.rs

1//! # Config
2//! This module provides a [`Config`] struct that can be used to cache configuration values.
3
4use rom_cache::cache::{CacheMut, CacheRef};
5use std::any::Any;
6
7/// A struct that can be used to **cache** configuration values.
8/// This behaves like a native cache in CPU:
9///
10/// `get`:
11/// 1. If cache hit, returns the cached value's ref.
12/// 2. If cache miss, loads the value from the source to cache (default as fallback), then returns the ref.
13///
14/// `get_mut`
15/// 1. If cache hit, returns the cached value's mut ref, dereferencing it will mark the value as dirty.
16/// 2. If cache miss, loads the value from the source to cache (default as fallback), then returns the mut ref.
17/// 3. All cached values marked dirty will be written back when Config dropped or cache line evicted.
18///
19/// **At most N** different config types are safe to be managed at the same time due to the cache capacity.
20/// And each type can be ref **up to (usize::MAX >> 2)** times or mut ref **up to 1** time at the same time.
21/// Or invalid borrow may happen (since the counter wraps around on overflow).
22#[cfg_attr(
23    feature = "secret",
24    doc = "To avoid entering the password during testing, you can enable `mock` feature. This can always return the **same** Encrypter during **each** test."
25)]
26pub struct Config<const N: usize> {
27    cache: rom_cache::Cache<1, N>,
28}
29
30impl<const N: usize> Default for Config<N> {
31    /// Create an empty [`Config`] cache.
32    fn default() -> Self {
33        Self {
34            cache: rom_cache::Cache::<1, N>::default(),
35        }
36    }
37}
38
39impl<const N: usize> Config<N> {
40    /// Create a new [`Config`] cache.
41    pub fn new() -> Self {
42        Self::default()
43    }
44
45    /// Get an immutable ref ([`CfgRef`]) from the config.
46    /// If the value was not valid, it would try loading from source, and fell back to the default value.
47    ///
48    /// Caution: You can only get up to (usize::MAX >> 2) immutable refs ([`CfgRef`]) of each type at the same time.
49    ///
50    /// If the value was marked as writing, it would panic like `RefCell`.
51    /// See [`CfgRef`] for more details.
52    pub fn get<T>(&self) -> <T as Cacheable<()>>::Ref<'_>
53    where
54        T: Cacheable<()> + Any + Send + Sync,
55    {
56        T::retrieve(&self.cache)
57    }
58
59    /// Get a mutable ref ([`CfgMut`]) from the config.
60    /// If the value was not valid, it would try loading from source, and fell back to the default value.
61    ///
62    /// Caution: You can only get up to 1 mutable ref ([`CfgMut`]) of each type at the same time.
63    ///
64    /// If the value was marked as reading or writing, it would panic like `RefCell`.
65    /// See [`CfgMut`] for more details.
66    pub fn get_mut<T>(&self) -> <T as Cacheable<()>>::Mut<'_>
67    where
68        T: Cacheable<()> + Any + Send + Sync,
69    {
70        T::retrieve_mut(&self.cache)
71    }
72
73    /// Get many immutable refs from the config.
74    ///
75    /// T: (T1, T2, T3,)
76    ///
77    /// If the value was not valid, it would try loading from source, and fell back to the default value.
78    /// See [`CfgRef`] for more details.
79    pub fn get_many<T>(&self) -> <T as Cacheable<((),)>>::Ref<'_>
80    where
81        T: Cacheable<((),)> + Any + Send + Sync,
82    {
83        T::retrieve(&self.cache)
84    }
85
86    /// Get many mutable refs from the config.
87    ///
88    /// T: (T1, T2, T3,)
89    ///
90    /// If the value was not valid, it would try loading from source, and fell back to the default value.
91    /// See [`CfgMut`] for more details.
92    pub fn get_mut_many<T>(&self) -> <T as Cacheable<((),)>>::Mut<'_>
93    where
94        T: Cacheable<((),)> + Any + Send + Sync,
95    {
96        T::retrieve_mut(&self.cache)
97    }
98}
99
100/// # Panic
101/// - If you already held a [`CfgMut`], [`Config::get()`] will panic.
102pub type CfgRef<'a, T> = CacheRef<'a, T>;
103
104/// # Panic
105/// - If you already held a [`CfgRef`] or [`CfgMut`], [`Config::get_mut()`] will panic.
106pub type CfgMut<'a, T> = CacheMut<'a, T>;
107
108/// This trait is used to retrieve the config value from the cache.
109#[allow(private_bounds, private_interfaces)]
110pub trait Cacheable<T> {
111    /// Immutable reference retrieved from the cache.
112    type Ref<'a>;
113    /// Mutable reference retrieved from the cache.
114    type Mut<'a>;
115    /// Retrieve the immutable ref from the cache.
116    fn retrieve<const N: usize>(cache: &rom_cache::Cache<1, N>) -> Self::Ref<'_>;
117    /// Retrieve the mutable ref from the cache.
118    fn retrieve_mut<const N: usize>(cache: &rom_cache::Cache<1, N>) -> Self::Mut<'_>;
119}
120
121#[allow(private_bounds, private_interfaces)]
122impl<T> Cacheable<()> for T
123where
124    T: rom_cache::Cacheable + Default,
125{
126    type Ref<'a> = CfgRef<'a, T>;
127    type Mut<'a> = CfgMut<'a, T>;
128
129    fn retrieve<const N: usize>(cache: &rom_cache::Cache<1, N>) -> Self::Ref<'_> {
130        cache.get::<T>().unwrap()
131    }
132
133    fn retrieve_mut<const N: usize>(cache: &rom_cache::Cache<1, N>) -> Self::Mut<'_> {
134        cache.get_mut::<T>().unwrap()
135    }
136}
137
138macro_rules! impl_cacheable {
139    ($($t: ident),+$(,)?) => {
140        #[allow(private_bounds, private_interfaces)]
141        impl<$($t),+> Cacheable<((),)> for ($($t),+,)
142        where
143            $($t: Cacheable<()>,)+
144        {
145            type Ref<'a> = ($(<$t as Cacheable<()>>::Ref<'a>),+,);
146            type Mut<'a> = ($(<$t as Cacheable<()>>::Mut<'a>),+,);
147            fn retrieve<const N: usize>(cache: &rom_cache::Cache<1, N>) -> Self::Ref<'_> {
148                ($(<$t as Cacheable<()>>::retrieve(cache)),+,)
149            }
150
151            fn retrieve_mut<const N: usize>(cache: &rom_cache::Cache<1, N>) -> Self::Mut<'_> {
152                ($(<$t as Cacheable<()>>::retrieve_mut(cache)),+,)
153            }
154        }
155    };
156}
157
158impl_cacheable!(T1);
159impl_cacheable!(T1, T2);
160impl_cacheable!(T1, T2, T3);
161impl_cacheable!(T1, T2, T3, T4);
162impl_cacheable!(T1, T2, T3, T4, T5);
163impl_cacheable!(T1, T2, T3, T4, T5, T6);
164impl_cacheable!(T1, T2, T3, T4, T5, T6, T7);
165impl_cacheable!(T1, T2, T3, T4, T5, T6, T7, T8);