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);