Skip to content
This repository has been archived by the owner on Jan 1, 2022. It is now read-only.

Derive attribute that specializes a user-provided function that gets to modify Arg #233

Open
2 tasks done
epage opened this issue Dec 6, 2021 · 1 comment
Open
2 tasks done

Comments

@epage
Copy link
Owner

epage commented Dec 6, 2021

Issue by marjakm
Thursday Nov 04, 2021 at 21:24 GMT
Originally opened as clap-rs/clap#2991


Please complete the following tasks

  • I have searched the discussions
  • I have searched the existing issues

Clap Version

master 879dd23

Describe your use case

I have a bunch of messages defined in protobuf, I'd like to make a CLI to send those messages - clap should be able to parse the messages from terminal. I generate rust structs from protobuf definitions using prost and I can automatically add clap_derive attributes, but I can't specify the attributes flexibly enough to solve my use-case.

Problematic cases are when one struct contains another optional struct:

struct A {
   simple: u32,
   inner: Option<B>
}

struct B {
   a: u32,
   b: String,
}

When automatically adding attributes, I can differentiate between protobuf native (u32, bool, ..) types and complex types (another struct), but I don't know if the complex type is Option<B> or Option<C>.

What I want is to parse these complex types (for example A::inner) from from json string from the command line. The default value in this case should be None (empty string), which is simple enough to implement currently. But, I'd also like to generate an example json value for the Some case in the CLI help. But what annotation can I add to the field A::inner, where I only know that its a optional struct, but don't know which struct type (B or C) it actually is?

Its really easy for me to write a function to generate the string:

fn example_json<T: serde::Serialize>(t: T) -> &'static str { todo!() } 

All I'd need to have some attribute in clap_derive to call that function and I don't need to know which type is A::inner

#[derive(clap::Parser)]
struct A {
   simple: u32,
   #[clap(about = example_json]
   inner: Option<B>
}

which should call something like this in the right place:

Arg::about(arg, example_json::<Option<B>>())

default_value_t attribute actually does exactly the type-based fn specialization - I'd just like to be able to provide the generic fn and have it specialized by the field type.

Describe the solution you'd like

I implemented something that would solve my problems here:

clap-rs/clap#2990

Alternatives, if applicable

No response

Additional Context

Conversation started on #2813

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by epage
Thursday Nov 04, 2021 at 21:39 GMT


Thank you! This context helps a lot!

So you are wanting to determine the value for an attribute based on the type of the field it is applied to, with the example being given of dynamically generating about, instead of manually doing it, to help with your code-gen use case.

This seems quite specialized. The first question to answer is if this is needed and then the second is how.

A key part stuck out in your comment

I don't know if the complex type is Option<B> or Option<C>.

This is what is leading you to wanting to defer to clap to generate this information. Could you help me understand this problem a little more? I'm wanting to learn more about how this clap struct generation is happening to see how all of this fits together and if there is a better, more general solution here.

If we do move forward with this, clap::Arg::modify_fn doesn't quite make sense on its own, only in the context of clap_derive. I wonder if we can instead do this purely within clap_derive.

Its also unclear how clap-rs/clap#2683 might impact any API design on clap in the future.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant