-
-
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
uri! scope resolution issues #1120
Comments
Note: This only applies to unreleased versions of Rocket, notably, the |
This seems like it should be doable with type aliases: use std::path::PathBuf;
#[get("/hello/<s1>/<s2>/<rest..>")]
fn hello(s1: String, s2: &str, rest: PathBuf) { }
// generated:
type rocket__type_for_uri_param_hello_0 = String;
type rocket__type_for_uri_param_hello_1<'a> = &'a str;
type rocket__type_for_uri_param_hello_2 = PathBuf; Generated code would refer to the That requirement to spell out anonymous lifetimes seems not too burdensome - it's already a hard requirement in |
I've opened rust-lang/rfcs#2968, which would allow us to resolve this issue on stable. Edit: For posterity, besides the issue of identifying lifetimes, the |
Unfortunately, I don't see this as resolvable without support from |
Alright, I think I have a solution. First, we add the following
pub struct Ignored;
impl UriDisplay<Query> for Ignored {
fn fmt(&self, _: &mut Formatter<'_, Query>) -> fmt::Result {
Ok(())
}
}
impl<T: Ignorable<Query>> FromUriParam<Query, Ignored> for T {
type Target = Ignored;
fn from_uri_param(_: Ignored) -> Self::Target { Ignored }
}
pub trait IntoUriParam<P: Part, T> {
type Target: UriDisplay<P>;
fn into_uri_param(self) -> Self::Target;
}
impl<P: Part, T, U: FromUriParam<P, T>> IntoUriParam<P, U> for T {
type Target = U::Target;
fn into_uri_param(self) -> Self::Target {
U::from_uri_param(self)
}
} Then, we generate the following code for the example route #[get("/<a>/b/<_>?<c>&<d>&e&<f..>")]
fn foo(a: &str, c: usize, d: Option<Date>, f: MyForm) {}
struct foo {}
impl foo {
fn uri<'a>(
self,
a: impl IntoUriParam<Path, &'a str>,
_0: impl UriDisplay<Path>,
c: impl IntoUriParam<Query, usize>,
d: impl IntoUriParam<Query, Option<Date>>,
f: impl IntoUriParam<Query, MyForm>,
) -> RouteUriBuilder {
let _a = a.into_uri_param();
let _c = c.into_uri_param();
let _d = d.into_uri_param();
let _f = f.into_uri_param();
RouteUriBuilder::new(
UriArgumentsKind::Dynamic(
&[&_a, &"b", &_0],
),
UriArgumentsKind::Dynamic(
&[
UriQueryArgument::NameValue("c", &_c),
UriQueryArgument::NameValue("d", &_d),
UriQueryArgument::Raw("e"),
UriQueryArgument::Value(&_f),
]
)
)
}
} Finally, a call to (foo {}).uri(a, _0, c, d, f); While a call to (foo {}).uri(a, _0, c, Ignored, f); If we want to keep named arguments, we need to keep the two-layers of expansion we have now. However, if we're okay with dropping named arguments, we can remove the entire first layer of expansion. This would also likely sacrifice error messages, where today we show errors of the form: error: invalid parameters for `has_one` route uri
--> $DIR/typed-uris-bad-params.rs:37:18
|
37 | uri!(has_one(name = 100, age = 50, id = 100, id = 50));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: uri parameters are: id: i32
help: unknown parameters: `name`, `age`
--> $DIR/typed-uris-bad-params.rs:37:18
|
37 | uri!(has_one(name = 100, age = 50, id = 100, id = 50));
| ^^^^ ^^^
help: duplicate parameter: `id`
--> $DIR/typed-uris-bad-params.rs:37:50
|
37 | uri!(has_one(name = 100, age = 50, id = 100, id = 50));
| ^^ And... error: route expects 2 parameters but 1 was supplied
--> $DIR/typed-uris-bad-params.rs:29:18
|
29 | uri!(has_two(10));
| ^^
|
= note: route `has_two` has uri "/<id>?<name>" ...a single level of expansion wouldn't allow us the same diagnostics. |
I ran into a related issue in regards to `uri!`` today and leaving this as a note here after discussion in the rocket chat. Doing This issue was resolved/side-stepped by importing the parent file of the end-point (in my case its Works: Does not work: |
Just tried and the calls works if it is done in the same file as the endpoint. #[get("/health")]
pub fn health() -> &'static str {
println!("{}", uri!(health()));
"ok"
} Works just fine. |
@sedrik In Rocket 0.4 (and I think Rocket 0.3), this same issue affected As far as I can see, the expansion strategy proposed above in #1120 (comment) -- that is a |
I see, if there is no good path to lift the restriction for now maybe the documentation for the old |
Now that
uri!
internally usesmacro_rules!
instead ofmacro
(#964), path resolution works differently. As far as I can tell this is a direct consequence of the fact thatmacro
was hygienic with respect to paths, resolving them at the macro definition site i.e. the "target" route. In contrastmacro_rules!
is not hygienic for item paths (only locals), so paths are resolved in the invocation scope of theuri
macro.As a consequence, code such as this now fails to compile because
PathBuf
is not in scope at theuri!
call:The best possible solution for this issue is to use
macro
once it stabilizes, but that is pretty far off. If it works, we could try fudging someSpan
s in the generatedmacro_rules!
macro. Another solution would be to use structs instead of a macro to encode the route information at compile time, but that is a much more significant rewrite ofuri!
that probably can't be done with the same feature set that is implemented now.The text was updated successfully, but these errors were encountered: