With the ClapSerde
procedural macro both clap and serde can be derived from a struct.
Then the struct can be parsed from clap and serde sources as in a layered config: the last
source has the precedence.
rust ignore
Args::from(serde_parsed)
.merge_clap();
In the snippet the precedence is:
In this example we define a struct which derives both clap and serde. The struct has various parameter type and also various attributes on its fields.
Finally we parse the structure from a YAML file with serde and then from command line with clap. The arguments from clap will override those from serde; the default value will be used if no source contained the field.
```rust use clapserdederive::{ clap::{self, ArgAction}, serde::Serialize, ClapSerde, };
pub struct Args {
/// Input files
pub input: Vec
/// String argument
#[clap(short, long)]
name: String,
/// Skip serde deserialize
#[default(13)]
#[serde(skip_deserializing)]
#[clap(long = "num")]
pub clap_num: u32,
/// Skip clap
#[serde(rename = "number")]
#[clap(skip)]
pub serde_num: u32,
/// Recursive fields
#[clap_serde]
#[clap(flatten)]
pub suboptions: SubConfig,
}
pub struct SubConfig { #[default(true)] #[clap(long = "no-flag", action = ArgAction::SetFalse)] pub flag: bool, }
let args = Args::from(serdeyaml::fromstr::<
You can easily take the config file path from command line in this way.
```rust use std::{fs::File, io::BufReader};
use clapserdederive::{ clap::{self, Parser}, ClapSerde, };
struct Args {
/// Input files
input: Vec
/// Config file
#[clap(short, long = "config", default_value = "config.yml")]
config_path: std::path::PathBuf,
/// Rest of arguments
#[clap(flatten)]
pub config: <Config as ClapSerde>::Opt,
}
struct Config { /// String argument #[clap(short, long)] name: String, }
// Parse whole args with clap let mut args = Args::parse();
// Get config file
let config = if let Ok(f) = File::open(&args.configpath) {
// Parse config with serde
match serdeyaml::from_reader::<_,