Skip to main content

rtb_config/
lib.rs

1//! Typed, layered configuration backed by [`figment`].
2//!
3//! # Design
4//!
5//! The Go Tool Base config system exposes a dynamic `Containable`
6//! interface with `GetString("foo.bar")` accessors. We deliberately do
7//! not mimic that. Rust's strength is in compile-time types, so
8//! [`Config`] is a generic container over *your* `serde::Deserialize`
9//! struct:
10//!
11//! ```
12//! use rtb_config::Config;
13//! use serde::Deserialize;
14//!
15//! #[derive(Deserialize, Default)]
16//! struct MyConfig { host: String, port: u16 }
17//!
18//! let cfg = Config::<MyConfig>::builder()
19//!     .embedded_default(concat!(
20//!         "host: localhost\n",
21//!         "port: 8080\n",
22//!     ))
23//!     .env_prefixed("MYTOOL_")
24//!     .build()
25//!     .expect("config layers are consistent");
26//!
27//! let current = cfg.get();
28//! assert_eq!(current.host, "localhost");
29//! ```
30//!
31//! # What ships
32//!
33//! * Typed [`Config<C>`] with `C` defaulting to `()` so rtb-app's
34//!   `Arc<Config>` field keeps working without a type parameter.
35//! * [`ConfigBuilder`] layering (embedded default → user file → env).
36//! * Explicit [`Config::reload`] re-reading every source and atomically
37//!   swapping the stored value via `arc_swap::ArcSwap`.
38//! * [`Config::subscribe`] returning a `tokio::sync::watch::Receiver`
39//!   that wakes every time a reload succeeds (v0.2).
40//! * `Config::watch_files` behind the `hot-reload` feature: a
41//!   debounced background watcher that calls `reload` on change and
42//!   hands back a `WatchHandle` to stop it (v0.2).
43//!
44//! See `docs/development/specs/2026-04-22-rtb-config-v0.1.md` and
45//! `docs/development/specs/2026-04-24-rtb-config-hot-reload.md` for
46//! the authoritative contracts.
47
48#![forbid(unsafe_code)]
49
50pub mod config;
51pub mod error;
52#[cfg(feature = "mutable")]
53mod mutable;
54#[cfg(feature = "hot-reload")]
55pub mod watch;
56
57pub use config::{Config, ConfigBuilder};
58pub use error::ConfigError;
59#[cfg(feature = "hot-reload")]
60pub use watch::WatchHandle;