Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider making Either uniform with futures::Either #550

Closed
olix0r opened this issue Jan 27, 2021 · 3 comments · Fixed by #637
Closed

Consider making Either uniform with futures::Either #550

olix0r opened this issue Jan 27, 2021 · 3 comments · Fixed by #637
Milestone

Comments

@olix0r
Copy link
Collaborator

olix0r commented Jan 27, 2021

The tower::Either behaves similarly to futures::Either, but they've diverged over time. Namely, tower's is:

enum Either<A, B> {
    A(A),
    B(B),
}

but future's is now:

enum Either<L, R> {
    Left(L),
    Right(R),
}
  • Should we rename our either variants to match future's?
  • Can we simply re-export the futures::Either type and provide Service impls for it?
@olix0r olix0r added this to the 0.5 milestone Jan 27, 2021
@davidpdrsn
Copy link
Member

Should we rename our either variants to match future's?

Yeah I think thats a good idea.

Can we simply re-export the futures::Either type and provide Service impls for it?

There is a bit more to tower's impl Future for Either and futures's so not sure thats possible. It uses #[pin_project] and has bounds the variants containing Results.

@olix0r
Copy link
Collaborator Author

olix0r commented Jan 27, 2021

There is a bit more to tower's impl Future for Either and futures's so not sure thats possible. It uses #[pin_project] and has bounds the variants containing Results.

Does it need to? I.e. if we inherit the Future impl, can it be used for our needs to satisfy Service<Req> for futures::Either<L,R>?

@olix0r
Copy link
Collaborator Author

olix0r commented Jan 18, 2022

As discussed in #629, we should probably update the Either service's return type to be an opaque future so we can drop the dependency on pin-project in tower. We should also require the inner service's to have a uniform error type (rather than boxing the error, potentially erasing infallibility).

hawkw pushed a commit that referenced this issue Feb 17, 2022
In practice I've found `Either` be hard to use since it changes the
error type to `BoxError`. That means if you combine two infallible
services you get a service that, to the type system, is fallible. That
doesn't work well with [axum's error
handling](https://docs.rs/axum/latest/axum/error_handling/index.html)
model which requires all services to be infallible and thus always
return a response. So you end up having to add boilerplate just to
please the type system.

Additionally, the fact that `Either` implements `Future` also means we
cannot fully remove the dependency on `pin-project` since
`pin-project-lite` doesn't support tuple enum variants, only named
fields.

This PR reworks `Either` to address these:

- It now requires the two services to have the same error type so no
  type information is lost. I did consider doing something like `where
  B::Error: From<A::Error>` but I hope this simpler model will lead to
  better compiler errors.
- Changes the response future to be a struct with a private enum using
  `pin-project-lite`
- Removes the `Future` impl so we can remove the dependency on
  `pin-project`

Goes without saying that this is a breaking change so we have to wait
until tower 0.5 to ship this.

cc @jplatte

Fixes #594
Fixes #550
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants