provcfg_clap/lib.rs
1//! Clap integration for [`provcfg`](https://docs.rs/provcfg).
2//!
3//! Derive [`ClapArgs`] alongside `provcfg::Configurable` to generate a
4//! `<Name>Args` struct (a `clap::Args`) plus a `From<&<Name>Args> for
5//! <Name>Partial` impl. A clap-parsed command line then flows into a provcfg
6//! CLI source without a hand-written per-field conversion.
7//!
8//! ```
9//! use clap::Parser;
10//! use provcfg::{Category, Config, Configurable};
11//! use provcfg_clap::ClapArgs;
12//!
13//! #[derive(Configurable, ClapArgs, Clone, Default, serde::Deserialize, serde::Serialize)]
14//! #[configurable(clap_prefix = "registry")]
15//! struct Registry {
16//! data_dir: String, // exposed as --registry-data-dir
17//! port: u16, // exposed as --registry-port
18//! }
19//!
20//! #[derive(Parser)]
21//! struct Cli {
22//! #[command(flatten)]
23//! registry: RegistryArgs,
24//! }
25//!
26//! let cli = Cli::parse_from(["app", "--registry-data-dir", "/var/lib/reg"]);
27//!
28//! // The generated `From<&RegistryArgs>` builds the provcfg partial for us.
29//! let partial: RegistryPartial = (&cli.registry).into();
30//! let registry = Config::new().add_cli(partial).build::<RegistryProv>().unwrap();
31//!
32//! assert_eq!(registry.data_dir.value(), "/var/lib/reg");
33//! assert_eq!(registry.data_dir.source().category(), Category::Cli);
34//! // `--registry-port` was not passed, so `port` keeps its compiled-in default.
35//! assert_eq!(registry.port.source().category(), Category::Default);
36//! ```
37//!
38//! The `ClapArgs` derive:
39//!
40//! - generates `<Name>Args` with each leaf wrapped in `Option<T>` and an
41//! `#[arg(long = "<prefix>-<field>")]` auto-derived from the field name;
42//! - forwards any user-written `#[arg(...)]` attributes; a user-supplied
43//! `long = "..."` overrides the auto-derived one;
44//! - for `#[configurable(nested)]` fields emits `#[command(flatten)]` into the
45//! nested type's own `Args` struct (which must also derive `ClapArgs`);
46//! - omits `#[configurable(skip)]` fields from both the Args struct and the
47//! `From` impl.
48
49/// Optional convenience re-export. The `ClapArgs` derive emits `::clap::Args`,
50/// so consumers must have `clap` as a direct dependency regardless; this
51/// re-export is only here for callers that prefer to reach for clap through
52/// `provcfg_clap::clap`.
53pub use clap;
54pub use provcfg_clap_macros::ClapArgs;