diff --git a/src/server.rs b/src/server.rs index 87923b2..20164d9 100644 --- a/src/server.rs +++ b/src/server.rs @@ -97,7 +97,32 @@ impl ConnectionInfo { /// .serve(MyService { count: Mutex::new(0) }) /// .expect("failed to start server"); /// ``` -pub trait Service: Send + Sync + 'static { +/// +/// If your service is already cheaply cloneable, you can instead use `serve_clone` and avoid an extra `Arc` wrapper: +/// +/// ```no_run +/// use astra::{Request, Response, Server, Service, Body, ConnectionInfo}; +/// use std::sync::{Arc, Mutex}; +/// +/// #[derive(Clone)] +/// struct MyService { +/// count: Arc>, +/// } +/// +/// impl Service for MyService { +/// fn call(&self, request: Request, _info: ConnectionInfo) -> Response { +/// let mut count = self.count.lock().unwrap(); +/// *count += 1; +/// println!("request #{}", *count); +/// Response::new(Body::new("Hello world")) +/// } +/// } +/// +/// Server::bind("localhost:3000") +/// .serve_clone(MyService { count: Arc::new(Mutex::new(0)) }) +/// .expect("failed to start server"); +/// ``` +pub trait Service: Send + 'static { fn call(&self, request: Request, info: ConnectionInfo) -> Response; } @@ -110,6 +135,15 @@ where } } +impl Service for Arc +where + S: Service + Sync, +{ + fn call(&self, request: Request, info: ConnectionInfo) -> Response { + (**self).call(request, info) + } +} + impl Server { /// Binds a server to the provided address. /// @@ -147,13 +181,21 @@ impl Server { /// ``` pub fn serve(self, service: S) -> io::Result<()> where - S: Service, + S: Service + Sync, + { + self.serve_clone(Arc::new(service)) + } + + /// Like [`Self::serve`] but does not wrap `service` in an `Arc` and expects it to + /// implement `Clone` and `Sync` internally. + pub fn serve_clone(self, service: S) -> io::Result<()> + where + S: Service + Clone, { let executor = executor::Executor::new(self.max_workers, self.worker_keep_alive); let mut http = Http::new().with_executor(executor.clone()); self.configure(&mut http); - let service = Arc::new(service); let reactor = Reactor::new().expect("failed to create reactor"); for conn in self.listener.unwrap().incoming() { @@ -443,11 +485,12 @@ mod service { type HyperRequest = hyper::Request; - pub struct HyperService(pub Arc, pub ConnectionInfo); + pub struct HyperService(pub S, pub ConnectionInfo); impl hyper::service::Service for HyperService where - S: Service, + S: Service + Clone, + // ::Target: Unpin, { type Response = Response; type Error = Infallible; @@ -462,7 +505,9 @@ mod service { } } - pub struct Lazy(Arc, Option, ConnectionInfo); + pub struct Lazy(S, Option, ConnectionInfo); + + impl Unpin for Lazy {} impl Future for Lazy where