-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
derive: flatten on Option fields #3123
Comments
The problem is "what does it mean?" Here, we have one field that is an option. Should structopt create a If we have 2 What about nested flatten? |
I just encountered this problem too, and I think my case is more clearcut: I have an optional filter argument and I want to add an additional second filter that can only be added if the first filter is set. I tried to represent this as following:
|
@TimoFreiberg How do you expect the top ( I guess this should work for you just fine struct Params {
#[structopt(flatten)]
range_filter: RangeFilter
}
#[derive(StructOpt)]
struct RangeFilter {
#[structopt(short = "b")]
bottom: Option<String>,
#[structopt(short = "t")]
top: Option<String>
} |
top should not be set unless bottom is set. I handled it similar to your suggestion now, but I panic when only top is set. |
@TimoFreiberg You can use #[derive(StructOpt)]
struct RangeFilter {
#[structopt(short = "b")]
bottom: Option<String>,
#[structopt(short = "t", requires = "bottom")]
top: Option<String>
} |
I propose to implement the first design variant since it would allow us to handle nested flatten quite naturally: #[derive(StructOpt)]
struct TopLevel {
#[structopt(flatten)]
section_a: Option<SectionA>,
}
#[derive(StructOpt)]
struct SectionA {
#[structopt(flatten)]
inner_sect: Option<InnerSection>,
#[structopt(long = "section_a.field")]
field: String,
}
#[derive(StructOpt)]
struct InnerSection {
#[structopt(long = "inner_section.field")]
field: String,
}
cc @TeXitoi do you agree? |
What about |
I'm afraid that implementing this will be very complicated to code, maintain and understand who to use. |
In my case: Given: #[derive(StructOpt, Debug, Serialize, Deserialize)]
pub struct Command1 {
// Some arguments
}
#[derive(StructOpt, Debug, Serialize, Deserialize)]
pub struct Command2 {
// Some arguments
} Need: #[derive(StructOpt, Debug, Serialize, Deserialize)]
pub struct MyCommand {
#[serde(flatten)]
#[structopt(flatten)]
com1: Command1,
#[serde(flatten)]
#[structopt(flatten, required_if("arg1"))]
com2: Option<Command2>,
#[structopt(short = "a", long)]
arg1: bool,
} In other words, in structure Of course we can create two separate structures for two options (with But good solution may be use flatten between our structures: #[derive(StructOpt, Debug, Serialize, Deserialize)]
pub struct MyCommand {
#[serde(flatten)]
#[structopt(flatten)]
com1: Command1,
}
#[derive(StructOpt, Debug, Serialize, Deserialize)]
pub struct MyCommandWithArg1 {
#[serde(flatten)]
#[structopt(flatten)]
my_com: MyCommand,
#[serde(flatten)]
#[structopt(flatten)]
com2: Command2,
} In this case we can reuse functionality of |
My two cents: maybe match whatever serde does? The feature request opened with "I have a usecase where a bunch of structures are used by both fwiw, I ended up here after trying a simpler thing: #[derive(StructOpt)]
struct Credentials {
#[structopt(long)]
username: String,
#[structopt(long)]
password: String,
}
#[derive(StructOpt)]
struct Opt {
// ...
#[structopt(flatten)]
credentials: Option<Credentials>,
// ...
} which I'd expect to have similar behavior as the following, with a more structured representation. #[derive(StructOpt)]
struct Opt {
// ...
#[structopt(long, requires="password")]
username: Option<String>,
#[structopt(long, requires="username")]
password: Option<String>,
// ...
} Not a must-have; it'd just make my code more readable and avoid having an unreachable error case later on: let credentials = match (opt.username, opt.password) {
(Some(username), Some(password)) => Some(Credentials {
username,
password,
}),
(None, None) => None,
_ => unreachable!(), // prevented by structopt requires
}; |
That would be really tricky to do this kind of things. |
Since this was discussed,
|
This was released in v4.0.10 |
Monday Apr 01, 2019 at 10:40 GMT
Originally opened as TeXitoi/structopt#175
I have a usecase where a bunch of structures are used by both
serde_derive
andstructopt_derive
in order to source cli-options and file-options in a uniform way. It works pretty well with#[structopt(flatten)]
and other annotations, except when trying to flattenOption<_>
fields.That is, a simplified example is as following:
This fails with:
Approaching this from my own crate, I think I can't solve this alone due to orphan rules (both the
StructOpt
trait and theOption
receiver are not originating in the crate). Thus I tried to add a blanketimpl<T: StructOpt> StructOpt for Option<T: StructOpt>
instructopt
; that pushed the issue a bit forward, but then I ended up stuck in proc-macro logic.@TeXitoi I'd like to know if you think it generally makes sense for
structopt
to take care of the Option case above, and if so adapting the derive logic to handle that.The text was updated successfully, but these errors were encountered: