spring/config/
mod.rs

1//! This module implements configuration loading.
2//!
3#![doc = include_str!("../../Config.md")]
4/// Environment Configuration
5pub mod env;
6/// Implement reading toml configuration
7pub 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
18/// The Configurable trait marks whether the struct can read configuration from the [ConfigRegistry]
19pub trait Configurable {
20    /// Prefix used to read toml configuration.
21    /// If you need to load external configuration, you need to rewrite this method
22    fn config_prefix() -> &'static str;
23}
24
25/// ConfigRegistry is the core trait of configuration management
26pub trait ConfigRegistry {
27    /// Get the configuration items according to the Configurable's `config_prefix`
28    fn get_config<T>(&self) -> Result<T>
29    where
30        T: serde::de::DeserializeOwned + Configurable;
31}
32
33/// ConfigRef avoids cloning of big struct through Arc
34#[derive(Debug, Clone)]
35pub struct ConfigRef<T: Configurable>(Arc<T>);
36
37impl<T: Configurable> ConfigRef<T> {
38    /// constructor
39    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
55/// Collects all configured schema generation information
56pub struct ConfigSchema {
57    /// [`Configurable::config_prefix`]
58    pub prefix: &'static str,
59    /// Generate the [`Schema`] for this configuration
60    pub schema: fn() -> Schema,
61}
62
63inventory::collect!(ConfigSchema);
64
65/// register config schema
66#[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
78/// Get all registered schemas
79pub 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
86/// Merge all config schemas into one json schema
87pub 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        // Put each schema under the corresponding prefix
92        properties.insert(prefix, serde_json::to_value(schema).unwrap());
93    }
94
95    json!({
96        "type": "object",
97        "properties": properties
98    })
99}
100
101/// write merged json schema to file
102pub 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}