-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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 FromParam for Enum #2832
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this is a great start.
Ideally, we should include some ui-fail tests with this macro, see core/codegen/tests/ui-fail/from_form.rs for some examples.
@SergioBenitez, I think this should be good to go with the changes I've recommended, let us know if you have any other comments.
079ee9f
to
9df9014
Compare
Hi @the10thWiz Thanks for the feedback. I have applied all your suggestions but I am not sure what is the point of From the name, I guess everything should fail in it right? How do you check that each structure fails? In my understanding, just one failing would be sufficient for the test to pass, right? |
Not in this case. We use Use |
Thanks for the explanations. I have updated the tests with the correct stderr. Should I add it to nightly too or just stable? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're very close! In terms of the ui-fail test, I think we will need a nightly version, but I might just take care of it myself.
.fields_validate(|_, fields| { | ||
if !fields.is_empty() { | ||
return Err(fields.span().error("Only empty enums are accepted")); | ||
} | ||
|
||
Ok(()) | ||
}) | ||
) | ||
.inner_mapper(MapperBuild::new() | ||
.enum_map(|_, data| { | ||
let mut matches = vec![]; | ||
|
||
for field in data.variants() { | ||
let field_name = &field; | ||
matches.push(quote!( | ||
stringify!(#field_name) => Ok(Self::#field_name), | ||
)) | ||
} | ||
|
||
quote! { | ||
type Error = &'a str; | ||
fn from_param(param: &'a str) -> Result<Self, Self::Error> { | ||
match param { | ||
#(#matches)* | ||
_ => Err("Failed to find enum") | ||
} | ||
} | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you take a look at the indentation here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see any issue with it. I checked with the auto-indent in my IDE and with cargo fmt --check
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rocket intentionally disables rustfmt (cargo fmt
), since it doesn't handle some of the more complex trait bounds well. I suspect your IDE's auto-indent is based on rustfmt as well (I don't think there is another well built option out there yet), so that's likely why it's not picking up on the issues here.
The specific issue here is that not all the indentations are the same size (This is extremely obvious in my editor, since I have indent guides turned on). If you would like, I can push a fixed version to this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even after enabling the indent guide, I don't see it. So it would be nice if you can do it.
I have pushed the requested changes and wrote a few comments |
You're close, just a few things to fix. The indentation on the one file needs to be fixed, and the test failure in the one doc-test needs to be addressed. Other than that, I'm quite happy with this feature. |
error: [note] error occurred while deriving `FromParam` | ||
--> tests/ui-fail-stable/from_param.rs:8:10 | ||
| | ||
8 | #[derive(FromParam)] | ||
| ^^^^^^^^^ | ||
| | ||
= note: this error originates in the derive macro `FromParam` (in Nightly builds, run with -Z macro-backtrace for more info) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's surprising that this isn't an actual note
, since they exist on nightly. Is this being tested? Is this the output that's actually being produced?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad. I supposed that it would produce the same output. Just tested and fixed it.
.validator(ValidatorBuild::new() | ||
.fields_validate(|_, fields| { | ||
if !fields.is_empty() { | ||
return Err(fields.span().error("Only empty enums are accepted")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the wording here should be "only enums without variants are supported" ah, I confused myself. The actual constraint here is "only enum variants with nullary (zero-length) fields".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably Only enums without data fields are supported
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the language I was looking for was getting away form "enums with foo" and instead going for "enum variants with foo," since that's the actual constant. We should also make sure the error is on the fields themselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also make sure the error is on the fields themselves.
Do you mean the error message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
He means the associated span, and it looks like you already have it correct.
let mut matches = vec![]; | ||
|
||
for field in data.variants() { | ||
let field_name = &field; | ||
matches.push(quote!( | ||
stringify!(#field_name) => Ok(Self::#field_name), | ||
)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can probably be a .iter().map()
. I don't recall if quote
can use the iterator directly, but if it can, then that would save us the allocation here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this correctly handle raw idents? IE:
enum Foo {
r#for,
}
// parse "for" as `Foo::r#for`
Finally, it want to note that this macro is almost exactly the FromFormField
macro except that macro also allows renaming fields. Is there a reason to have two implementations, or can we simply factor out the existing FromFormField
implementation for FromParam
?
I agree that I am just wondering if it makes sense to merge them together. Is there any chance that By the way, raw identifiers are not working. How would do you like to proceed? Removing the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! I'll take care of formatting and raw idents (Ident
has an unraw
method that strips the r#
), and merge these changes.
Looking forward, I think we will want to add support for a rename attribute, as well as refactor both this and the FromFormField
derive to share code as much as possible. FromFormField
may eventually wind up with a more complex macro, since it does have quite a bit more context (i.e. the name, and potentially a whole file). It also matches case-insensitively, but I think the difference in behavior is justified.
Merged in 38cebeb! |
Implement #2826