Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions examples/dyn_reply.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![deny(warnings)]
use warp::{http::StatusCode, Filter};

async fn dyn_reply(word: String) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
if &word == "hello" {
// a cast is needed for now, see https://github.com/rust-lang/rust/issues/60424
Ok(Box::new("world") as Box<dyn warp::Reply>)
} else {
Ok(Box::new(StatusCode::BAD_REQUEST) as Box<dyn warp::Reply>)
}
}

#[tokio::main]
async fn main() {
let routes = warp::path::param().and_then(dyn_reply);

warp::serve(routes).run(([127, 0, 0, 1], 3030)).await;
}
33 changes: 31 additions & 2 deletions src/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use serde_json;
use crate::reject::IsReject;
// This re-export just looks weird in docs...
pub(crate) use self::sealed::Reply_;
use self::sealed::{BoxedReply, Internal};
#[doc(hidden)]
pub use crate::filters::reply as with;

Expand Down Expand Up @@ -226,8 +227,7 @@ where
///
/// let route = warp::any().map(handler);
/// ```
//NOTE: This list is duplicated in the module documentation.
pub trait Reply: Send {
pub trait Reply: BoxedReply + Send {
/// Converts the given value into a [`Response`].
///
/// [`Response`]: type.Response.html
Expand Down Expand Up @@ -292,6 +292,12 @@ pub trait Reply: Send {
*/
}

impl Reply for Box<dyn Reply> {
fn into_response(self) -> Response {
self.boxed_into_response(Internal)
}
}

fn _assert_object_safe() {
fn _assert(_: &dyn Reply) {}
}
Expand Down Expand Up @@ -540,6 +546,23 @@ mod sealed {
self.0
}
}

#[allow(missing_debug_implementations)]
pub struct Internal;

// Implemented for all types that implement `Reply`.
//
// A user doesn't need to worry about this, it's just trait
// hackery to get `Box<dyn Reply>` working.
pub trait BoxedReply {
fn boxed_into_response(self: Box<Self>, internal: Internal) -> Response;
}

impl<T: Reply> BoxedReply for T {
fn boxed_into_response(self: Box<Self>, _: Internal) -> Response {
self.into_response()
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -568,4 +591,10 @@ mod tests {
assert_eq!(res.status(), 500);
}

#[test]
fn boxed_reply() {
let r: Box<dyn Reply> = Box::new(reply());
let resp = r.into_response();
assert_eq!(resp.status(), 200);
}
}