rust_config_tree/config.rs
1//! High-level `confique` integration and config-template rendering.
2//!
3//! This module loads `.env` values, builds a Figment runtime source graph,
4//! extracts it into a `confique` schema for defaults and validation, renders
5//! example templates that mirror the same include tree, and writes JSON Schema
6//! files that editors can use for completion and validation. YAML templates can
7//! also be split across nested schema sections.
8
9use std::path::PathBuf;
10
11use confique::Config;
12
13pub use crate::config_env::ConfiqueEnvProvider;
14pub use crate::config_format::ConfigFormat;
15pub use crate::config_load::{
16 build_config_figment, load_config, load_config_from_figment, load_config_with_figment,
17};
18pub(crate) use crate::config_output::{
19 default_config_schema_output, resolve_config_template_output,
20};
21pub use crate::config_schema::{
22 ConfigSchemaTarget, config_schema_targets_for_path, write_config_schema, write_config_schemas,
23};
24pub use crate::config_templates::{
25 ConfigTemplateTarget, template_for_path, template_targets_for_paths,
26 template_targets_for_paths_with_schema, write_config_templates,
27 write_config_templates_with_schema,
28};
29pub use crate::config_trace::trace_config_sources;
30
31/// Result type used by the high-level configuration API.
32///
33/// The error type is [`ConfigError`](crate::ConfigError).
34pub type ConfigResult<T> = std::result::Result<T, crate::ConfigError>;
35
36/// A `confique` schema that can expose recursive include paths and template
37/// section layout.
38///
39/// Implement this trait for the same type that derives `confique::Config`.
40/// `include_paths` receives a partially loaded layer so the crate can discover
41/// child config files before the final schema is merged.
42pub trait ConfigSchema: Config + Sized {
43 /// Returns include paths declared by a loaded config layer.
44 ///
45 /// Relative paths are resolved from the file that declared them. Empty paths
46 /// are rejected before traversal continues.
47 ///
48 /// # Arguments
49 ///
50 /// - `layer`: Partially loaded `confique` layer for one config file.
51 ///
52 /// # Returns
53 ///
54 /// Returns include paths declared by `layer`.
55 ///
56 /// # Examples
57 ///
58 /// ```
59 /// use confique::Config;
60 /// use rust_config_tree::ConfigSchema;
61 ///
62 /// #[derive(Config)]
63 /// struct AppConfig {
64 /// #[config(default = [])]
65 /// include: Vec<std::path::PathBuf>,
66 /// }
67 ///
68 /// impl ConfigSchema for AppConfig {
69 /// fn include_paths(layer: &<Self as Config>::Layer) -> Vec<std::path::PathBuf> {
70 /// layer.include.clone().unwrap_or_default()
71 /// }
72 /// }
73 /// ```
74 fn include_paths(layer: &<Self as Config>::Layer) -> Vec<PathBuf>;
75
76 /// Overrides the generated template file path for a split nested section.
77 ///
78 /// A nested section is split only when its field schema has
79 /// `x-tree-split = true`, for example
80 /// `#[schemars(extend("x-tree-split" = true))]`. By default, top-level
81 /// split sections are generated as `<field>.yaml` relative to the root
82 /// template directory and nested split sections as children of their
83 /// parent section file stem, e.g. `trading/risk.yaml`.
84 ///
85 /// # Arguments
86 ///
87 /// - `section_path`: Path of nested schema field names from the root schema
88 /// to the section being rendered.
89 ///
90 /// # Returns
91 ///
92 /// Returns `Some(path)` to override the generated file path, or `None` to
93 /// use the default section path.
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// use confique::Config;
99 /// use rust_config_tree::ConfigSchema;
100 ///
101 /// #[derive(Config)]
102 /// struct AppConfig {
103 /// #[config(default = [])]
104 /// include: Vec<std::path::PathBuf>,
105 /// }
106 ///
107 /// impl ConfigSchema for AppConfig {
108 /// fn include_paths(layer: &<Self as Config>::Layer) -> Vec<std::path::PathBuf> {
109 /// layer.include.clone().unwrap_or_default()
110 /// }
111 ///
112 /// fn template_path_for_section(section_path: &[&str]) -> Option<std::path::PathBuf> {
113 /// match section_path {
114 /// ["server"] => Some(std::path::PathBuf::from("config/server.yaml")),
115 /// _ => None,
116 /// }
117 /// }
118 /// }
119 /// ```
120 fn template_path_for_section(section_path: &[&str]) -> Option<PathBuf> {
121 let _ = section_path;
122 None
123 }
124}
125
126#[cfg(test)]
127#[path = "unit_tests/config.rs"]
128mod unit_tests;