tuwunel_core/config/sources.rs
1//! Defines the inputs used to assemble configuration.
2//!
3//! [`Sources`] retains file paths and optional overrides so reloads reproduce
4//! startup inputs. Loading layers extra paths before applying those overrides.
5
6#[cfg(test)]
7mod tests;
8
9use std::path::{Path, PathBuf};
10
11use super::{Config, Figment};
12use crate::{Result, implement};
13
14/// Applies the entry point's own contribution to a freshly loaded
15/// configuration.
16pub type Overrides = dyn Fn(Figment) -> Result<Figment> + Send + Sync;
17
18/// Retains the inputs used to assemble a server configuration.
19///
20/// Reloads reuse these paths and the optional override to reproduce startup
21/// behavior. Environment providers are added by the configuration loader
22/// itself.
23#[derive(Default)]
24pub struct Sources {
25 /// Lists configuration files in merge order.
26 ///
27 /// Later paths overlay values from earlier paths. Reloads begin with this
28 /// same ordered sequence before adding any explicit extra paths.
29 pub paths: Vec<PathBuf>,
30
31 /// Applies an optional transform after the standard providers are merged.
32 ///
33 /// The callback can add synthetic overrides after standard loading. Reloads
34 /// retain it so those values are not silently discarded.
35 pub overrides: Option<Box<Overrides>>,
36}
37
38/// Builds a raw configuration from these sources, with `extra` paths layered
39/// after them.
40#[implement(Sources)]
41pub fn load<'a, I>(&'a self, extra: I) -> Result<Figment>
42where
43 I: Iterator<Item = &'a Path>,
44{
45 let paths = self
46 .paths
47 .iter()
48 .map(PathBuf::as_path)
49 .chain(extra);
50
51 Config::load(paths).and_then(|raw| self.apply(raw))
52}
53
54#[implement(Sources)]
55#[inline]
56pub(crate) fn file_paths(&self) -> impl Iterator<Item = PathBuf> + '_ {
57 Config::file_paths(self.paths.iter().map(PathBuf::as_path))
58}
59
60#[implement(Sources)]
61fn apply(&self, raw: Figment) -> Result<Figment> {
62 match &self.overrides {
63 | None => Ok(raw),
64 | Some(overrides) => overrides(raw),
65 }
66}