-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Arg::default_value* and friends use impl IntoResettable<OsStr> for the type of defaults for an argument. Runtime arguments arrive as OsString (or OsStr) this makes sense that a default value needs to convert to the same type as if it had been presented on the runtime execution call.
An implementation of impl IntoResettable<OsStr> for Option<&'static str> is provided in the builder crate, which is helpful, when the default value provided is a static compile time string:
clap/clap_builder/src/builder/resettable.rs
Lines 124 to 131 in 4e1a565
| impl IntoResettable<OsStr> for Option<&'static str> { | |
| fn into_resettable(self) -> Resettable<OsStr> { | |
| match self { | |
| Some(s) => Resettable::Value(s.into()), | |
| None => Resettable::Reset, | |
| } | |
| } | |
| } |
But there are other situations where this is not enough. Namely,
impl IntoResettable<OsStr> for Option<OsStr>impl IntoResettable<OsStr> for Option<std::ffi::OsString>
are generally useful and needed in my case. The first for completeness and the second to go from an owned OS specific string to the clap::builder::OsStr without having to go through a lossy conversion first.
Implementation of both is straightforward.
impl IntoResettable<OsStr> for Option<OsStr> {
fn into_resettable(self) -> Resettable<OsStr> {
match self {
Some(s) => Resettable::Value(s),
None => Resettable::Reset,
}
}
}
#[cfg(feature = "string")]
impl IntoResettable<OsStr> for Option<std::ffi::OsString> {
fn into_resettable(self) -> Resettable<OsStr> {
match self {
Some(s) => Resettable::Value(s.into()),
None => Resettable::Reset,
}
}
}
My situation is that I want the default value for an argument to be the home directory. Getting the home directory can fail, so I'd like to handle this gracefully by returning None when it fails, allowing clap to treat the argument as having no default. This would make it work seamlessly with the derive API:
// if home::home_dir() fails, returns None and forces clap into normal behavior for a missing value
// if home::home_dir() succeeds, there's no loss of information in converting to a OsStr
fn default_data_dir() -> Option<std::ffi::OsString> {
home::home_dir()
.map(|path| path.join(DATA_DIRECTORY_NAME).into_os_string())
}
// somewhere else
#[arg(default_value_t = default_data_dir())]
pub data_directory: Option<PathBuf>,