Skip to content

Commit 935498f

Browse files
authored
Merge pull request #397 from tirr-c/more-generic-endpoint
Make Endpoint::call generic over lifetime
2 parents b429110 + cd975d8 commit 935498f

File tree

9 files changed

+40
-65
lines changed

9 files changed

+40
-65
lines changed

examples/json.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ fn main() -> io::Result<()> {
1111
task::block_on(async {
1212
let mut app = tide::new();
1313

14-
app.at("/submit").post(|mut req: tide::Request<()>| {
15-
async move {
14+
app.at("/submit")
15+
.post(|mut req: tide::Request<()>| async move {
1616
let cat: Cat = req.body_json().await.unwrap();
1717
println!("cat name: {}", cat.name);
1818

1919
let cat = Cat {
2020
name: "chashu".into(),
2121
};
2222
tide::Response::new(200).body_json(&cat).unwrap()
23-
}
24-
});
23+
});
2524

2625
app.listen("127.0.0.1:8080").await?;
2726
Ok(())

src/endpoint.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,24 +46,19 @@ use crate::{response::IntoResponse, Request, Response};
4646
///
4747
/// Tide routes will also accept endpoints with `Fn` signatures of this form, but using the `async` keyword has better ergonomics.
4848
pub trait Endpoint<State>: Send + Sync + 'static {
49-
/// The async result of `call`.
50-
type Fut: Future<Output = Response> + Send + 'static;
51-
5249
/// Invoke the endpoint within the given context
53-
fn call(&self, req: Request<State>) -> Self::Fut;
50+
fn call<'a>(&'a self, req: Request<State>) -> BoxFuture<'a, Response>;
5451
}
5552

56-
pub(crate) type DynEndpoint<State> =
57-
dyn (Fn(Request<State>) -> BoxFuture<'static, Response>) + 'static + Send + Sync;
53+
pub(crate) type DynEndpoint<State> = dyn Endpoint<State>;
5854

5955
impl<State, F: Send + Sync + 'static, Fut> Endpoint<State> for F
6056
where
6157
F: Fn(Request<State>) -> Fut,
6258
Fut: Future + Send + 'static,
6359
Fut::Output: IntoResponse,
6460
{
65-
type Fut = BoxFuture<'static, Response>;
66-
fn call(&self, req: Request<State>) -> Self::Fut {
61+
fn call<'a>(&'a self, req: Request<State>) -> BoxFuture<'a, Response> {
6762
let fut = (self)(req);
6863
Box::pin(async move { fut.await.into_response() })
6964
}

src/middleware/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<'a, State: 'static> Next<'a, State> {
5252
self.next_middleware = next;
5353
current.handle(req, self)
5454
} else {
55-
(self.endpoint)(req)
55+
self.endpoint.call(req)
5656
}
5757
}
5858
}

src/redirect.rs

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
use async_std::future;
2-
use async_std::task::{Context, Poll};
3-
4-
use std::pin::Pin;
5-
1+
use crate::utils::BoxFuture;
62
use crate::{Endpoint, Request, Response};
73

84
/// Redirect a route to another route.
@@ -21,7 +17,7 @@ use crate::{Endpoint, Request, Response};
2117
/// app.listen("127.0.0.1:8080").await?;
2218
/// #
2319
/// # Ok(()) }) }
24-
/// ````
20+
/// ```
2521
pub fn redirect<State>(location: impl AsRef<str>) -> impl Endpoint<State> {
2622
let location = location.as_ref().to_owned();
2723
Redirect { location }
@@ -33,22 +29,8 @@ pub struct Redirect {
3329
}
3430

3531
impl<State> Endpoint<State> for Redirect {
36-
type Fut = Future;
37-
38-
fn call(&self, _req: Request<State>) -> Self::Fut {
32+
fn call<'a>(&'a self, _req: Request<State>) -> BoxFuture<'a, Response> {
3933
let res = Response::new(307).set_header("Location", &self.location);
40-
Future { res: Some(res) }
41-
}
42-
}
43-
44-
/// Future returned from `redirect`.
45-
pub struct Future {
46-
res: Option<Response>,
47-
}
48-
49-
impl future::Future for Future {
50-
type Output = Response;
51-
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
52-
Poll::Ready(self.res.take().unwrap())
34+
Box::pin(async move { res })
5335
}
5436
}

src/router.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,11 @@ impl<State: 'static> Router<State> {
3333
self.method_map
3434
.entry(method)
3535
.or_insert_with(MethodRouter::new)
36-
.add(path, Box::new(move |cx| Box::pin(ep.call(cx))))
36+
.add(path, Box::new(ep))
3737
}
3838

3939
pub(crate) fn add_all(&mut self, path: &str, ep: impl Endpoint<State>) {
40-
self.all_method_router
41-
.add(path, Box::new(move |cx| Box::pin(ep.call(cx))))
40+
self.all_method_router.add(path, Box::new(ep))
4241
}
4342

4443
pub(crate) fn route(&self, path: &str, method: http::Method) -> Selection<'_, State> {

