Skip to content

Commit

Permalink
docs: Expand on deprecation instructions
Browse files Browse the repository at this point in the history
epage committed Sep 12, 2022
1 parent d1ff063 commit 7272aa0
Showing 9 changed files with 1,028 additions and 100 deletions.
10 changes: 9 additions & 1 deletion clap_complete/src/shells/shell.rs
Original file line number Diff line number Diff line change
@@ -24,7 +24,15 @@ pub enum Shell {

impl Shell {
/// Deprecated, replaced with [`EnumValueParser`][clap::builder::EnumValueParser]
#[deprecated(since = "3.2.0", note = "Replaced with `EnumValueParser`")]
///
/// Builder API: Instead of `arg.possible_values(Shell::possible_values())`, use `arg.value_parser(value_parser!(Shell))`
#[deprecated(
since = "3.2.0",
note = "Replaced with `EnumValueParser`
Builder API: Instead of `arg.possible_values(Shell::possible_values())`, use `arg.value_parser(value_parser!(Shell))`
"
)]
pub fn possible_values() -> impl Iterator<Item = PossibleValue<'static>> {
Shell::value_variants()
.iter()
2 changes: 1 addition & 1 deletion clap_derive/src/derives/args.rs
Original file line number Diff line number Diff line change
@@ -302,7 +302,7 @@ pub fn gen_augment(
parse_try_from_os_str();
},
ParserKind::FromFlag => quote_spanned! { func.span()=>
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::SetTrue)]`")]
#[deprecated(since = "3.2.0", note = "Replaced with `#[clap(action = ArgAction::SetTrue, default_value = <absent>, default_missing_value = <present>)]`")]
fn parse_from_flag() {
}
parse_from_flag();
24 changes: 22 additions & 2 deletions src/builder/action.rs
Original file line number Diff line number Diff line change
@@ -71,11 +71,24 @@ pub enum ArgAction {
/// ```
Append,
/// Deprecated, replaced with [`ArgAction::Set`] or [`ArgAction::Append`]
///
/// Builder: Instead of `arg.action(ArgAction::StoreValue)`,
/// - Use `arg.action(ArgAction::Set)` for single-occurrence arguments
/// - Use `arg.action(ArgAction::Append)` for multiple-occurrence arguments
///
/// Derive: opt-in to the new behavior with `#[clap(action)]`
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `ArgAction::Set` or `ArgAction::Append`"
note = "Replaced with `ArgAction::Set` or `ArgAction::Append`
Derive: opt-in to the new behavior with `#[clap(action)]`
Builder: Instead of `arg.action(ArgAction::StoreValue)`,
- Use `arg.action(ArgAction::Set)` for single-occurrence arguments
- Use `arg.action(ArgAction::Append)` for multiple-occurrence arguments
"
)
)]
StoreValue,
@@ -84,7 +97,14 @@ pub enum ArgAction {
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `ArgAction::SetTrue` or `ArgAction::Count`"
note = "Replaced with `ArgAction::SetTrue` or `ArgAction::Count`
Derive: opt-in to the new behavior with `#[clap(action)]`
Builder: Instead of `arg.action(ArgAction::IncOccurrence)`,
- Use `arg.action(ArgAction::SetTrue)` if you just care if its set, then switch `matches.is_present` to `matches.get_flag`
- Use `arg.action(ArgAction::Count)` if you care how many times its set, then switch `matches.occurrences_of` to `matches.get_count`
"
)
)]
IncOccurrence,
534 changes: 489 additions & 45 deletions src/builder/app_settings.rs

Large diffs are not rendered by default.

156 changes: 140 additions & 16 deletions src/builder/arg.rs
Original file line number Diff line number Diff line change
@@ -134,10 +134,18 @@ impl<'help> Arg<'help> {
self
}

