Builder loosing implementation

⚓ Rust    📅 2025-09-29    👤 surdeus    👁️ 12      

surdeus

Warning

This post was published 113 days ago. The information described in this article may have changed.

The 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;
}

Full context

1 post - 1 participant

Read full topic

🏷️ Rust_feed