I'm using futures 0.1.14 and I have some code that parses an incoming request body that is multipart into tuples (String, String) consisting of a key and either the text of the field or the file path for the temporary file:
I'm stuck figuring out how to merge the results of the Map of Either's into a Map or stream or something of (String, String). If I map the result of read file, it iterates over the futures of wrapper type Either, which doesn't seem to help me because I need to resolve those futures.
Either<A, B> is a Future only if A and B are futures; otherwise it’s an ordinary enum.
It sounds like your case ends up using it as just an enum. As such, you may as well remove Either and just return the tuple. Then your stream’s type will be the tuple and not the wrapper Either.
That doesn't work because the futures in each branch of the if/else (which handle things differently based on whether the Field is a text or file field) are different future types, which is why the Either is necessary to wrap them =/
So do field.data.read_text() and field.data.read_file() return futures? I originally didn't think so but I guess so based on what you're saying. In that case, you need to make sure your mapping function internally returns a future as well, so that Either<A, B> becomes a future. For instance:
let read_field = |field: Field<Body>| if field.is_text() {
Either::A(field.data.read_text().map(|field| -> (String, String) {
Ok((field.headers.name.clone(), field.text)).into_future() <== make this a FutureResult, which is a Future
}))
} else {
Either::B(field.data.read_file().map(|field| -> (String, String) {
Ok((field.headers.name.clone(), field.filename)).into_future() <== ditto here
}))
};
Ok I see what you're saying, but even when I make sure that I'm returning FutureResults, it doesn't seem that Either is taking on the Future trait, even though both branches are in fact futures. This is the type that comes out if I then on the Map of read_field:
This is what the full code for the if/else looks like now (read_file was an abstraction to make reading the code easier, this is how I'm actually doing it):
Ok, we're getting somewhere here, doing that resolves the Either into a FutureResult, so now that map is getting a FutureResult<(String, String), hyper::Error> though and I can't seem to figure out how to get that resolved.
No, something's not right though if that's what you're seeing.
multi.and_then(read_field) is supposed to transform the multi into a Stream<Item=(String, String), Error=hyper::Error>. It should do that by ensuring the closure you pass returns something that's IntoFuture<Item=(String, String), Error=hyper::Error>.
Either<A,B> is the type returned from your closure - it implements Future if A and B do (as we discussed upthread). Any F: Future<...> is automatically an IntoFuture as well.
So A and B need to be futures that also yield Item=(String, String). The A and B are your two arms of the if/else.
Ah, so if I make the map of each Either branch return (String, String) instead of a FutureResult, it looks like the correct thing is reaching the map after and_then. I think at that point I was just double wrapping the future.
Thanks so much for your help!
For anyone else that might run into this, this is what the working code looks like: