Crate filecaster_derive

Crate filecaster_derive 

Source
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:

  1. A companion “shadow” struct (e.g., YourStructFile for YourStruct) where each field is wrapped in Option<T>. This shadow struct is designed for deserialization from configuration files (e.g., JSON, TOML, YAML).
  2. An implementation of the FromFile trait for your original struct. This includes the from_file method, which takes an Option<YourStructFile> and constructs your final YourStruct. It intelligently fills in None fields with either:
    • An expression you supply via #[from_file(default = ...)].
    • Default::default() (if no default attribute is provided, requiring T: Default).

§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: Enables serde serialization/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 derive merge::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 the Default trait.

Derive Macros§

FromFile
Implements the FromFile trait.