shared/extensions/
settings.rs

1use std::{collections::HashMap, sync::Arc};
2
3pub struct SettingsSerializer {
4    pub database: Arc<crate::database::Database>,
5
6    prefix: compact_str::CompactString,
7    keys: Vec<compact_str::CompactString>,
8    values: Vec<compact_str::CompactString>,
9}
10
11impl SettingsSerializer {
12    pub(crate) fn new(
13        database: Arc<crate::database::Database>,
14        prefix: impl Into<compact_str::CompactString>,
15    ) -> Self {
16        Self {
17            database,
18            prefix: prefix.into(),
19            keys: Vec::new(),
20            values: Vec::new(),
21        }
22    }
23
24    pub(crate) fn key_prefix(&self, key: impl AsRef<str>) -> compact_str::CompactString {
25        compact_str::format_compact!("{}::{}", self.prefix, key.as_ref())
26    }
27
28    pub(crate) fn nest_prefix(&self, nested_prefix: &str) -> compact_str::CompactString {
29        compact_str::format_compact!(
30            "{}{}{}",
31            self.prefix,
32            if self.prefix.is_empty() { "" } else { "::" },
33            nested_prefix
34        )
35    }
36
37    pub fn write_raw_setting(
38        mut self,
39        key: impl AsRef<str>,
40        value: impl Into<compact_str::CompactString>,
41    ) -> Self {
42        self.keys.push(self.key_prefix(key));
43        self.values.push(value.into());
44
45        self
46    }
47
48    pub fn write_serde_setting(
49        mut self,
50        key: impl AsRef<str>,
51        value: &impl serde::Serialize,
52    ) -> Result<Self, serde_json::Error> {
53        let serialized = serde_json::to_string(value)?;
54        self.keys.push(self.key_prefix(key));
55        self.values
56            .push(compact_str::CompactString::from(serialized));
57
58        Ok(self)
59    }
60
61    pub async fn nest(
62        mut self,
63        nested_prefix: &str,
64        settings: &impl SettingsSerializeExt,
65    ) -> Result<Self, anyhow::Error> {
66        let serializer = Self::new(self.database.clone(), self.nest_prefix(nested_prefix));
67
68        let nested_serializer = settings.serialize(serializer).await?;
69
70        self.keys.extend(nested_serializer.keys);
71        self.values.extend(nested_serializer.values);
72
73        Ok(self)
74    }
75
76    pub fn merge(mut self, other: SettingsSerializer) -> Self {
77        self.keys.extend(other.keys);
78        self.values.extend(other.values);
79
80        self
81    }
82
83    pub(crate) fn into_parts(
84        self,
85    ) -> (
86        Vec<compact_str::CompactString>,
87        Vec<compact_str::CompactString>,
88    ) {
89        (self.keys, self.values)
90    }
91}
92
93pub struct SettingsDeserializer<'a> {
94    pub database: Arc<crate::database::Database>,
95
96    pub(crate) prefix: compact_str::CompactString,
97    pub(crate) settings: &'a mut HashMap<compact_str::CompactString, compact_str::CompactString>,
98}
99
100impl<'a> SettingsDeserializer<'a> {
101    pub(crate) fn new(
102        database: Arc<crate::database::Database>,
103        prefix: impl Into<compact_str::CompactString>,
104        settings: &'a mut HashMap<compact_str::CompactString, compact_str::CompactString>,
105    ) -> Self {
106        Self {
107            database,
108            prefix: prefix.into(),
109            settings,
110        }
111    }
112
113    pub(crate) fn key_prefix(&self, key: impl AsRef<str>) -> compact_str::CompactString {
114        compact_str::format_compact!("{}::{}", self.prefix, key.as_ref())
115    }
116
117    pub(crate) fn nest_prefix(&self, nested_prefix: &str) -> compact_str::CompactString {
118        compact_str::format_compact!(
119            "{}{}{}",
120            self.prefix,
121            if self.prefix.is_empty() { "" } else { "::" },
122            nested_prefix
123        )
124    }
125
126    pub fn read_raw_setting(&self, key: impl AsRef<str>) -> Option<&compact_str::CompactString> {
127        self.settings.get(&self.key_prefix(key))
128    }
129
130    pub fn take_raw_setting(&mut self, key: impl AsRef<str>) -> Option<compact_str::CompactString> {
131        self.settings.remove(&self.key_prefix(key))
132    }
133
134    pub fn read_serde_setting<T: serde::de::DeserializeOwned>(
135        &self,
136        key: impl AsRef<str>,
137    ) -> Result<T, serde_json::Error> {
138        let value = match self.settings.get(&self.key_prefix(key)) {
139            Some(v) => v,
140            None => return serde_json::from_value(serde_json::Value::Null),
141        };
142
143        serde_json::from_str(value)
144    }
145
146    pub async fn nest<T: 'static>(
147        &mut self,
148        nested_prefix: &str,
149        deserializer: &(dyn SettingsDeserializeExt + Send + Sync),
150    ) -> Result<T, anyhow::Error> {
151        let settings_deserializer = SettingsDeserializer::new(
152            self.database.clone(),
153            self.nest_prefix(nested_prefix),
154            self.settings,
155        );
156
157        let boxed = deserializer
158            .deserialize_boxed(settings_deserializer)
159            .await?;
160
161        match (boxed as Box<dyn std::any::Any + Send + Sync>).downcast::<T>() {
162            Ok(concrete_box) => Ok(*concrete_box),
163            Err(_) => Err(anyhow::anyhow!(
164                "Type mismatch: expected {}, but nested prefix {} returned a different type",
165                std::any::type_name::<T>(),
166                nested_prefix
167            )),
168        }
169    }
170}
171
172pub type ExtensionSettings = Box<dyn SettingsSerializeExt + Send + Sync + 'static>;
173pub type ExtensionSettingsDeserializer = Arc<dyn SettingsDeserializeExt + Send + Sync + 'static>;
174
175#[async_trait::async_trait]
176pub trait SettingsSerializeExt: std::any::Any + Send + Sync {
177    async fn serialize(
178        &self,
179        serializer: SettingsSerializer,
180    ) -> Result<SettingsSerializer, anyhow::Error>;
181}
182
183#[async_trait::async_trait]
184pub trait SettingsDeserializeExt {
185    async fn deserialize_boxed(
186        &self,
187        deserializer: SettingsDeserializer<'_>,
188    ) -> Result<ExtensionSettings, anyhow::Error>;
189}
190
191#[async_trait::async_trait]
192impl<T: SettingsSerializeExt + ?Sized + Send + Sync> SettingsSerializeExt for Box<T> {
193    async fn serialize(
194        &self,
195        serializer: SettingsSerializer,
196    ) -> Result<SettingsSerializer, anyhow::Error> {
197        (**self).serialize(serializer).await
198    }
199}
200
201#[async_trait::async_trait]
202impl<T: SettingsDeserializeExt + ?Sized + Send + Sync> SettingsDeserializeExt for Arc<T> {
203    async fn deserialize_boxed(
204        &self,
205        deserializer: SettingsDeserializer<'_>,
206    ) -> Result<ExtensionSettings, anyhow::Error> {
207        (**self).deserialize_boxed(deserializer).await
208    }
209}
210
211pub struct EmptySettings;
212
213#[async_trait::async_trait]
214impl SettingsSerializeExt for EmptySettings {
215    async fn serialize(
216        &self,
217        serializer: SettingsSerializer,
218    ) -> Result<SettingsSerializer, anyhow::Error> {
219        Ok(serializer)
220    }
221}
222
223#[async_trait::async_trait]
224impl SettingsDeserializeExt for EmptySettings {
225    async fn deserialize_boxed(
226        &self,
227        _deserializer: SettingsDeserializer<'_>,
228    ) -> Result<ExtensionSettings, anyhow::Error> {
229        Ok(Box::new(EmptySettings))
230    }
231}