/// Deprecated, replaced with [`Arg::id`]
/// Deprecated, replaced with [`Arg::id`] to avoid confusion with [`Arg::value_name`]
///
/// Builder: replaced `arg.name(...)` with `arg.id(...)`
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.1.0", note = "Replaced with `Arg::id`")
deprecated(
since = "3.1.0",
note = "Replaced with `Arg::id` to avoid confusion with `Arg::value_name`
Builder: replaced `arg.name(...)` with `arg.id(...)`
"
)
)]
pub fn name<S: Into<&'help str>>(self, n: S) -> Self {
self.id(n)
@@ -790,7 +798,13 @@ impl<'help> Arg<'help> {
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `Arg::action` (Issue #3772)")
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::action` (Issue #3772)
Builder: replace `arg.multiple_occurrences(true)` with `arg.action(ArgAction::Append)` when taking a value and `arg.action(ArgAction::Count)` with `matches.get_count` when not
"
)
)]
pub fn multiple_occurrences(self, yes: bool) -> Self {
if yes {
@@ -800,14 +814,23 @@ impl<'help> Arg<'help> {
}
}

/// Deprecated, for flags this is replaced with `action(ArgAction::Count).value_parser(value_parser!(u8).range(..max))`
/// Deprecated, for flags, this is replaced with `RangedI64ValueParser::range`
///
/// Derive: `#[clap(action = ArgAction::Count, value_parser = value_parser!(u8).range(..max))]`
///
/// Builder: `arg.action(ArgAction::Count).value_parser(value_parser!(u8).range(..max))`
#[inline]
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "For flags, replaced with `action(ArgAction::Count).value_parser(value_parser!(u8).range(..max))`"
note = "For flags, this is replaced with `RangedI64ValueParser::range`
Derive: `#[clap(action = ArgAction::Count, value_parser = value_parser!(u8).range(..max))]`
Builder: `arg.action(ArgAction::Count).value_parser(value_parser!(u8).range(..max))`
"
)
)]
pub fn max_occurrences(mut self, qty: usize) -> Self {
@@ -1516,11 +1539,25 @@ impl<'help> Arg<'help> {
}

/// Deprecated, replaced with [`Arg::value_parser(...)`]
///
/// Derive: replace `#[clap(validator = ...)]` with `#[clap(value_parser = ...)]`
///
/// Builder: replace `arg.validator(...)` with `arg.value_parser(...)` and `matches.value_of` with
/// `matches.get_one::<T>` or `matches.values_of` with `matches.get_many::<T>`
#[inline]
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `Arg::value_parser(...)`")
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::value_parser(...)`
Derive: replace `#[clap(validator = <fn>)]` with `#[clap(value_parser = <fn>)]`
Builder: replace `arg.validator(<fn>)` with `arg.value_parser(<fn>)` and `matches.value_of` with
`matches.get_one::<T>` or `matches.values_of` with `matches.get_many::<T>`
"
)
)]
pub fn validator<F, O, E>(mut self, mut f: F) -> Self
where
@@ -1537,7 +1574,16 @@ impl<'help> Arg<'help> {
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `Arg::value_parser(...)`")
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::value_parser(...)`
Derive: replace `#[clap(validator = <fn>)]` with `#[clap(value_parser = <TypedValueParser>)]`
Builder: replace `arg.validator(<fn>)` with `arg.value_parser(<TypedValueParser>)` and `matches.value_of_os` with
`matches.get_one::<T>` or `matches.values_of_os` with `matches.get_many::<T>`
"
)
)]
pub fn validator_os<F, O, E>(mut self, mut f: F) -> Self
where
@@ -1551,11 +1597,20 @@ impl<'help> Arg<'help> {
}

/// Deprecated in [Issue #3743](https://github.com/clap-rs/clap/issues/3743), replaced with [`Arg::value_parser(...)`]
///
/// Derive: replace `#[clap(validator_regex = ...)]` with `#[clap(value_parser = |s: &str| regex.is_match(s).then(|| s.to_owned()).ok_or_else(|| ...))]`
///
/// Builder: replace `arg.validator_regex(...)` with `arg.value_parser(|s: &str| regex.is_match(s).then(|| s.to_owned()).ok_or_else(|| ...))`
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Deprecated in Issue #3743; eplaced with `Arg::value_parser(...)`"
note = "Deprecated in Issue #3743; replaced with `Arg::value_parser(...)`
Derive: replace `#[clap(validator_regex = ...)]` with `#[clap(value_parser = |s: &str| regex.is_match(s).then(|| s.to_owned()).ok_or_else(|| ...))]`
Builder: replace `arg.validator_regex(...)` with `arg.value_parser(|s: &str| regex.is_match(s).then(|| s.to_owned()).ok_or_else(|| ...))`
"
)
)]
#[cfg(feature = "regex")]
@@ -1576,11 +1631,22 @@ impl<'help> Arg<'help> {
}

