Expand description
§filecaster-derive
filecaster-derive is the procedural macro crate for filecaster. It provides the
#[derive(FromFile)] macro, which automates the process of loading partial
configurations from files, merging them with default values, and constructing
fully-populated Rust structs.
This crate significantly simplifies configuration management by generating
the necessary boilerplate code for the FromFile trait (defined in the
filecaster crate).
§What it does
For any struct with named fields, #[derive(FromFile)] generates:
- A companion “shadow” struct (e.g.,
YourStructFileforYourStruct) where each field is wrapped inOption<T>. This shadow struct is designed for deserialization from configuration files (e.g., JSON, TOML, YAML). - An implementation of the
FromFiletrait for your original struct. This includes thefrom_filemethod, which takes anOption<YourStructFile>and constructs your finalYourStruct. It intelligently fills inNonefields with either:- An expression you supply via
#[from_file(default = ...)]. Default::default()(if nodefaultattribute is provided, requiringT: Default).
- An expression you supply via
§Optional per-field defaults
Use a #[from_file(default = <expr>)] attribute on any field to override
the fallback value. You may supply any expression valid in that struct’s
context. If you omit it, the macro will require the field’s type to implement
Default and will call Default::default().
§Example
use filecaster::FromFile;
#[derive(Debug, Clone, PartialEq, FromFile)]
struct AppConfig {
/// If the user does not specify a host, use `"127.0.0.1"`.
#[from_file(default = "127.0.0.1")]
host: String,
/// Port number; defaults to `8080`.
#[from_file(default = 8080)]
port: u16,
/// If not set, use `false`. Requires `bool: Default`.
auto_reload: bool,
}
fn example() {
// Simulate file content (e.g., from a JSON file)
let file_content = r#"{ "host": "localhost", "port": 3000 }"#;
// The `AppConfigFile` struct is automatically generated by `#[derive(FromFile)]`.
// It has all fields as `Option<T>`.
let partial_config: AppConfigFile = serde_json::from_str(file_content).unwrap();
let partial_config2 = partial_config.clone();
// Use the generated `from_file` method to get the final config.
// Default values are applied for missing fields.
let config = AppConfig::from_file(Some(partial_config));
// or
let config: AppConfig = partial_config2.into();
assert_eq!(config.host, "localhost");
assert_eq!(config.port, 3000);
assert_eq!(config.auto_reload, false); // `Default::default()` for bool is `false`
println!("Final Config: {:#?}", config);
// Example with no file content (all defaults)
let default_config = AppConfig::from_file(None);
assert_eq!(default_config.host, "127.0.0.1");
assert_eq!(default_config.port, 8080);
assert_eq!(default_config.auto_reload, false);
}§Feature flags
serde: Enablesserdeserialization/deserialization support for the generated shadow structs. This is typically required to deserialize your configuration from file formats like JSON, TOML, or YAML.merge: If enabled, the generated shadow struct will also derivemerge::Merge. This allows you to layer multiple partial configuration files together before calling.from_file(...). Any field-level#[merge(...)]attributes will be respected.
§Limitations
- Only works on structs with named fields (no tuple structs or enums).
- All fields without a
#[from_file(default = ...)]attribute must implement theDefaulttrait.