Repository: google/argh (language: rust)

Issue:
Vec with default does not work
You can't have a repeated option with a default it looks like:

```
#[derive(FromArgs, PartialEq, Debug, Clone)]
/// Foo
#[argh(description = "foo")]
pub struct TestArgs {
    /// test repeated with default
    #[argh(option, default = "default_param_req()")]
    pub param: Vec<String>,
}

fn default_param_req() -> Vec<String> { 
    vec!["foo".to_string(), "bar".to_string()] 
}
```


fails with:
```
the trait bound `std::vec::Vec<String>: std::str::FromStr` is not satisfied
```



Discussion / hints:

Fix patch:
diff --git a/argh/src/lib.rs b/argh/src/lib.rs
index b191459..3cbfa5f 100644
--- a/argh/src/lib.rs
+++ b/argh/src/lib.rs
@@ -833,6 +833,14 @@ impl<T> ParseValueSlot for ParseValueSlotTy<Vec<T>, T> {
     }
 }
 
+// `ParseValueSlotTy<Option<Vec<T>>, T>` is used as the slot for optional repeating arguments.
+impl<T> ParseValueSlot for ParseValueSlotTy<Option<Vec<T>>, T> {
+    fn fill_slot(&mut self, arg: &str, value: &str) -> Result<(), String> {
+        self.slot.get_or_insert_with(Vec::new).push((self.parse_func)(arg, value)?);
+        Ok(())
+    }
+}
+
 /// A type which can be the receiver of a `Flag`.
 pub trait Flag {
     /// Creates a default instance of the flag value;
diff --git a/argh_derive/src/args_info.rs b/argh_derive/src/args_info.rs
index ae640a7..969acf0 100644
--- a/argh_derive/src/args_info.rs
+++ b/argh_derive/src/args_info.rs
@@ -234,10 +234,14 @@ fn impl_args_info_data<'a>(
             Optionality::None => quote! { argh::Optionality::Required },
             Optionality::Defaulted(_) => quote! { argh::Optionality::Optional },
             Optionality::Optional => quote! { argh::Optionality::Optional },
-            Optionality::Repeating if field.attrs.greedy.is_some() => {
+            Optionality::Repeating | Optionality::DefaultedRepeating(_)
+                if field.attrs.greedy.is_some() =>
+            {
                 quote! { argh::Optionality::Greedy }
             }
-            Optionality::Repeating => quote! { argh::Optionality::Repeating },
+            Optionality::Repeating | Optionality::DefaultedRepeating(_) => {
+                quote! { argh::Optionality::Repeating }
+            }
         };
 
         match field.kind {
diff --git a/argh_derive/src/help.rs b/argh_derive/src/help.rs
index bd20622..68a427a 100644
--- a/argh_derive/src/help.rs
+++ b/argh_derive/src/help.rs
@@ -157,7 +157,7 @@ fn positional_usage(out: &mut String, field: &StructField<'_>) {
     }
     let name = field.positional_arg_name();
     out.push_str(&name);
-    if field.optionality == Optionality::Repeating {
+    if matches!(field.optionality, Optionality::Repeating | Optionality::DefaultedRepeating(_)) {
         out.push_str("...");
     }
     if field.attrs.greedy.is_none() {
@@ -194,7 +194,10 @@ fn option_usage(out: &mut String, field: &StructField<'_>) {
             } else {
                 out.push_str(long_name.trim_start_matches("--"));
             }
-            if field.optionality == Optionality::Repeating {
+            if matches!(
+                field.optionality,
+                Optionality::Repeating | Optionality::DefaultedRepeating(_)
+            ) {
                 out.push_str("...");
             }
             out.push('>');
diff --git a/argh_derive/src/lib.rs b/argh_derive/src/lib.rs
index 7e12542..6eff785 100644
--- a/argh_derive/src/lib.rs
+++ b/argh_derive/src/lib.rs
@@ -67,6 +67,7 @@ enum Optionality {
     Defaulted(TokenStream),
     Optional,
     Repeating,
+    DefaultedRepeating(TokenStream),
 }
 
 impl PartialEq<Optionality> for Optionality {
@@ -159,8 +160,14 @@ impl<'a> StructField<'a> {
                             tree
                         })
                         .collect();
-                    optionality = Optionality::Defaulted(tokens);
-                    ty_without_wrapper = &field.ty;
+                    let inner = if let Some(x) = ty_inner(&["Vec"], &field.ty) {
+                        optionality = Optionality::DefaultedRepeating(tokens);
+                        x
+                    } else {
+                        optionality = Optionality::Defaulted(tokens);
+                        &field.ty
+                    };
+                    ty_without_wrapper = inner;
                 } else {
                     let mut inner = None;
                     optionality = if let Some(x) = ty_inner(&["Option"], &field.ty) {
@@ -653,6 +660,9 @@ fn declare_local_storage_for_from_args_fields<'a>(
             Optionality::None | Optionality::Defaulted(_) => {
                 quote! { std::option::Option<#field_type> }
             }
+            Optionality::DefaultedRepeating(_) => {
+                quote! { std::option::Option<std::vec::Vec<#field_type>> }
+            }
         };
 
         match field.kind {
@@ -698,7 +708,7 @@ fn unwrap_from_args_fields<'a>(
                 Optionality::Optional | Optionality::Repeating => {
                     quote! { #field_name: #field_name.slot }
                 }
-                Optionality::Defaulted(tokens) => {
+                Optionality::Defaulted(tokens) | Optionality::DefaultedRepeating(tokens) => {
                     quote! {
                         #field_name: #field_name.slot.unwrap_or_else(|| #tokens)
                     }
@@ -708,7 +718,7 @@ fn unwrap_from_args_fields<'a>(
             FieldKind::SubCommand => match field.optionality {
                 Optionality::None => quote! { #field_name: #field_name.unwrap() },
                 Optionality::Optional | Optionality::Repeating => field_name.into_token_stream(),
-                Optionality::Defaulted(_) => unreachable!(),
+                Optionality::Defaulted(_) | Optionality::DefaultedRepeating(_) => unreachable!(),
             },
         }
     })
@@ -738,6 +748,9 @@ fn declare_local_storage_for_redacted_fields<'a>(
                     Optionality::Repeating => {
                         quote! { std::vec::Vec<String> }
                     }
+                    Optionality::DefaultedRepeating(_) => {
+                        quote! { std::option::Option<std::vec::Vec<String>> }
+                    }
                     Optionality::None | Optionality::Optional | Optionality::Defaulted(_) => {
                         quote! { std::option::Option<String> }
                     }
@@ -756,6 +769,9 @@ fn declare_local_storage_for_redacted_fields<'a>(
                     Optionality::Repeating => {
                         quote! { std::vec::Vec<String> }
                     }
+                    Optionality::DefaultedRepeating(_) => {
+                        quote! { std::option::Option<std::vec::Vec<String>> }
+                    }
                     Optionality::None | Optionality::Optional | Optionality::Defaulted(_) => {
                         quote! { std::option::Option<String> }
                     }
@@ -798,6 +814,13 @@ fn unwrap_redacted_fields<'a>(
                         __redacted.extend(#field_name.slot.into_iter());
                     }
                 }
+                Optionality::DefaultedRepeating(_) => {
+                    quote! {
+                        if let Some(__field_name) = #field_name.slot {
+                            __redacted.extend(__field_name.into_iter());
+                        }
+                    }
+                }
                 Optionality::None | Optionality::Optional | Optionality::Defaulted(_) => {
                     quote! {
                         if let Some(__field_name) = #field_name.slot {
diff --git a/argh_shared/src/lib.rs b/argh_shared/src/lib.rs
index 20383a4..c9306e0 100644
--- a/argh_shared/src/lib.rs
+++ b/argh_shared/src/lib.rs
@@ -81,7 +81,7 @@ pub struct FlagInfo<'a> {
     /// The long string of the flag.
     pub long: &'a str,
     /// The single character short indicator
-    /// for trhis flag.
+    /// for this flag.
     pub short: Option<char>,
     /// The description of the flag.
     pub description: &'a str,
@@ -102,7 +102,7 @@ pub enum FlagInfoKind<'a> {
     Option { arg_name: &'a str },
 }
 
-/// The optionality defines the requirments related
+/// The optionality defines the requirements related
 /// to the presence of the argument on the command line.
 #[derive(Debug, Default, PartialEq, Eq, serde::Serialize)]
 pub enum Optionality {
@@ -117,7 +117,7 @@ pub enum Optionality {
     /// or more times.
     Repeating,
     /// Greedy is used for positional arguments which
-    /// capture the all command line input upto the next flag or
+    /// capture the all command line input up to the next flag or
     /// the end of the input.
     Greedy,
 }


Test patch: