warp icon indicating copy to clipboard operation
warp copied to clipboard

add `tuple_all` filter combinator

Open mikeyhew opened this issue 4 years ago • 3 comments

Adds a new method to Filter that wraps Self::Extract in a tuple. This is useful in generic code that doesn't know how many arguments the filter extracts.

// effective signature:
fn tuple_args(self) -> impl Filter<Extract = (Self::Extract,), Error = Self::Error>

I added an example for documentation, but it's a little complicated, so maybe we should move it to an example or test case, and link to it. Or if someone has a less complicated example, we can use that instead. I'll post it here too:

use warp::{filters::BoxedFilter, Filter, Rejection};

trait FilterExt: Filter {
    /// similar to `and_then`, except the closure is run inside of
    /// `tokio::spawn_blocking` and may block.
    /// Note that, for simplicity, the closure is passed all arguments
    /// as a single tuple.
    ///
    /// # Example
    ///
    /// ```
    /// let route = warp::path!("posts" / u64)
    ///     .and(warp::method())
    ///     .blocking_and_then(|(id, method)| {
    ///         // do something with id and method. It's safe to block here.
    ///     });
    /// ```
    fn blocking_and_then<F, O>(self, func: F) -> BoxedFilter<(O,)>
    where
        F: Fn(Self::Extract) -> Result<O, Rejection> + Clone + Send + Sync + 'static,
        Self: Filter<Error = Rejection> + Clone + Sized + Send + Sync + 'static,
        Self::Extract: Send + 'static,
        O: Send + 'static,
    {
        self.tuple_args()
            .and_then(move |args| {
                let func = func.clone();

                async move {
                    tokio::task::spawn_blocking(move || func(args))
                        .await
                        .unwrap_or_else(|err| panic!("{}", err))
                }
            })
            .boxed()
    }
}

mikeyhew avatar Mar 08 '20 03:03 mikeyhew

Note that this is the inverse of untuple_one.

EDIT: and as far as naming goes, another possible name is tuple_one. That would make it more obvious that these combinators are the opposites of each other, but I'm not sure that name is quite right. untuple_one requires there to be one argument that is a tuple, and "untuples it"; this combinator, on the other hand, can have any number of arguments, and combines them into a single argument. I'm OK with any name really, just want to have this so this example works.

mikeyhew avatar Mar 08 '20 03:03 mikeyhew

@seanmonstar sorry it took me so long to get back to this! I renamed the method from tuple_args to tuple_all, because I think the name matches up with untuple_one better, and replaced the example in the docs with a simpler one based off of the one you gave me.

mikeyhew avatar Apr 13 '21 05:04 mikeyhew

@seanmonstar just wanted to check on this, let me know if there's any more changes you'd like me to make

mikeyhew avatar May 18 '21 22:05 mikeyhew