docs: update libdocs

This commit is contained in:
2025-07-15 19:00:50 +03:00
parent dabacf02df
commit 9d365a9593
2 changed files with 177 additions and 44 deletions

View File

@@ -1,39 +1,42 @@
//! # filecaster
//! # filecaster-derive
//!
//! `filecaster` is a small `proc-macro` crate that provides a derivemacro
//! `#[derive(FromFile)]` to make it trivial to load partial configurations
//! from files, merge them with defaults, and get a fullypopulated struct.
//! `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 `<YourStruct>NameFile` struct in which each field is wrapped
//! in `Option<...>`.
//! 2. A constructor `YourStruct::from_file(file: Option<YourStructFile>) -> YourStruct`
//! that takes your partiallyfilled file struct, fills in `None` fields
//! with either:
//! - an expression you supply via `#[from_file(default = ...)]`, or
//! - `Default::default()` (requires `T: Default`)
//! 3. An implementation of `From<Option<YourStructFile>> for YourStruct`.
//! 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`).
//!
//! Because each field in the filestruct is optional, you can deserialize
//! e.g. JSON, YAML or TOML into it via Serde, then call `.from_file(...)`
//! to get your final struct.
//!
//! ## Optional perfield defaults
//! ## 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 structs
//! context. If you omit it, the macro will require `T: Default` and call
//! `unwrap_or_default()`.
//! context. If you omit it, the macro will require the field's type to implement
//! `Default` and will call `Default::default()`.
//!
//! Example:
//! ## Example
//!
//! ```rust
//! use filecaster::FromFile;
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Debug, Clone, FromFile)]
//! #[derive(Debug, Clone, PartialEq, FromFile, Serialize, Deserialize)]
//! struct AppConfig {
//! /// If the user does not specify a host, use `"127.0.0.1"`.
//! #[from_file(default = "127.0.0.1")]
@@ -43,38 +46,54 @@
//! #[from_file(default = 4)]
//! workers: usize,
//!
//! /// If not set, use `false`.
//! auto_reload: bool, // requires `bool: Default`
//! /// If not set, use `false`. Requires `bool: Default`.
//! auto_reload: bool,
//! }
//!
//! let file_content = r#"
//! {
//! "host": "localhost"
//! }
//! "#;
//! fn main() {
//! // Simulate file content (e.g., from a JSON file)
//! let file_content = r#"{
//! "host": "localhost",
//! "workers": 8
//! }"#;
//!
//! let config_from_file = serde_json::from_str::<AppConfigFile>(file_content).unwrap();
//! // After deserializing the partial config from disk (e.g. with Serde):
//! let cfg = AppConfig::from_file(Some(config_from_file));
//! println!("{cfg:#?}");
//! // 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();
//!
//! // 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));
//!
//! assert_eq!(config.host, "localhost");
//! assert_eq!(config.workers, 8);
//! 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.workers, 4);
//! assert_eq!(default_config.auto_reload, false);
//! }
//! ```
//!
//! ## Feature flags
//!
//! - `merge`
//! If you enable the `merge` feature, the generated `<Name>File` struct will
//! also derive `merge::Merge`, and you can layer multiple partial files
//! together before calling `.from_file(...)`. Any fieldlevel merge strategy
//! annotations (`#[merge(...)]`) are applied automatically.
//! - `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 tuplestructs or enums).
//! - All fields without a `#[from_file(default = ...)]` must implement `Default`.
//!
//! ## License
//!
//! MIT OR Apache-2.0
//!
//! - 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.
mod from_file;