Skip to content

Commit eceb6cf

Browse files
FollpvostenSergioBenitez
authored andcommitted
Add 'Request::local_cache_async' for use in async request guards.
1 parent b9dd2b0 commit eceb6cf

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed

core/lib/src/request/request.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::sync::{Arc, RwLock, Mutex};
22
use std::net::{IpAddr, SocketAddr};
3+
use std::future::Future;
34
use std::fmt;
45
use std::str;
56

@@ -564,6 +565,39 @@ impl<'r> Request<'r> {
564565
})
565566
}
566567

568+
/// Retrieves the cached value for type `T` from the request-local cached
569+
/// state of `self`. If no such value has previously been cached for this
570+
/// request, `fut` is `await`ed to produce the value which is subsequently
571+
/// returned.
572+
///
573+
/// # Example
574+
///
575+
/// ```rust
576+
/// # use rocket::http::Method;
577+
/// # use rocket::Request;
578+
/// # type User = ();
579+
/// async fn current_user<'r>(request: &Request<'r>) -> User {
580+
/// // Validate request for a given user, load from database, etc.
581+
/// }
582+
///
583+
/// # Request::example(Method::Get, "/uri", |request| rocket::async_test(async {
584+
/// let user = request.local_cache_async(async {
585+
/// current_user(request).await
586+
/// }).await;
587+
/// # }));
588+
pub async fn local_cache_async<'a, T, F>(&'a self, fut: F) -> &'a T
589+
where F: Future<Output = T>,
590+
T: Send + Sync + 'static
591+
{
592+
match self.state.cache.try_get() {
593+
Some(s) => s,
594+
None => {
595+
self.state.cache.set(fut.await);
596+
self.state.cache.get()
597+
}
598+
}
599+
}
600+
567601
/// Retrieves and parses into `T` the 0-indexed `n`th segment from the
568602
/// request. Returns `None` if `n` is greater than the number of segments.
569603
/// Returns `Some(Err(T::Error))` if the parameter type `T` failed to be

examples/request_local_state/src/main.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
use std::sync::atomic::{AtomicUsize, Ordering};
66

7-
use rocket::request::{self, Request, FromRequest, State};
87
use rocket::outcome::Outcome::*;
8+
use rocket::request::{self, FromRequest, FromRequestAsync, FromRequestFuture, Request, State};
99

1010
#[cfg(test)] mod tests;
1111

@@ -17,6 +17,8 @@ struct Atomics {
1717

1818
struct Guard1;
1919
struct Guard2;
20+
struct Guard3;
21+
struct Guard4;
2022

2123
impl<'a, 'r> FromRequest<'a, 'r> for Guard1 {
2224
type Error = ();
@@ -39,15 +41,51 @@ impl<'a, 'r> FromRequest<'a, 'r> for Guard2 {
3941
}
4042
}
4143

42-
#[get("/")]
43-
fn index(_g1: Guard1, _g2: Guard2) {
44+
impl<'a, 'r> FromRequestAsync<'a, 'r> for Guard3 {
45+
type Error = ();
46+
47+
fn from_request<'fut>(req: &'a Request<'r>) -> FromRequestFuture<'fut, Self, ()>
48+
where 'a: 'fut
49+
{
50+
Box::pin(async move {
51+
let atomics = try_outcome!(req.guard::<State<'_, Atomics>>());
52+
atomics.uncached.fetch_add(1, Ordering::Relaxed);
53+
req.local_cache_async(async {
54+
atomics.cached.fetch_add(1, Ordering::Relaxed)
55+
}).await;
56+
57+
Success(Guard3)
58+
})
59+
}
60+
}
61+
62+
impl<'a, 'r> FromRequestAsync<'a, 'r> for Guard4 {
63+
type Error = ();
64+
65+
fn from_request<'fut>(req: &'a Request<'r>) -> FromRequestFuture<'fut, Self, ()>
66+
where 'a: 'fut
67+
{
68+
Box::pin(async move {
69+
try_outcome!(Guard3::from_request(req).await);
70+
Success(Guard4)
71+
})
72+
}
73+
}
74+
75+
#[get("/sync")]
76+
fn r_sync(_g1: Guard1, _g2: Guard2) {
77+
// This exists only to run the request guards.
78+
}
79+
80+
#[get("/async")]
81+
async fn r_async(_g1: Guard3, _g2: Guard4) {
4482
// This exists only to run the request guards.
4583
}
4684

4785
fn rocket() -> rocket::Rocket {
4886
rocket::ignite()
4987
.manage(Atomics::default())
50-
.mount("/", routes!(index))
88+
.mount("/", routes![r_sync, r_async])
5189
}
5290

5391
fn main() {

examples/request_local_state/src/tests.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ use rocket::local::Client;
66
#[rocket::async_test]
77
async fn test() {
88
let client = Client::new(rocket()).unwrap();
9-
client.get("/").dispatch().await;
9+
client.get("/sync").dispatch().await;
1010

1111
let atomics = client.rocket().state::<Atomics>().unwrap();
1212
assert_eq!(atomics.uncached.load(Ordering::Relaxed), 2);
1313
assert_eq!(atomics.cached.load(Ordering::Relaxed), 1);
14+
15+
client.get("/async").dispatch().await;
16+
17+
let atomics = client.rocket().state::<Atomics>().unwrap();
18+
assert_eq!(atomics.uncached.load(Ordering::Relaxed), 4);
19+
assert_eq!(atomics.cached.load(Ordering::Relaxed), 2);
1420
}

0 commit comments

Comments
 (0)