From ea419e29432cd8614a8efcf8a603e832342df44b Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Fri, 22 Nov 2024 14:48:48 +0100 Subject: [PATCH 1/2] feat: Implement IntoResponse for alloc::string::String So no_std+alloc can use the normal strings. --- src/response.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/response.rs b/src/response.rs index 2078dbf..5db1321 100644 --- a/src/response.rs +++ b/src/response.rs @@ -625,8 +625,8 @@ impl IntoResponse for heapless::String { } } -#[cfg(feature = "std")] -impl IntoResponse for std::string::String { +#[cfg(feature = "alloc")] +impl IntoResponse for alloc::string::String { async fn write_to>( self, connection: Connection<'_, R>, From a22baab82005430edacc31d1d5c20b5b1003ac52 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Sun, 24 Nov 2024 18:24:46 +0100 Subject: [PATCH 2/2] Add PUT and DELETE --- examples/hello_world/src/main.rs | 11 +- src/routing.rs | 255 +++++++++++++++++++++++++++++-- 2 files changed, 250 insertions(+), 16 deletions(-) diff --git a/examples/hello_world/src/main.rs b/examples/hello_world/src/main.rs index adb7739..82236cc 100644 --- a/examples/hello_world/src/main.rs +++ b/examples/hello_world/src/main.rs @@ -6,8 +6,15 @@ use picoserve::routing::get; async fn main() -> anyhow::Result<()> { let port = 8000; - let app = - std::rc::Rc::new(picoserve::Router::new().route("/", get(|| async { "Hello World" }))); + let app = std::rc::Rc::new( + picoserve::Router::new().route( + "/", + get(|| async { "Hello World" }) + .post(|| async { "Hello post" }) + .put(|| async { "Hello put" }) + .delete(|| async { "Hello delete" }), + ), + ); let config = picoserve::Config::new(picoserve::Timeouts { start_read_request: Some(Duration::from_secs(5)), diff --git a/src/routing.rs b/src/routing.rs index 7ac70c4..ab8dee6 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -438,54 +438,157 @@ pub trait MethodHandler: Sealed { /// A [MethodHandler] which routes requests to the appropriate [RequestHandler] based on the method. /// /// Automatically handled the `HEAD` method by calling the `GET` handler and returning an empty body. -pub struct MethodRouter { +pub struct MethodRouter { get: GET, post: POST, + put: PUT, + delete: DELETE, } -impl Sealed for MethodRouter {} +impl Sealed for MethodRouter {} /// Route `GET` requests to the given [handler](RequestHandlerFunction). pub fn get>( handler: Handler, -) -> MethodRouter, MethodNotAllowed> { +) -> MethodRouter< + impl RequestHandler, + MethodNotAllowed, + MethodNotAllowed, + MethodNotAllowed, +> { MethodRouter { get: HandlerFunctionRequestHandler::new(handler), post: MethodNotAllowed, + put: MethodNotAllowed, + delete: MethodNotAllowed, } } /// Route `GET` requests to the given [service](RequestHandlerService). pub fn get_service( service: impl RequestHandlerService, -) -> MethodRouter, MethodNotAllowed> { +) -> MethodRouter< + impl RequestHandler, + MethodNotAllowed, + MethodNotAllowed, + MethodNotAllowed, +> { MethodRouter { get: RequestHandlerServiceRequestHandler { service }, post: MethodNotAllowed, + put: MethodNotAllowed, + delete: MethodNotAllowed, } } /// Route `POST` requests to the given [handler](RequestHandlerFunction). pub fn post>( handler: Handler, -) -> MethodRouter> { +) -> MethodRouter< + MethodNotAllowed, + impl RequestHandler, + MethodNotAllowed, + MethodNotAllowed, +> { MethodRouter { get: MethodNotAllowed, post: HandlerFunctionRequestHandler::new(handler), + put: MethodNotAllowed, + delete: MethodNotAllowed, } } /// Route `POST` requests to the given [service](RequestHandlerService). pub fn post_service( service: impl RequestHandlerService, -) -> MethodRouter> { +) -> MethodRouter< + MethodNotAllowed, + impl RequestHandler, + MethodNotAllowed, + MethodNotAllowed, +> { MethodRouter { get: MethodNotAllowed, post: RequestHandlerServiceRequestHandler { service }, + put: MethodNotAllowed, + delete: MethodNotAllowed, } } -impl MethodRouter { +/// Route `PUT` requests to the given [handler](RequestHandlerFunction). +pub fn put>( + handler: Handler, +) -> MethodRouter< + MethodNotAllowed, + MethodNotAllowed, + impl RequestHandler, + MethodNotAllowed, +> { + MethodRouter { + get: MethodNotAllowed, + post: MethodNotAllowed, + put: HandlerFunctionRequestHandler::new(handler), + delete: MethodNotAllowed, + } +} + +/// Route `PUT` requests to the given [service](RequestHandlerService). +pub fn put_service( + service: impl RequestHandlerService, +) -> MethodRouter< + MethodNotAllowed, + MethodNotAllowed, + impl RequestHandler, + MethodNotAllowed, +> { + MethodRouter { + get: MethodNotAllowed, + post: MethodNotAllowed, + put: RequestHandlerServiceRequestHandler { service }, + delete: MethodNotAllowed, + } +} + +/// Route `DELETE` requests to the given [handler](RequestHandlerFunction). +pub fn delete< + State, + PathParameters, + T, + Handler: RequestHandlerFunction, +>( + handler: Handler, +) -> MethodRouter< + MethodNotAllowed, + MethodNotAllowed, + MethodNotAllowed, + impl RequestHandler, +> { + MethodRouter { + get: MethodNotAllowed, + post: MethodNotAllowed, + put: MethodNotAllowed, + delete: HandlerFunctionRequestHandler::new(handler), + } +} + +/// Route `DELETE` requests to the given [service](RequestHandlerService). +pub fn delete_service( + service: impl RequestHandlerService, +) -> MethodRouter< + MethodNotAllowed, + MethodNotAllowed, + MethodNotAllowed, + impl RequestHandler, +> { + MethodRouter { + get: MethodNotAllowed, + post: MethodNotAllowed, + put: MethodNotAllowed, + delete: RequestHandlerServiceRequestHandler { service }, + } +} + +impl MethodRouter { /// Chain an additional [handler](RequestHandlerFunction) that will only accept `GET` requests. pub fn get< State, @@ -495,15 +598,19 @@ impl MethodRouter { >( self, handler: Handler, - ) -> MethodRouter, POST> { + ) -> MethodRouter, POST, PUT, DELETE> { let MethodRouter { get: MethodNotAllowed, post, + put, + delete, } = self; MethodRouter { get: HandlerFunctionRequestHandler::new(handler), post, + put, + delete, } } @@ -511,20 +618,24 @@ impl MethodRouter { pub fn get_service( self, service: impl RequestHandlerService, - ) -> MethodRouter, POST> { + ) -> MethodRouter, POST, PUT, DELETE> { let MethodRouter { get: MethodNotAllowed, post, + put, + delete, } = self; MethodRouter { get: RequestHandlerServiceRequestHandler { service }, post, + put, + delete, } } } -impl MethodRouter { +impl MethodRouter { /// Chain an additional [handler](RequestHandlerFunction) that will only accept `POST` requests. pub fn post< State, @@ -534,15 +645,19 @@ impl MethodRouter { >( self, handler: Handler, - ) -> MethodRouter> { + ) -> MethodRouter, PUT, DELETE> { let MethodRouter { get, post: MethodNotAllowed, + put, + delete, } = self; MethodRouter { get, post: HandlerFunctionRequestHandler::new(handler), + put, + delete, } } @@ -550,20 +665,118 @@ impl MethodRouter { pub fn post_service( self, service: impl RequestHandlerService, - ) -> MethodRouter> { + ) -> MethodRouter, PUT, DELETE> { let MethodRouter { get, post: MethodNotAllowed, + put, + delete, } = self; MethodRouter { get, post: RequestHandlerServiceRequestHandler { service }, + put, + delete, + } + } +} + +impl MethodRouter { + /// Chain an additional [handler](RequestHandlerFunction) that will only accept `PUT` requests. + pub fn put< + State, + PathParameters, + T, + Handler: RequestHandlerFunction, + >( + self, + handler: Handler, + ) -> MethodRouter, DELETE> { + let MethodRouter { + get, + post, + put: MethodNotAllowed, + delete, + } = self; + + MethodRouter { + get, + post, + put: HandlerFunctionRequestHandler::new(handler), + delete, + } + } + + /// Chain an additional [service](RequestHandlerService) that will only accept `PUT` requests. + pub fn put_service( + self, + service: impl RequestHandlerService, + ) -> MethodRouter, DELETE> { + let MethodRouter { + get, + post, + put: MethodNotAllowed, + delete, + } = self; + + MethodRouter { + get, + post, + put: RequestHandlerServiceRequestHandler { service }, + delete, } } } -impl MethodRouter { +impl MethodRouter { + /// Chain an additional [handler](RequestHandlerFunction) that will only accept `DELETE` requests. + pub fn delete< + State, + PathParameters, + T, + Handler: RequestHandlerFunction, + >( + self, + handler: Handler, + ) -> MethodRouter> { + let MethodRouter { + get, + post, + put, + delete: MethodNotAllowed, + } = self; + + MethodRouter { + get, + post, + put, + delete: HandlerFunctionRequestHandler::new(handler), + } + } + + /// Chain an additional [service](RequestHandlerService) that will only accept `DELETE` requests. + pub fn delete_service( + self, + service: impl RequestHandlerService, + ) -> MethodRouter> { + let MethodRouter { + get, + post, + put, + delete: MethodNotAllowed, + } = self; + + MethodRouter { + get, + post, + put, + delete: RequestHandlerServiceRequestHandler { service }, + } + } +} + +impl MethodRouter { /// Add a [Layer] to all routes in the router pub fn layer>( self, @@ -572,6 +785,8 @@ impl MethodRouter { where GET: RequestHandler, POST: RequestHandler, + PUT: RequestHandler, + DELETE: RequestHandler, { layer::MethodRouterLayer { layer, inner: self } } @@ -582,7 +797,9 @@ impl< PathParameters, GET: RequestHandler, POST: RequestHandler, - > MethodHandler for MethodRouter + PUT: RequestHandler, + DELETE: RequestHandler, + > MethodHandler for MethodRouter { async fn call_method_handler>( &self, @@ -612,6 +829,16 @@ impl< .call_request_handler(state, path_parameters, request, response_writer) .await } + "PUT" => { + self.put + .call_request_handler(state, path_parameters, request, response_writer) + .await + } + "DELETE" => { + self.delete + .call_request_handler(state, path_parameters, request, response_writer) + .await + } _ => { MethodNotAllowed .call_request_handler(state, path_parameters, request, response_writer)