Open djrenren opened 1 year ago
This issue also only occurs if you use the generic as the type in the function argument list.
This appears to be the culprit, at least indirectly. Since it's the only thing that discriminates based on being a generic. https://github.com/juhaku/utoipa/blob/489ddd663051a578e9285f5f4b5d87c0f626d6c0/utoipa-gen/src/ext/rocket.rs#L134-L136
My guess is that we've run afoul of some basic heuristic breaking down. Like "If it's a generic, then it's a Rocket guard and not an actual parameter"
Yeah, I think there is no "quick" fix for this. At the moment the IntoParams
does not support generics and it was never meant to support them though. This might not be ideal for some, but surely keeps things bit simplier.
Then why there is no generics support on IntoParams
, one might ask. Simple answer to this is that they are a bit problematic in utoipa. Most likely longer explanations can be found from issue threads related to the generics in ToSchema
derive macro. The idealogy is the same, with generics there is no way to know the actual type at the compile time, unless it is told the possible "variants". This is how the #[aliases(...)]
comes into picutre with ToSchema
generics and if generic support was to be implemented for IntoParams
it needed the same #[aliases(...)]
support as well.
This issue is not only limited to the rocket but it also exists from the beginning of IntoParams
support in general.
So far the only cure is to implement IntoParams
in these cases manually leveraging schema!(...)
macro and PartialSchema
trait.
Hey @juhaku thanks for taking the time to respond. I think there may be some confusion, either on your end or mine.
The issue I'm having has nothing to do with the IntoParams
#[derive]
macro. In the example above, IntoParams
is indeed implemented manually. The issue is the codegen from #[path]
. And you can confirm that this issue only occurs with rocket_extras
because the following equivalent definition successfully compiles:
#[utoipa::path(get, path="/{foo}",
params(
Foo::<Opaque>,
Foo::<i32>,
),
)]
pub async fn example(foo: Foo<Opaque>) -> String {
"hi".into()
}
Using generic concrete instantiations for IntoParams
in the #[path]
macro should be fine because the type name isn't used anywhere.
Aah, okay, that might be my bad.
There probably is some room to improve this in rocket but the rocket support is not super straight forward. I am beginning to remeber what this is all about.
The thing in rocket is that path and query args are all "unwrapped". They are not being wrapped to another container type such as Path<T>
or Query<T>
like in other framework namely actix_web and axum. This just adds to the difficulty to distinct the IntoParams
type from the other args.
My guess is that we've run afoul of some basic heuristic breaking down. Like "If it's a generic, then it's a Rocket guard and not an actual parameter"
As you stated earlier, you are absolutely right.
The logic used to determine the parameters might just need revising. Yet this is not simple, as the big open question lies in front of us that how to distinct the parameters from rocket guards just based on the argument name or type name? There is no compile time evaluation of what traits are being implemented for the arguments based on tokens only.
I'm not entirely sure exactly why this happens but here's a minimal repro:
and the error message:
If we expand the macro using rust-analyzer we get the following expansion:
Notably the problem occurs here:
Where no closure is passed to
into_params
.This issue only occurs when the
params
tuple contains a repeat of the same generic type (in this caseFoo
). You may ask why you would want to do this, but we have an impl block that looks like:Where each possible T produces a different set of params.
This issue also only occurs when integrating with rocket. This problem dates back to at least utopia 3.1.0 and rocket 5.0.rc2 but it repros on utopia 3.3.0 and rocket 5.0.rc3.