Refactoring: Drop custom `Either` types where possible
Description
We have a lot of custom Either types within libp2p-core, some of which (I think) could go away by implementing our traits directly on the Either type that we are already depending on.
Motivation
Less code to maintain.
Are you planning to do it yourself in a pull request?
No / Maybe. Could be a good first issue. What do you think @mxinden?
Sounds good to me. Also, should we be using either::Either or futures::future::Either or both?
Sounds good to me. Also, should we be using
either::Eitherorfutures::future::Eitheror both?
I am not sure how well maintained either::Either is but feels like the more appropriate one, given that Future is part of std now?
I've had a brief look and for example the Error impl in either::Either is not overriding all methods so it may need a bit of upstream work until we can completely replace our types.
I think as part of this ticket, one would need to do a bit more research to see if we can drop future::Either for example. Would be interesting to know, why they have their own Either type in the first place.
examining it naively the future::Either could be dropped as it seems to serve as a convenience enum type, which could be replaced by what you mentioned earlier by implementing our traits directly on the Either type or implementing IntoFuture to be awaited.
I've had a brief look and for example the Error impl in either::Either is not overriding all methods so it may need a bit of upstream work until we can completely replace our types.
This is fixed now: https://github.com/bluss/either/pull/69
There is also a new release coming: https://github.com/bluss/either/pull/73
I've opened an issue regarding pin projection which is another blocker for some of our Either use cases: https://github.com/bluss/either/issues/76
I opened an issue with either to see if we can get AsyncRead + AsyncWrite traits. Then we could drop the EitherOutput type: https://github.com/bluss/either/issues/79
I opened an issue with
eitherto see if we can getAsyncRead+AsyncWritetraits. Then we could drop theEitherOutputtype: bluss/either#79
Update: As suggested in the linked issue, we could simply use the futures::Either type for all cases where we need implementations of AsyncRead etc.
I think that is a sensible way forward. Using the same type everywhere would be better but using two already existing ones is already an improvement over defining our own types in my opinion.
I opened an issue with
eitherto see if we can getAsyncRead+AsyncWritetraits. Then we could drop theEitherOutputtype: bluss/either#79Update: As suggested in the linked issue, we could simply use the
futures::Eithertype for all cases where we need implementations ofAsyncReadetc.I think that is a sensible way forward. Using the same type everywhere would be better but using two already existing ones is already an improvement over defining our own types in my opinion.
Unfortunately, this doesn't quite work.
- Our
EitherFuturetype only works onTryFutures and directly transposes the result. - We use our
EitherFuturetype in multiple places. In some of them, the resultingOutputshould be anEitherthat implementsfuturestraits and in some it should be the regularEither. - The
futures::Eithertype implementsFuturesuch that both futures need to evaluate to the same type which is a bit silly IMO and probably the reason we have our own type.
The bottom line is that I think we should convince either that they should provide a Future etc implementation that doesn't try to be clever but simply sets all associated types like Future::Output and Stream::Item to Either.
The bottom line is that I think we should convince
eitherthat they should provide aFutureetc implementation that doesn't try to be clever but simply sets all associated types likeFuture::OutputandStream::ItemtoEither.
That is also not possible because they already implement Future in the exact same way as futures::Either. Unfortunately, this means we are stuck with a custom EitherFuture type that behaves the way we need it. The good news is that we might only need it for SelectUpgrade if we end up doing https://github.com/libp2p/rust-libp2p/issues/3347.
EitherFuture is here to stay for a while so I am considering this to be completed because everything that is actionable has been done.