Skip to main content

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;