Builder loosing implementation
⚓ Rust 📅 2025-09-29 👤 surdeus 👁️ 12The problem
When I use .predicate() with a closure, RequireBuilder loses its build implementation.
It works fine with structs that implement PredicateAsync, but not with a closure or a function.
.fallback(), which is quite similar, works fine.
Generics Pr2 and Pr require the same implementations, so I dunno why would it loose its implementation.
here is this error quickly recreated in Rust Playground by a GPT.
let f = |backend, user, state| verify_permissions(backend, user, state);
let require_login = Require::<TestBackend, TestState>::builder_with_state(state.clone())
.fallback(RedirectFallback::new().login_url("/login"))
.predicate(f)
.build();
compilation error:
error[E0599]: no method named `build` found for struct `RequireBuilder<TestBackend, TestState, Body, ..., ..., ...>` in the current scope
--> axum-login/src/require/builder/tests.rs:796:14
|
792 | let require_login = Require::<TestBackend, TestState>::builder_with_state(state.clone())
| _____________________________-
793 | | .fallback(RedirectFallback::new().login_url("/login"))
794 | | .restrict(|_| async { StatusCode::UNAUTHORIZED.into_response() })
795 | | .predicate(f)
796 | | .build();
| | -^^^^^ method not found in `RequireBuilder<TestBackend, TestState, Body, ..., ..., ...>`
| |_____________|
|
|
::: axum-login/src/require/builder/mod.rs:29:1
|
29 | / pub struct RequireBuilder<
30 | | B,
31 | | ST = (),
32 | | T = Body,
... |
35 | | Pr = DefaultPredicate<B, ST>,
36 | | > {
| |_- method `build` not found for this struct
|
= note: the method was found for
- `RequireBuilder<B, ST, T, Fb, Rs, Pr>`
RequireBuilder implementation
impl<B, ST, T> RequireBuilder<B, ST, T, DefaultFallback, DefaultRestrict, DefaultPredicate<B, ST>>
where
DefaultPredicate<B, ST>: PredicateAsync<B, ST>,
B: AuthnBackend,
ST: std::marker::Send + std::marker::Sync + std::clone::Clone,
T: 'static + Send,
{
/// Creates a new `RequireBuilder` with a set state.
pub fn new_with_state(state: ST) -> Self {
Self {
predicate: DefaultPredicate {
_backend: PhantomData,
_state: PhantomData,
},
restrict: DefaultRestrict,
fallback: DefaultFallback,
state,
_backend: PhantomData,
_body: PhantomData,
}
}
}
impl<B, ST, T, Fb, Rs, Pr> RequireBuilder<B, ST, T, Fb, Rs, Pr>
where
B: AuthnBackend,
T: 'static + Send,
ST: Clone + std::marker::Send,
Fb: AsyncFallbackHandler<T> + std::marker::Send + std::marker::Sync,
Rs: AsyncFallbackHandler<T> + std::marker::Send + std::marker::Sync,
Pr: PredicateAsync<B, ST> + std::marker::Send + std::marker::Sync,
{
pub fn predicate<Pr2>(self, new_predicate: Pr2) -> RequireBuilder<B, ST, T, Fb, Rs, Pr2>
where
Pr2: PredicateAsync<B, ST> + std::marker::Send + std::marker::Sync,
{
RequireBuilder {
predicate: new_predicate,
restrict: self.restrict,
fallback: self.fallback,
state: self.state,
_backend: PhantomData,
_body: PhantomData,
}
}
pub fn fallback<Fb2>(self, new_fallback: Fb2) -> RequireBuilder<B, ST, T, Fb2, Rs, Pr>
where
Fb2: AsyncFallbackHandler<T> + std::marker::Send + std::marker::Sync,
{
RequireBuilder {
predicate: self.predicate,
restrict: self.restrict,
fallback: new_fallback,
state: self.state,
_backend: PhantomData,
_body: PhantomData,
}
}
PredicateAsync implementation
impl<F, Fut, B, ST> PredicateAsync<B, ST> for F
where
F: Fn(&B, &<B as AuthnBackend>::User, &ST) -> Fut,
Fut: Future<Output = bool>,
B: AuthnBackend + AuthzBackend + 'static,
B::User: 'static,
B::Permission: Clone + Debug,
ST: Clone + Send + Sync + 'static,
{
type Future = Fut;
fn predicate(
& self,
backend: &B,
user: &<B as AuthnBackend>::User,
state: &ST,
) -> Self::Future {
(self)(backend, user, state)
}
}
pub trait PredicateAsync<B: AuthnBackend, ST = ()> {
type Future: Future<Output = bool>;
fn predicate(
& self,
backend: &B,
user: &<B as AuthnBackend>::User,
state: &ST,
) -> Self::Future;
}
1 post - 1 participant
🏷️ Rust_feed