1use std::ops::Deref;
2
3use config::{Config, ConfigError, Environment, FileFormat, Format, Source};
4use serde::de::DeserializeOwned;
5use serde_json::Value;
6
7use crate::{FromMiwaContext, MiwaResult};
8
9use super::MiwaId;
10
11#[derive(Debug, Clone)]
12pub struct MiwaConfig {
13 cfg: Config,
14}
15
16impl MiwaConfig {
17 pub fn default_cfg() -> MiwaResult<Self> {
18 let prefix = "MIWA".to_string();
19 Ok(MiwaConfig {
20 cfg: Config::builder()
21 .add_source(Environment::with_prefix(&prefix).separator("_"))
22 .build()?,
23 })
24 }
25
26 pub fn with_config(cfg: Config) -> MiwaResult<Self> {
27 Ok(MiwaConfig { cfg })
28 }
29
30 pub fn get<T: DeserializeOwned>(&self, key: &str) -> MiwaResult<T> {
31 self.cfg.get(key).map(Ok)?
32 }
33}
34
35pub struct ExtensionConfig<T>(pub T);
36
37impl<T> Deref for ExtensionConfig<T> {
38 type Target = T;
39
40 fn deref(&self) -> &Self::Target {
41 &self.0
42 }
43}
44
45pub trait Configurable {
46 fn prefix() -> &'static str;
47}
48
49impl<'a, T: Configurable + DeserializeOwned> FromMiwaContext<'a> for ExtensionConfig<T> {
50 fn from_context(context: &'a crate::MiwaContext) -> crate::MiwaResult<Self> {
51 let cfg = context.config().get::<T>(T::prefix())?;
52 Ok(ExtensionConfig(cfg))
53 }
54}
55
56impl<T: 'static> MiwaId for ExtensionConfig<T> {
57 fn component_id() -> std::any::TypeId {
58 std::any::TypeId::of::<ExtensionConfig<T>>()
59 }
60}
61
62#[derive(Debug, Clone)]
63pub struct JsonSource(pub Value);
64
65impl Source for JsonSource {
66 fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
67 Box::new((*self).clone())
68 }
69
70 fn collect(&self) -> Result<config::Map<String, config::Value>, ConfigError> {
71 let json_str = serde_json::to_string(&self.0).unwrap();
72
73 FileFormat::Json
74 .parse(None, &json_str)
75 .map_err(ConfigError::Foreign)
76 }
77}