Skip to content

Add combinators for working with Services#104

Merged
carllerche merged 8 commits intotower-rs:masterfrom
fafhrd91:service-ext
Sep 17, 2018
Merged

Add combinators for working with Services#104
carllerche merged 8 commits intotower-rs:masterfrom
fafhrd91:service-ext

Conversation

@fafhrd91
Copy link
Contributor

@fafhrd91 fafhrd91 commented Sep 1, 2018

  • ServiceExt trait
  • and_then, then, map, map_err, from_err, apply combinators

@fafhrd91
Copy link
Contributor Author

fafhrd91 commented Sep 1, 2018

@carllerche

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems right at a glance, so far. I think there's some code here that can be simplified with try_ready!

type Future = ThenFuture<A, B>;

fn poll_ready(&mut self) -> Poll<(), Self::Error> {
match self.a.poll_ready() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take it or leave it: I think this could just be

let _ =  try_ready!(self.a.poll_ready());
self.b.poll_ready()

type Error = T::Error;

fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match self.fut.poll()? {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could just be

let resp = try_ready!(self.fut.poll());
Ok(Async::Ready((self.f)(resp)))

pub struct Apply<T, F, R, Req> {
service: T,
f: F,
r: PhantomData<Fn(Req) -> R>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: since this field isn't used, it should probably have a leading _.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think only the request is needed as a generic on the struct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am not sure, we need F which is Fn(Req, T) -> IntoFuture. do i miss anything?

return fut.poll();
}

match self.fut_a.poll() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can just be

let resp = try_ready!(self.fut_a.poll());
self.fut_b = Some(self.b.call(resp));
self.poll()

type Future = AndThenFuture<A, B>;

fn poll_ready(&mut self) -> Poll<(), Self::Error> {
match self.a.poll_ready() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be:

let _ = try_ready!(self.a.poll_ready());
self.b.poll_ready()

Copy link
Member

@carllerche carllerche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. I left some thoughts inline. Looking forward to the rest.

impl<A, B> AndThen<A, B>
where
A: Service,
A::Error: Into<B::Error>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend against the Into strategy for matching up error types. This is considered a futures 0.1 mistake (the issue doesn't have much discussion...). The problem is it creates a bunch of type inference issues.

The strategy is to either require both services to have the same error type or make the combinator's error Either<A, B>. In this case, I believe it makes most sense to require thee same error type. The user would be able to map the error w/ map_err.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just figured out inference problems.

pub struct Apply<T, F, R, Req> {
service: T,
f: F,
r: PhantomData<Fn(Req) -> R>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think only the request is needed as a generic on the struct?

pub struct MapErr<T, F, E> {
service: T,
f: F,
e: PhantomData<E>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this PhantomData required?

impl<T, F, E> MapErr<T, F, E>
where
T: Service,
F: Fn(T::Error) -> E + Clone,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did Clone on closures land in Rust stable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fn and_then<B, U>(self, service: U) -> AndThen<Self, B>
where
Self: Sized,
U: Into<B>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why the B service is being converted here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would be useful for #69, but i found that From/Into does not work well with type inference.
we need to use custom IntoService trait. i can remove conversion or implement IntoService, it is up to you?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think we should limit Into / From bounds due to type inference issues.

Let's remove the conversion for now.

Separately, I think IntoService will helpful at some point, but lets punt for this PR so that we can get it merged.

@fafhrd91 fafhrd91 changed the title [WIP] add combinators for working with Service's Add combinators for working with Service's Sep 11, 2018
@hawkw hawkw changed the title Add combinators for working with Service's Add combinators for working with Services Sep 11, 2018
Copy link
Member

@carllerche carllerche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks 👍 LGTM. I'll probably play around w/ these combinators some after merging.

Is this ready to merge?

@fafhrd91
Copy link
Contributor Author

Yes, it is ready

@carllerche
Copy link
Member

Thanks 👍

@carllerche carllerche merged commit c29f7e9 into tower-rs:master Sep 17, 2018
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 this pull request may close these issues.

3 participants