1#![doc = include_str!("../../Config.md")]
4pub mod env;
6pub mod toml;
8
9pub use inventory::submit;
10pub use schemars::schema_for;
11pub use schemars::Schema;
12pub use spring_macros::Configurable;
13
14use crate::error::Result;
15use serde_json::json;
16use std::{ops::Deref, sync::Arc};
17
18pub trait Configurable {
20 fn config_prefix() -> &'static str;
23}
24
25pub trait ConfigRegistry {
27 fn get_config<T>(&self) -> Result<T>
29 where
30 T: serde::de::DeserializeOwned + Configurable;
31}
32
33#[derive(Debug, Clone)]
35pub struct ConfigRef<T: Configurable>(Arc<T>);
36
37impl<T: Configurable> ConfigRef<T> {
38 pub fn new(config: T) -> Self {
40 Self(Arc::new(config))
41 }
42}
43
44impl<T> Deref for ConfigRef<T>
45where
46 T: Configurable,
47{
48 type Target = T;
49
50 fn deref(&self) -> &Self::Target {
51 &self.0
52 }
53}
54
55pub struct ConfigSchema {
57 pub prefix: &'static str,
59 pub schema: fn() -> Schema,
61}
62
63inventory::collect!(ConfigSchema);
64
65#[macro_export]
67macro_rules! submit_config_schema {
68 ($prefix:expr, $ty:ty) => {
69 ::spring::config::submit! {
70 ::spring::config::ConfigSchema {
71 prefix: $prefix,
72 schema: || ::spring::config::schema_for!($ty),
73 }
74 }
75 };
76}
77
78pub fn auto_config_schemas() -> Vec<(String, Schema)> {
80 inventory::iter::<ConfigSchema>
81 .into_iter()
82 .map(|c| (c.prefix.to_string(), (c.schema)()))
83 .collect()
84}
85
86pub fn merge_all_schemas() -> serde_json::Value {
88 let mut properties = serde_json::Map::new();
89
90 for (prefix, schema) in auto_config_schemas() {
91 properties.insert(prefix, serde_json::to_value(schema).unwrap());
93 }
94
95 json!({
96 "type": "object",
97 "properties": properties
98 })
99}
100
101pub fn write_merged_schema_to_file(path: &str) -> std::io::Result<()> {
103 let merged = merge_all_schemas();
104 std::fs::write(path, serde_json::to_string_pretty(&merged).unwrap())
105}