/// Deprecated, replaced with [`Arg::value_parser(PossibleValuesParser::new(...))`]
///
/// Derive: replace `#[clap(possible_value = <1>, possible_value = <2>, ...)]` with `#[clap(value_parser = [<1>, <2>])]`.
/// If the field is not a `String`, instead do `#[clap(value_parser = PossibleValueParser::new([<1>, <2>]).map(T::from_str))]`
///
/// Builder: replace `arg.possible_value(<1>).possible_value(<2>) with `arg.value_parser([<1>, <2>])`
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::value_parser(PossibleValuesParser::new(...)).takes_value(true)`"
note = "Replaced with `Arg::value_parser(PossibleValuesParser::new(...)).takes_value(true)`
Derive: replace `#[clap(possible_value = <1>, possible_value = <2>, ...)]` with `#[clap(value_parser = [<1>, <2>])]`.
If the field is not a `String`, instead do `#[clap(value_parser = PossibleValueParser::new([<1>, <2>]).map(T::from_str))]`
Builder: replace `arg.possible_value(<1>).possible_value(<2>) with `arg.value_parser([<1>, <2>])`
"
)
)]
#[must_use]
@@ -1593,11 +1659,22 @@ impl<'help> Arg<'help> {
}

/// Deprecated, replaced with [`Arg::value_parser(PossibleValuesParser::new(...))`]
///
/// Derive: replace `#[clap(possible_values = [<1>, <2>])]` with `#[clap(value_parser = [<1>, <2>])]`.
/// If the field is not a `String`, instead do `#[clap(value_parser = PossibleValueParser::new([<1>, <2>]).map(T::from_str))]`
///
/// Builder: replace `arg.possible_values([<1>, <2>) with `arg.value_parser([<1>, <2>])`
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::value_parser(PossibleValuesParser::new(...)).takes_value(true)`"
note = "Replaced with `Arg::value_parser(PossibleValuesParser::new(...)).takes_value(true)`
Derive: replace `#[clap(possible_values = [<1>, <2>])]` with `#[clap(value_parser = [<1>, <2>])]`.
If the field is not a `String`, instead do `#[clap(value_parser = PossibleValueParser::new([<1>, <2>]).map(T::from_str))]`
Builder: replace `arg.possible_values([<1>, <2>) with `arg.value_parser([<1>, <2>])`
"
)
)]
#[must_use]
@@ -1729,15 +1806,29 @@ impl<'help> Arg<'help> {
}
}

/// Deprecated, replaced with [`Arg::value_parser(...)`] with either [`ValueParser::os_string()`][crate::builder::ValueParser::os_string]
/// or [`ValueParser::path_buf()`][crate::builder::ValueParser::path_buf]
/// Deprecated, replaced with [`value_parser`][Arg::value_parser]
///
/// Derive: replace `#[clap(allow_invalid_utf8 = true)]` with `#[clap(action)]` (which opts-in to the
/// new clap v4 behavior which gets the type via `value_parser!`)
///
/// Builder: replace `arg.allow_invalid_utf8(true)` with `arg.value_parser(value_parser!(T))` where
/// `T` is the type of interest, like `OsString` or `PathBuf`, and `matches.value_of_os` with
/// `matches.get_one::<T>` or `matches.values_of_os` with `matches.get_many::<T>`
#[inline]
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::value_parser(...)` with either `ValueParser::os_string()` or `ValueParser::path_buf()`"
note = "Replaced with `value_parser`
Derive: replace `#[clap(allow_invalid_utf8 = true)]` with `#[clap(action)]` (which opts-in to the
new clap v4 behavior which gets the type via `value_parser!`)
Builder: replace `arg.allow_invalid_utf8(true)` with `arg.value_parser(value_parser!(T))` where
`T` is the type of interest, like `OsString` or `PathBuf`, and `matches.value_of_os` with
`matches.get_one::<T>` or `matches.values_of_os` with `matches.get_many::<T>`
"
)
)]
pub fn allow_invalid_utf8(self, yes: bool) -> Self {
@@ -1749,13 +1840,22 @@ impl<'help> Arg<'help> {
}

/// Deprecated, replaced with [`Arg::value_parser(NonEmptyStringValueParser::new())`]
///
/// Derive: replace `#[clap(forbid_empty_values = true)]` with `#[clap(value_parser = NonEmptyStringValueParser::new())]`
///
/// Builder: replace `arg.forbid_empty_values(true)` with `arg.value_parser(NonEmptyStringValueParser::new())`
#[inline]
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::value_parser(NonEmptyStringValueParser::new())`"
note = "Replaced with `Arg::value_parser(NonEmptyStringValueParser::new())`
Derive: replace `#[clap(forbid_empty_values = true)]` with `#[clap(value_parser = NonEmptyStringValueParser::new())]`
Builder: replace `arg.forbid_empty_values(true)` with `arg.value_parser(NonEmptyStringValueParser::new())`
"
)
)]
pub fn forbid_empty_values(self, yes: bool) -> Self {
@@ -1881,11 +1981,23 @@ impl<'help> Arg<'help> {
}

/// Deprecated, replaced with [`Arg::use_value_delimiter`]
///
/// Derive: replace `#[clap(use_delimiter = true)]` with `#[clap(use_value_delimiter = true)]`
///
/// Builder: replace `arg.use_delimiter(true)` with `arg.use_value_delimiter(true)`
#[inline]
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.1.0", note = "Replaced with `Arg::use_value_delimiter`")
deprecated(
since = "3.1.0",
note = "Replaced with `Arg::use_value_delimiter`
Derive: replace `#[clap(use_delimiter = true)]` with `#[clap(use_value_delimiter = true)]`
Builder: replace `arg.use_delimiter(true)` with `arg.use_value_delimiter(true)`
"
)
)]
pub fn use_delimiter(self, yes: bool) -> Self {
self.use_value_delimiter(yes)
@@ -2008,11 +2120,23 @@ impl<'help> Arg<'help> {
}

/// Deprecated, replaced with [`Arg::require_value_delimiter`]
///
/// Derive: replace `#[clap(require_delimiter = true)]` with `#[clap(require_value_delimiter = true)]`
///
/// Builder: replace `arg.require_delimiter(true)` with `arg.require_value_delimiter(true)`
#[inline]
#[must_use]
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.1.0", note = "Replaced with `Arg::require_value_delimiter`")
deprecated(
since = "3.1.0",
note = "Replaced with `Arg::require_value_delimiter`
Derive: replace `#[clap(require_delimiter = true)]` with `#[clap(require_value_delimiter = true)]`
Builder: replace `arg.require_delimiter(true)` with `arg.require_value_delimiter(true)`
"
)
)]
pub fn require_delimiter(self, yes: bool) -> Self {
self.require_value_delimiter(yes)
10 changes: 9 additions & 1 deletion src/builder/arg_group.rs
Original file line number Diff line number Diff line change
@@ -129,9 +129,17 @@ impl<'help> ArgGroup<'help> {
}

/// Deprecated, replaced with [`ArgGroup::id`]
///
/// Builder: replaced `group.name(...)` with `group.id(...)`
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.1.0", note = "Replaced with `ArgGroup::id`")
deprecated(
since = "3.1.0",
note = "Replaced with `ArgGroup::id`
Builder: replaced `group.name(...)` with `group.id(...)`
"
)
)]
pub fn name<S: Into<&'help str>>(self, n: S) -> Self {
self.id(n)
280 changes: 254 additions & 26 deletions src/builder/arg_settings.rs

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion src/builder/command.rs
Original file line number Diff line number Diff line change
@@ -959,9 +959,21 @@ impl<'help> App<'help> {
}

