Crate union_future

Source
Expand description

Explicit and efficient future that results from a branched future.

The union_future macro creates a future derived from a branch of different underlying futures. The macro can prevent unnecessary boxing of futures when the code can branch into multiple future types.

The macro works by exposing an enum that implements the Future trait, where the underlying future drives the polling behavior. The variants of the enum can have different underlying state machines (types that implement the Future trait).

Additionally, the underlying branch state machines can have different Item types that are mapped to the union_future future’s Item type via the From trait.

Also, as an added bonus, the macro will derive the From trait for the underlying state machines in order to make the branched code clean.

§Installation

Add this to your Cargo.toml:

[dependencies]
union-future = "0.1"
futures = "0.1"

§Examples

The basic usage of the macro uses the same Item type from different underlying futures. For example, if you have a locally cached version otherwise the code will query the database:

#[macro_use]
extern crate union_future;
extern crate futures;

use futures::*;
use futures::future::*;


// Macro will create the enum and necessary trait implementations
// for the QueryFuture. This enum will have 2 variants: Cached and Db.
union_future!(QueryFuture<u64, DbError>,
      Cached => FutureResult<u64, DbError>,
      Db => DbQueryFuture<u64>);

// Example code that branches, using the future created by the macro
pub fn query(db: &Db, key: &str) -> QueryFuture {
    // this example shows multiple ways the QueryFuture can be constructed:
    // either by the explicit enum variant or by using the From/Into traits
    if let Some(cached_val) = check_local_cache(key) {
        QueryFuture::Cached(ok(cached_val))
    } else {
        query_db(db, key).into()
    }
}

fn check_local_cache(key: &str) -> Option<u64> {
    // ...
}

fn query_db(db: &Db, key: &str) -> DbQueryFuture<u64> {
    // ...
}

You could, however, have a future that can be mapped into the future result type with the From trait:

pub enum RedisValue {
    Null,
    Integer(i64),
    Bulk(String),
}

// Implementing the From trait allows the underlying futures to expose
// different Item types transparently

impl From<()> for RedisValue {
    fn from(_: ()) -> RedisValue {
        RedisValue::Null
    }
}

impl From<i64> for RedisValue {
    fn from(other: i64) -> RedisValue {
        RedisValue::Integer(other)
    }
}

impl From<String> for RedisValue {
    fn from(other: String) -> RedisValue {
        RedisValue::Bulk(other)
    }
}

union_future!(RedisValueFuture<RedisValue, DbError>,
      Pong => FutureResult<(), DbError>,
      IntegerQuery => DbQueryFuture<i64>,
      StringQuery => DbQueryFuture<String>);

Macros§

  • A macro to create a future that has branched from multiple underlying futures of distinct types.