Eliza Weisman 359db0ee3f
util: add FutureService::new, with relaxed bounds (#523)
* util: add `FutureService::new`, with relaxed bounds

There are a couple issues with the current implementation of
`FutureService`.

The first, and less important, is a minor usability
issue: there's no `FutureService::new`, just a free function that
returns `FutureService`. While the free function is nice in some cases,
it means that if a user *is* naming the type someplace, they need to
import `tower::util::future_service` *and* `tower::util::FutureService`,
which is slightly annoying. Also, it just kind of violates the common
assumption that most publicly constructable types have a `new`,
requiring a look at the docs.

The second, more significant issue is that the `future_service` function
places a `Service` bound on the future's output type. While this is of
course necessary for the *`Service` impl* on `FutureService`, it's not
required to construct a `FutureService`. Of course, you generally don't
want to construct a `FutureService` that *won't* implement service.
However, the bound also means that additional generic parameters are now
required at the site where the `FutureService` is constructed. In
particular, the caller must now either know the request type, or be
generic over one.

In practice, when other middleware returns or constructs a
`FutureService`, this essentially means that it's necessary to add a
`PhantomData` for the request type parameter. This complicates code, and
perhaps more importantly, increases compile times, especially with
deeply-ensted middleware stacks.

As an example of the downside of aggressive bounds at the constructor,
it's worth noting that the implementation of `FutureService` currently
in `tower` is based directly on a similar implementation in
`linkerd2-proxy`. Except for the difference of whether or not the
constructor has a `Service` bound on the future's output, the two
implementations are very similar, almost identical. This gist shows some
of the change necessary to replace our otherwise identical
implementation with the `tower` version that bounds the `Service` type
at construction-time:

https://gist.github.com/hawkw/a6b07f9f4a8bce0c4b61036ed94114db

This PR solves these issues by adding a `FutureService::new` constructor
that does not introduce the `Service` bound. I didn't change the
`future_service` function: I don't *think* removing bounds is a breaking
change, but it is a modification to a publicly exposed function's type
signature, so I'm a little leery about it. Also, I thought that the more
aggressive bounding at construction-time might still be useful in
simpler use-cases where the `FutureService` is not part of a more
complex middleware stack, and that the free fn might be more likely to
be used in those cases anyway.

cc @davidpdrsn

* relax bounds on free fn

Signed-off-by: Eliza Weisman <eliza@buoyant.io>

* Revert "relax bounds on free fn"

This reverts commit 5ee4fd36c3d1849acede223218a1d457306b9247. This
actually *is* breaking --- it would mean removing the `R` type parameter
for the request type on the function. This changes the function
definition, which might break uses of it.
2021-01-13 12:09:18 -08:00
2016-08-26 16:26:03 -07:00
2020-10-27 11:21:18 -07:00

Tower

Tower is a library of modular and reusable components for building robust networking clients and servers.

Crates.io Documentation Documentation (master) MIT licensed Build Status Discord chat

Overview

Tower aims to make it as easy as possible to build robust networking clients and servers. It is protocol agnostic, but is designed around a request / response pattern. If your protocol is entirely stream based, Tower may not be a good fit.

Status

Currently, tower 0.4 is released on crates.io.

License

This project is licensed under the MIT license.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Tower by you, shall be licensed as MIT, without any additional terms or conditions.

Description
async fn(Request) -> Result
Readme MIT 8.2 MiB
Languages
Rust 100%