elfo_core/
config.rs

1use std::{
2    any::{Any, TypeId},
3    fmt, mem,
4    ops::Deref,
5    sync::Arc,
6};
7
8use derive_more::From;
9use serde::{de, de::value::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
10use serde_value::{Value, ValueDeserializer};
11
12use crate::local::Local;
13
14pub trait Config: for<'de> Deserialize<'de> + Send + Sync + fmt::Debug + 'static {}
15impl<C> Config for C where C: for<'de> Deserialize<'de> + Send + Sync + fmt::Debug + 'static {}
16
17assert_impl_all!((): Config);
18
19// === AnyConfig ===
20
21#[derive(Clone)]
22pub struct AnyConfig {
23    raw: Arc<Value>,
24    decoded: Option<Local<Decoded>>,
25}
26
27#[derive(Clone)]
28struct Decoded {
29    system: Arc<SystemConfig>,
30    // Actually, we store `Arc<Arc<C>>` here.
31    user: Arc<dyn Any + Send + Sync>,
32}
33
34impl AnyConfig {
35    pub fn new(value: Value) -> Self {
36        Self {
37            raw: Arc::new(value),
38            decoded: None,
39        }
40    }
41
42    pub(crate) fn get_user<C: 'static>(&self) -> &Arc<C> {
43        self.decoded
44            .as_ref()
45            .and_then(|local| local.user.downcast_ref())
46            .expect("must be decoded")
47    }
48
49    pub(crate) fn get_system(&self) -> &Arc<SystemConfig> {
50        &self.decoded.as_ref().expect("must be decoded").system
51    }
52
53    pub(crate) fn decode<C: Config>(&self) -> Result<AnyConfig, String> {
54        let mut raw = (*self.raw).clone();
55
56        let system_decoded = if let Value::Map(map) = &mut raw {
57            if let Some(system_raw) = map.remove(&Value::String("system".into())) {
58                let de = ValueDeserializer::<DeError>::new(system_raw);
59                let config = SystemConfig::deserialize(de).map_err(|err| err.to_string())?;
60                Arc::new(config)
61            } else {
62                Default::default()
63            }
64        } else {
65            Default::default()
66        };
67
68        // Handle the special case of default config.
69        let user_decoded = if TypeId::of::<C>() == TypeId::of::<()>() {
70            Arc::new(Arc::new(())) as Arc<_>
71        } else {
72            let de = ValueDeserializer::<DeError>::new(raw);
73            let config = C::deserialize(de).map_err(|err| err.to_string())?;
74            Arc::new(Arc::new(config)) as Arc<_>
75        };
76
77        Ok(AnyConfig {
78            raw: self.raw.clone(),
79            decoded: Some(Local::from(Decoded {
80                system: system_decoded,
81                user: user_decoded,
82            })),
83        })
84    }
85
86    pub(crate) fn into_value(mut self) -> Value {
87        mem::replace(Arc::make_mut(&mut self.raw), Value::Unit)
88    }
89}
90
91impl Default for AnyConfig {
92    fn default() -> Self {
93        Self::new(Value::Map(Default::default()))
94    }
95}
96
97impl fmt::Debug for AnyConfig {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        // Configs can contain credentials, so we should never print unknown configs.
100        f.write_str("..")
101    }
102}
103
104impl<'de> Deserialize<'de> for AnyConfig {
105    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
106        Value::deserialize(deserializer).map(Self::new)
107    }
108}
109
110impl Serialize for AnyConfig {
111    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
112        self.raw.serialize(serializer)
113    }
114}
115
116impl<'de> Deserializer<'de> for AnyConfig {
117    type Error = serde_value::DeserializerError;
118
119    serde::forward_to_deserialize_any! {
120        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit
121        seq bytes byte_buf map unit_struct
122        tuple_struct struct tuple ignored_any identifier
123    }
124
125    fn deserialize_any<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
126        self.into_value().deserialize_any(visitor)
127    }
128
129    fn deserialize_option<V: de::Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
130        self.into_value().deserialize_option(visitor)
131    }
132
133    fn deserialize_enum<V: de::Visitor<'de>>(
134        self,
135        name: &'static str,
136        variants: &'static [&'static str],
137        visitor: V,
138    ) -> Result<V::Value, Self::Error> {
139        self.into_value().deserialize_enum(name, variants, visitor)
140    }
141
142    fn deserialize_newtype_struct<V: de::Visitor<'de>>(
143        self,
144        name: &'static str,
145        visitor: V,
146    ) -> Result<V::Value, Self::Error> {
147        self.into_value().deserialize_newtype_struct(name, visitor)
148    }
149}
150
151// === SystemConfig ===
152
153#[derive(Default, Deserialize)]
154#[serde(default)]
155pub(crate) struct SystemConfig {
156    pub(crate) logging: crate::logging::LoggingConfig,
157    pub(crate) dumping: crate::dumping::DumpingConfig,
158    pub(crate) telemetry: crate::telemetry::TelemetryConfig,
159}
160
161// === Secret ===
162
163#[derive(Clone, Copy, PartialEq, Eq, Default, From)]
164pub struct Secret<T>(T);
165
166impl<T> Secret<T> {
167    pub fn into_inner(self) -> T {
168        self.0
169    }
170}
171
172impl<T> Deref for Secret<T> {
173    type Target = T;
174
175    #[inline]
176    fn deref(&self) -> &Self::Target {
177        &self.0
178    }
179}
180
181impl<T> fmt::Debug for Secret<T> {
182    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183        write!(f, "<secret>")
184    }
185}
186
187impl<T> fmt::Display for Secret<T> {
188    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189        write!(f, "<secret>")
190    }
191}
192
193impl<'de, T: Deserialize<'de>> Deserialize<'de> for Secret<T> {
194    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
195        T::deserialize(deserializer).map(Self)
196    }
197}
198
199impl<T: Serialize> Serialize for Secret<T> {
200    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
201        // TODO: it should depend on the context (network or dumping).
202        serializer.serialize_str("<secret>")
203    }
204}