Optimize future combinators

When the receiving future is completed many of the combinator methods can be optimized to avoid creating intermediate futures.

This is a work in progress, it basically doubles the size of complexity of the methods.