1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use AppError;
/// Implemented by an app's `User` model (or whatever it calls its
/// authenticatable type) so `larust_support::auth`'s guard functions and
/// the [`crate::Auth`] extractor can look a user up from the id stored in
/// the session.
///
/// `find_for_auth`'s signature deliberately matches what `#[derive(Model)]`
/// already generates (`Self::find(id: i64) -> Result<Option<Self>,
/// AppError>` - see `larust-macros`' `model.rs`), so a typical impl is a
/// two-line delegation:
///
/// ```ignore
/// impl larust_support::auth::Authenticatable for User {
/// fn auth_id(&self) -> i64 { self.id }
/// async fn find_for_auth(id: i64) -> Result<Option<Self>, AppError> {
/// Self::find(id).await
/// }
/// }
/// ```
///
/// Declared as `-> impl Future<...> + Send` rather than a plain `async fn` -
/// native async-fn-in-traits doesn't propagate auto-trait bounds on the
/// returned future by default, and the [`crate::Auth`] extractor's
/// `FromRequestParts` impl (itself required to return a `Send` future by
/// axum-core's own `#[async_trait]` declaration - see GOTCHAS.md) calls
/// this through an `async` block that needs to stay `Send`. This doesn't
/// change how an implementation looks: implementing this method with a
/// plain `async fn find_for_auth(id: i64) -> Result<Option<Self>, AppError>
/// { Self::find(id).await }` still works, since `async fn`'s desugared
/// return type already satisfies `-> impl Future<...>` - only the trait's
/// own declaration needs the explicit spelling.
///
/// The two-line delegation above is the easy path for a `#[derive(Model)]`
/// (SQL-family) app, but it isn't the only path - this trait has zero
/// dependency on `#[derive(Model)]`, `larust-orm`, or SQL of any kind, so a
/// user model backed by something else entirely (a document store like
/// Firestore, an in-memory cache, a call to another service) implements it
/// exactly the same way, just with a different lookup body:
///
/// ```ignore
/// impl larust_support::auth::Authenticatable for User {
/// fn auth_id(&self) -> i64 { self.id }
/// async fn find_for_auth(id: i64) -> Result<Option<Self>, AppError> {
/// // No `#[derive(Model)]` involved - e.g. a hand-written lookup
/// // against a `larust_support::repository::Repository` impl, or
/// // any other store this type knows how to query:
/// MY_USER_REPOSITORY.find(id).await
/// }
/// }
/// ```