src/server/mod.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,14 +321,23 @@ impl<State: Send + Sync + 'static> Server<State> {
321321
///
322322
/// This type is useful only in conjunction with the [`HttpService`] trait,
323323
/// i.e. for hosting a Tide app within some custom HTTP server.
324-
#[derive(Clone)]
325324
#[allow(missing_debug_implementations)]
326325
pub struct Service<State> {
327326
router: Arc<Router<State>>,
328327
state: Arc<State>,
329328
middleware: Arc<Vec<Arc<dyn Middleware<State>>>>,
330329
}
331330

331+
impl<State> Clone for Service<State> {
332+
fn clone(&self) -> Self {
333+
Self {
334+
router: self.router.clone(),
335+
state: self.state.clone(),
336+
middleware: self.middleware.clone(),
337+
}
338+
}
339+
}
340+
332341
#[derive(Debug)]
333342
pub struct ReadyFuture;
334343

@@ -351,17 +360,15 @@ impl<State: Sync + Send + 'static> HttpService for Service<State> {
351360

352361
fn respond(&self, _conn: &mut (), req: http_service::Request) -> Self::ResponseFuture {
353362
let req = Request::new(self.state.clone(), req, Vec::new());
354-
let fut = self.call(req);
355-
Box::pin(async move { Ok(fut.await.into()) })
363+
let service = self.clone();
364+
Box::pin(async move { Ok(service.call(req).await.into()) })
356365
}
357366
}
358367

359368
impl<State: Sync + Send + 'static, InnerState: Sync + Send + 'static> Endpoint<State>
360369
for Service<InnerState>
361370
{
362-
type Fut = BoxFuture<'static, Response>;
363-
364-
fn call(&self, req: Request<State>) -> Self::Fut {
371+
fn call<'a>(&'a self, req: Request<State>) -> BoxFuture<'a, Response> {
365372
let Request {
366373
request: req,
367374
mut route_params,

src/server/route.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::{router::Router, Endpoint};
1+
use crate::utils::BoxFuture;
2+
use crate::{router::Router, Endpoint, Response};
23

34
/// A handle to a route.
45
///
@@ -172,9 +173,7 @@ impl<E> Clone for StripPrefixEndpoint<E> {
172173
}
173174

174175
impl<State, E: Endpoint<State>> Endpoint<State> for StripPrefixEndpoint<E> {
175-
type Fut = E::Fut;
176-
177-
fn call(&self, mut req: crate::Request<State>) -> Self::Fut {
176+
fn call<'a>(&'a self, mut req: crate::Request<State>) -> BoxFuture<'a, Response> {
178177
let rest = req.rest().unwrap_or("");
179178
let mut path_and_query = format!("/{}", rest);
180179
let uri = req.uri();

tests/nested.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,9 @@ fn nested_middleware() {
9393
fn nested_with_different_state() {
9494
let mut outer = tide::new();
9595
let mut inner = tide::with_state(42);
96-
inner.at("/").get(|req: tide::Request<i32>| {
97-
async move {
98-
let num = req.state();
99-
format!("the number is {}", num)
100-
}
96+
inner.at("/").get(|req: tide::Request<i32>| async move {
97+
let num = req.state();
98+
format!("the number is {}", num)
10199
});
102100
outer.at("/").get(|_| async move { "Hello, world!" });
103101
outer.at("/foo").nest(inner);

tests/server.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ fn hello_world() -> Result<(), surf::Exception> {
99
task::block_on(async {
1010
let server = task::spawn(async {
1111
let mut app = tide::new();
12-
app.at("/").get(|mut req: tide::Request<()>| {
13-
async move {
14-
assert_eq!(req.body_string().await.unwrap(), "nori".to_string());
15-
tide::Response::new(200).body_string("says hello".to_string())
16-
}
12+
app.at("/").get(|mut req: tide::Request<()>| async move {
13+
assert_eq!(req.body_string().await.unwrap(), "nori".to_string());
14+
tide::Response::new(200).body_string("says hello".to_string())
1715
});
1816
app.listen("localhost:8080").await?;
1917
Result::<(), surf::Exception>::Ok(())
@@ -67,13 +65,11 @@ fn json() -> Result<(), surf::Exception> {
6765
task::block_on(async {
6866
let server = task::spawn(async {
6967
let mut app = tide::new();
70-
app.at("/").get(|mut req: tide::Request<()>| {
71-
async move {
72-
let mut counter: Counter = req.body_json().await.unwrap();
73-
assert_eq!(counter.count, 0);
74-
counter.count = 1;
75-
tide::Response::new(200).body_json(&counter).unwrap()
76-
}
68+
app.at("/").get(|mut req: tide::Request<()>| async move {
69+
let mut counter: Counter = req.body_json().await.unwrap();
70+
assert_eq!(counter.count, 0);
71+
counter.count = 1;
72+
tide::Response::new(200).body_json(&counter).unwrap()
7773
});
7874
app.listen("localhost:8082").await?;
7975
Result::<(), surf::Exception>::Ok(())

0 commit comments

Comments
 (0)