use std::time::Duration;
use confique::Config;
#[derive(Debug, Config)]
#[allow(dead_code)]
struct Conf {
#[config(validate = validate_name)]
name: String,
#[config(env = "PORT", validate(*port >= 1024, "port must not require super-user"))]
port: Option<u16>,
#[config(nested)]
watch: WatchConfig,
}
#[derive(Debug, Config)]
#[config(validate = Self::validate)]
struct WatchConfig {
#[config(default = false)]
busy_poll: bool,
#[config(
deserialize_with = deserialize_duration_ms,
validate(*poll_period > Duration::from_millis(10), "cannot poll faster than 10ms"),
)]
poll_period: Option<Duration>,
}
fn validate_name(name: &String) -> Result<(), &'static str> {
if name.is_empty() {
return Err("name must be non-empty");
}
if !name.is_ascii() {
return Err("name must be ASCII");
}
Ok(())
}
impl WatchConfig {
fn validate(&self) -> Result<(), &'static str> {
if !self.busy_poll && self.poll_period.is_some() {
return Err("'poll_period' set, but busy polling is not enabled");
}
Ok(())
}
}
pub(crate) fn deserialize_duration_ms<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where
D: serde::Deserializer<'de>,
{
let ms = <u64 as serde::Deserialize>::deserialize(deserializer)?;
Ok(Duration::from_millis(ms))
}
fn main() {
let r = Conf::builder()
.env()
.file("examples/files/validate.toml")
.load();
match r {
Ok(conf) => println!("{:#?}", conf),
Err(e) => println!("{e:#}"),
}
}