/// Deprecated, replaced with [`ArgAction::Set`][super::ArgAction::Set]
///
/// The new actions (`ArgAction::Set`, `ArgAction::SetTrue`) do this by default.
///
/// See `ArgAction::StoreValue` and `ArgAction::IncOccurrence` for how to migrate
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `Arg::action(ArgAction::Set)`")
deprecated(
since = "3.2.0",
note = "Replaced with `Arg::action(ArgAction::...)`
The new actions (`ArgAction::Set`, `ArgAction::SetTrue`) do this by default.
See `ArgAction::StoreValue` and `ArgAction::IncOccurrence` for how to migrate
"
)
)]
pub fn args_override_self(self, yes: bool) -> Self {
if yes {
98 changes: 91 additions & 7 deletions src/parser/matches/arg_matches.rs
Original file line number Diff line number Diff line change
@@ -405,9 +405,17 @@ impl ArgMatches {
}

/// Deprecated, replaced with [`ArgMatches::get_one()`]
///
/// Replace `m.value_of(...)` with `m.get_one::<String>(...).map(|s| s.as_str())`
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_one()`
Replace `m.value_of(...)` with `m.get_one::<String>(...).map(|s| s.as_str())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of<T: Key>(&self, id: T) -> Option<&str> {
@@ -418,9 +426,17 @@ impl ArgMatches {
}

/// Deprecated, replaced with [`ArgMatches::get_one()`]
///
/// Replace `m.value_of(...)` with `m.get_one::<String>(...).map(|s| s.as_str())`
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_one()`
Replace `m.value_of(...)` with `m.get_one::<String>(...).map(|s| s.as_str())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of_lossy<T: Key>(&self, id: T) -> Option<Cow<'_, str>> {
@@ -431,9 +447,17 @@ impl ArgMatches {
}

/// Deprecated, replaced with [`ArgMatches::get_one()`]
///
/// Replace `m.value_of(...)` with `m.get_one::<OsString>(...).map(|s| s.as_os_str())`
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_one()`")
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_one()`
Replace `m.value_of(...)` with `m.get_one::<OsString>(...).map(|s| s.as_os_str())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn value_of_os<T: Key>(&self, id: T) -> Option<&OsStr> {
@@ -446,7 +470,11 @@ impl ArgMatches {
/// Deprecated, replaced with [`ArgMatches::get_many()`]
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::get_many()`")
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::get_many()`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
pub fn values_of<T: Key>(&self, id: T) -> Option<Values> {
@@ -620,11 +648,30 @@ impl ArgMatches {

/// Deprecated, replaced with [`ArgAction::SetTrue`][crate::ArgAction] or
/// [`ArgMatches::contains_id`].
///
/// With `ArgAction::SetTrue` becoming the new flag default in clap v4, flags will always be present.
/// To make the migration easier, we've renamed this function so people can identify when they actually
/// care about an arg being present or if they need to update to the new way to check a flag's
/// presence.
///
/// For flags, call `arg.action(ArgAction::SetTrue)` and lookup the value with `matches.get_flag(...)`
///
/// For presence, replace `matches.is_present(...)` with `matches.contains_id(...)`
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with either `ArgAction::SetTrue` or `ArgMatches::contains_id(...)`"
note = "Replaced with either `ArgAction::SetTrue` or `ArgMatches::contains_id(...)` to avoid confusion over new semantics
With `ArgAction::SetTrue` becoming the new flag default in clap v4, flags will always be present.
To make the migration easier, we've renamed this function so people can identify when they actually
care about an arg being present or if they need to update to the new way to check a flag's
presence.
For flags, call `arg.action(ArgAction::SetTrue)` and lookup the value with `matches.get_flag(...)`
For presence, replace `matches.is_present(...)` with `matches.contains_id(...)`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
@@ -669,11 +716,28 @@ impl ArgMatches {

/// Deprecated, replaced with [`ArgAction::Count`][crate::ArgAction],
/// [`ArgMatches::get_many`]`.len()`, or [`ArgMatches::value_source`].
///
/// `occurrences_of`s meaning was overloaded and we are replacing it with more direct approaches.
///
/// For counting flags, call `arg.action(ArgAction::Count)` and lookup the value with `matches.get_count(...)`
///
/// To check if a user explicitly passed in a value, check the source with `matches.value_source(...)`
///
/// To see how many values there are, call `matches.get_many::<T>(...).map(|v| v.len())`
#[cfg_attr(
feature = "deprecated",
deprecated(
since = "3.2.0",
note = "Replaced with either `ArgAction::Count`, `ArgMatches::get_many(...).len()`, or `ArgMatches::value_source`"
note = "Replaced with either `ArgAction::Count`, `ArgMatches::get_many(...).len()`, or `ArgMatches::value_source`
`occurrences_of`s meaning was overloaded and we are replacing it with more direct approaches.
For counting flags, call `arg.action(ArgAction::Count)` and lookup the value with `matches.get_count(...)`
To check if a user explicitly passed in a value, check the source with `matches.value_source(...)`
To see how many values there are, call `matches.get_many::<T>(...).map(|v| v.len())`
"
)
)]
#[cfg_attr(debug_assertions, track_caller)]
@@ -914,7 +978,27 @@ impl ArgMatches {
#[doc(hidden)]
#[cfg_attr(
feature = "deprecated",
deprecated(since = "3.2.0", note = "Replaced with `ArgMatches::try_get_one()`")
deprecated(
since = "3.2.0",
note = "Replaced with `ArgMatches::try_get_one()`
When helping to catch mistyped argument IDs, we overlooked the use cases for more dynamic lookups
of arguments, so we added `is_valid_arg` as a short-term hack. Since then, we've generalized
`value_of` as `try_get_one` to give callers all the relevant information they need.
So replace
```
if matches.is_valid_arg(...) {
matches.value_of(...)
}
```
with
```
if let Ok(value) = matches.try_get_one::<T>(...) {
}
```
"
)
)]
pub fn is_valid_arg(&self, _id: impl Key) -> bool {
#[cfg(debug_assertions)]

0 comments on commit 7272aa0

Please sign in to comment.