use premortem::prelude::*;
use serde::Deserialize;
#[derive(Debug, Deserialize, DeriveValidate)]
struct DatabaseConfig {
#[validate(non_empty)]
host: String,
#[validate(range(1..=65535))]
port: u16,
#[validate(range(1..=100))]
pool_size: i32,
}
#[derive(Debug, Deserialize, DeriveValidate)]
struct ServerConfig {
#[validate(non_empty)]
host: String,
#[validate(range(1..=65535))]
port: u16,
}
#[derive(Debug, Deserialize, DeriveValidate)]
struct AppConfig {
#[validate(nested)]
server: ServerConfig,
#[validate(nested)]
database: DatabaseConfig,
}
fn main() {
println!("=== Error Output Demo ===\n");
println!("--- Valid Configuration ---\n");
demo_valid_config();
println!("\n--- Invalid Configuration (Accumulated Errors) ---\n");
demo_invalid_config();
println!("\n--- Error Output (README Format) ---\n");
demo_readme_errors();
println!("\n--- Pretty-Printed Errors (Grouped by Source) ---");
demo_pretty_errors();
}
fn demo_valid_config() {
let config_toml = r#"
[server]
host = "localhost"
port = 8080
[database]
host = "db.example.com"
port = 5432
pool_size = 10
"#;
let result = Config::<AppConfig>::builder()
.source(Toml::string(config_toml).named("config.toml"))
.build();
match result {
Ok(config) => {
println!("Configuration loaded successfully!");
println!(" Server: {}:{}", config.server.host, config.server.port);
println!(
" Database: {}:{} (pool: {})",
config.database.host, config.database.port, config.database.pool_size
);
}
Err(errors) => {
eprintln!("Unexpected errors: {}", errors);
}
}
}
fn demo_invalid_config() {
let config_toml = r#"[server]
host = ""
port = 8080
[database]
host = "db.example.com"
port = 5432
pool_size = -5"#;
let env = MockEnv::new()
.with_file("config.toml", config_toml)
.with_env("APP_SERVER_PORT", "0");
let result = Config::<AppConfig>::builder()
.source(Toml::file("config.toml"))
.source(Env::prefix("APP").separator("_"))
.build_with_env(&env);
match result {
Ok(_) => println!("Unexpected success"),
Err(errors) => {
print!("{}", errors);
}
}
}
fn demo_readme_errors() {
let config_toml = r#"[server]
host = "localhost"
port = 8080
[database]
port = 5432
pool_size = 10"#;
let env = MockEnv::new().with_file("config.toml", config_toml);
let result = Config::<AppConfig>::builder()
.source(Toml::file("config.toml"))
.build_with_env(&env);
match result {
Ok(_) => println!("Unexpected success"),
Err(errors) => {
print!("{}", errors);
}
}
}
fn demo_pretty_errors() {
let config_toml = r#"[server]
host = ""
port = 8080
[database]
host = "db.example.com"
port = 5432
pool_size = -5"#;
let env = MockEnv::new()
.with_file("config.toml", config_toml)
.with_env("APP_SERVER_PORT", "0");
let result = Config::<AppConfig>::builder()
.source(Toml::file("config.toml"))
.source(Env::prefix("APP").separator("_"))
.build_with_env(&env);
match result {
Ok(_) => println!("Unexpected success"),
Err(errors) => {
errors.pretty_print(&PrettyPrintOptions::default());
}
}
}