Then() or map() from futures combinators?


#1

then() maps Result<Item, Error> to Result<Item, Error>;
map() maps Item to Item;
map_err() maps Error to Error;

Is there a combinator:

  • which maps Item to Result<Item, Error>,
  • which would be invoked only when future chain was successful before (like map()) AND
  • which would trigger following chained map() calls, if the combinator returns Ok(Item) AND
  • which would trigger following chained map_err() calls, if the combinator returns Err(Error)
    ?

If there is none, how could I come up with one?


#2

I think you should use then() - only criteria it doesn’t fit is your second one, but it’s easy to handle it yourself inside the closure you provide to it by matching on the Result you’re given.

If you return Ok from the closure, the chain continues with the value you put in there; if you return Err, the chain continues with the error instead.


#3

That is what I ended up doing. I just noticed this comes up frequently for me.


#4

Does and_then() work for you? It’ll transform from Item to Result if the previous future was successful.


#5

and_then implies that new future is spawned, does not fit the case when result is ready. Although, It can be used with futures::result(…) to achieve the outcome.


#6

Note that then and and_then both return something that’s an IntoFuture, so there’s no real difference from that standpoint. and_then requires that your Error type is the same as the upstream future (since it’s only called on success), whereas then does not.


#7

To me it looks like you want; (with types added)

f: Future<Item, Error>
f.map(|i:Item| Result::Ok(i))
.or_else(|e:Error| future::ok(Result::Err(e))) /*maybe conditional*/
.and_then(|i: Result<Item,Error>| {...}) /* or map */

So long as it isn’t calling something like lazy there shouldn’t be any extra poll. Maybe even gets optimised away.


#8

The or_else there would essentially turn the chain into a Future<Item=Result<...>, Error=...>, which means the chain continues with a success value but the item itself is a Result. This means a subsequent map_err wouldn’t execute. I think then is more straightforward since you can change whether the chain continues with success or error in one combinator.