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}