Skip to content

Commit d894439

Browse files
authoredMay 15, 2023
feat(service): change Service::call to take &self (#3223)
change Service::call to take &self instead of &mut self. Because of this change, the trait bound in the service::util::service_fn and the trait bound in the impl for the ServiceFn struct were changed from FnMut to Fn. This change was decided on for the following reasons: - It prepares the way for async fn, since then the future only borrows &self, and thus a Service can concurrently handle multiple outstanding requests at once. - It's clearer that Services can likely be cloned - To share state across clones you generally need Arc<Mutex<_>> that means you're not really using the &mut self and could do with a &self Closes #3040 BREAKING CHANGE: The Service::call function no longer takes a mutable reference to self. The FnMut trait bound on the service::util::service_fn function and the trait bound on the impl for the ServiceFn struct were changed from FnMut to Fn.
1 parent ea0f0e3 commit d894439

File tree

4 files changed

+24
-10
lines changed

4 files changed

+24
-10
lines changed
 

‎examples/service_struct_impl.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use tokio::net::TcpListener;
88
use std::future::Future;
99
use std::net::SocketAddr;
1010
use std::pin::Pin;
11+
use std::sync::Mutex;
1112

1213
type Counter = i32;
1314

@@ -23,7 +24,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
2324

2425
tokio::task::spawn(async move {
2526
if let Err(err) = http1::Builder::new()
26-
.serve_connection(stream, Svc { counter: 81818 })
27+
.serve_connection(
28+
stream,
29+
Svc {
30+
counter: Mutex::new(81818),
31+
},
32+
)
2733
.await
2834
{
2935
println!("Failed to serve connection: {:?}", err);
@@ -33,15 +39,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
3339
}
3440

3541
struct Svc {
36-
counter: Counter,
42+
counter: Mutex<Counter>,
3743
}
3844

3945
impl Service<Request<IncomingBody>> for Svc {
4046
type Response = Response<Full<Bytes>>;
4147
type Error = hyper::Error;
4248
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
4349

44-
fn call(&mut self, req: Request<IncomingBody>) -> Self::Future {
50+
fn call(&self, req: Request<IncomingBody>) -> Self::Future {
4551
fn mk_response(s: String) -> Result<Response<Full<Bytes>>, hyper::Error> {
4652
Ok(Response::builder().body(Full::new(Bytes::from(s))).unwrap())
4753
}
@@ -58,7 +64,7 @@ impl Service<Request<IncomingBody>> for Svc {
5864
};
5965

6066
if req.uri().path() != "/favicon.ico" {
61-
self.counter += 1;
67+
*self.counter.lock().expect("lock poisoned") += 1;
6268
}
6369

6470
Box::pin(async { res })

‎src/service/service.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,13 @@ pub trait Service<Request> {
2828
type Future: Future<Output = Result<Self::Response, Self::Error>>;
2929

3030
/// Process the request and return the response asynchronously.
31-
fn call(&mut self, req: Request) -> Self::Future;
31+
/// call takes a &self instead of a mut &self because:
32+
/// - It prepares the way for async fn,
33+
/// since then the future only borrows &self, and thus a Service can concurrently handle
34+
/// multiple outstanding requests at once.
35+
/// - It's clearer that Services can likely be cloned
36+
/// - To share state across clones you generally need Arc<Mutex<_>>
37+
/// that means you're not really using the &mut self and could do with a &self
38+
/// To see the discussion on this see: https://github.com/hyperium/hyper/issues/3040
39+
fn call(&self, req: Request) -> Self::Future;
3240
}

‎src/service/util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{Request, Response};
2929
/// ```
3030
pub fn service_fn<F, R, S>(f: F) -> ServiceFn<F, R>
3131
where
32-
F: FnMut(Request<R>) -> S,
32+
F: Fn(Request<R>) -> S,
3333
S: Future,
3434
{
3535
ServiceFn {
@@ -46,7 +46,7 @@ pub struct ServiceFn<F, R> {
4646

4747
impl<F, ReqBody, Ret, ResBody, E> Service<Request<ReqBody>> for ServiceFn<F, ReqBody>
4848
where
49-
F: FnMut(Request<ReqBody>) -> Ret,
49+
F: Fn(Request<ReqBody>) -> Ret,
5050
ReqBody: Body,
5151
Ret: Future<Output = Result<Response<ResBody>, E>>,
5252
E: Into<Box<dyn StdError + Send + Sync>>,
@@ -56,7 +56,7 @@ where
5656
type Error = E;
5757
type Future = Ret;
5858

59-
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
59+
fn call(&self, req: Request<ReqBody>) -> Self::Future {
6060
(self.f)(req)
6161
}
6262
}

‎tests/server.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2656,7 +2656,7 @@ impl Service<Request<IncomingBody>> for TestService {
26562656
type Error = BoxError;
26572657
type Future = BoxFuture;
26582658

2659-
fn call(&mut self, mut req: Request<IncomingBody>) -> Self::Future {
2659+
fn call(&self, mut req: Request<IncomingBody>) -> Self::Future {
26602660
let tx = self.tx.clone();
26612661
let replies = self.reply.clone();
26622662

@@ -2722,7 +2722,7 @@ impl Service<Request<IncomingBody>> for HelloWorld {
27222722
type Error = hyper::Error;
27232723
type Future = future::Ready<Result<Self::Response, Self::Error>>;
27242724

2725-
fn call(&mut self, _req: Request<IncomingBody>) -> Self::Future {
2725+
fn call(&self, _req: Request<IncomingBody>) -> Self::Future {
27262726
let response = Response::new(Full::new(HELLO.into()));
27272727
future::ok(response)
27282728
}

0 commit comments

Comments
 (0)
Please sign in to comment.