union!

union! - one macro to rule them all. Combines sync/async results, transforms tuple of results in result of tuple, provides single and multi thread (sync/async) step by step execution of branches and useful shortcut combinators.

Combinators

where value is the previous value.

Every combinator prefixed by ~ will act as deferred action (all actions will wait until completion in every step and only after move to the next one).

Handler

might be one of

or not specified - then Result<(result0, result1, ..), Error> or Option<(result0, result1, ..)> will be returned.

Single thread combinations

Simple sync results combination

Converts input in series of chained results and joins them step by step.

```rust extern crate union;

use std::error::Error; use union::union;

type Result = std::result::Result>;

fn action_1() -> Result { Ok(1) }

fn action_2() -> Result { Ok(2) }

fn main() { let sum = union! { action1(), action2().map(|v| v as u16), action2().map(|v| v as u16 + 1).andthen(|v| Ok(v * 4)), action1().andthen(|_| Err("5".into())).or(Ok(2)), map => |a, b, c, d| a + b + c + d }.expect("Failed to calculate sum");

println!("Calculated: {}", sum);

} ```

Async results combination

Each branch will represent chain of tasks. All branches will be joined using join! macro and macro will return unpolled future.

```rust

![recursion_limit="256"]

extern crate union; extern crate futures; extern crate tokio;

use std::error::Error; use union::union_async; use futures::future::{ok, err};

type Result = std::result::Result>;

async fn action1() -> Result { Ok(1) } async fn action2() -> Result { Ok(2) }

[tokio::main]

async fn main() { let sum = unionasync! { action1(), action2().andthen(|v| ok(v as u16)), action2().map(|v| v.map(|v| v as u16 + 1)).andthen(|v| ok(v * 4u16)), action1().andthen(|| err("5".into())).orelse(|| ok(2u16)), andthen => |a, b, c, d| ok(a + b + c + d) }.await.expect("Failed to calculate sum");

println!("Calculated: {}", sum);

} ```

Multi-thread combinations

To execute several tasks in parallel you could use union_spawn! (spawnion!) for sync tasks and union_async_spawn! (spasyncion!) for async tasks. Since union_async already provides parallel futures execution in one thread, union_async_spawn! spawns every branch into tokio executor so they will be evaluated in multi-threaded executor.

Multi-thread sync branches

union_spawn spawns one ::std::thread per each step of each branch (number of branches is the max thread count at the time).

```rust extern crate union;

use std::error::Error; use union::union_spawn;

type Result = std::result::Result>;

fn action_1() -> Result { Ok(1) }

fn action_2() -> Result { Ok(2) }

fn main() { // Branches will be executed in parallel let sum = unionspawn! { action1(), action2().map(|v| v as usize), action2().map(|v| v as usize + 1).andthen(|v| Ok(v * 4)), action1().andthen(|| Err("5".into())).or(Ok(2)), map => |a, b, c, d| a + b + c + d }.expect("Failed to calculate sum");

println!("Calculated: {}", sum);

} ```

union_async_spawn! uses ::tokio::spawn function to spawn tasks so it should be done inside tokio runtime (number of branches is the max count of tokio tasks at the time).

Multi-thread async branches

```rust

![recursion_limit="256"]

extern crate union; extern crate futures; extern crate tokio;

use std::error::Error; use union::unionasyncspawn; use futures::future::{ok, err};

type Result = std::result::Result>;

async fn action_1() -> Result { Ok(1) }

async fn action_2() -> Result { Ok(2) }

[tokio::main]

async fn main() { let sum = unionasyncspawn! { action1(), action2().andthen(|v| ok(v as u16)), action2().map(|v| v.map(|v| v as u16 + 1)).andthen(|v| ok(v * 4u16)), action1().andthen(|| err("5".into())).orelse(|| ok(2u16)), and_then => |a, b, c, d| ok(a + b + c + d) }.await.expect("Failed to calculate sum");

println!("Calculated: {}", sum);

} ```

Using combinators we can rewrite first example like

```rust extern crate union;

use std::error::Error; use union::union;

type Result = std::result::Result>;

fn action_1() -> Result { Ok(1) }

fn action_2() -> Result { Ok(2) }

fn main() { let sum = union! { action1(), action2() |> |v| v as u16, action2() |> |v| v as u16 + 1 => |v| Ok(v * 4), action1() => |_| Err("5".into()) <| Ok(2), map => |a, b, c, d| a + b + c + d }.expect("Failed to calculate sum");

println!("Calculated: {}", sum);

} ```

By separating chain in actions, you will make actions wait for completion of all of them in current step before go to the next step.

```rust extern crate union;

use std::error::Error; use union::union;

type Result = std::result::Result;

fn action_1() -> Result { Ok(1) }

fn action_2() -> Result { Ok(2) }

fn main() { let sum = union! { action1(), let result1 = action2() ~|> |v| v as u16 + 1, action2() ~|> move |v| { // result_1 now is the result of action_2() [Ok(1u8)] if result1.isok() { v as u16 + 1 } else { unreachable!() } } ~=> move |v| { // result_1 now is the result of |v| v as u16 + 1 [Ok(2u16)] if let Ok(result1) = result1 { Ok(v * 4 + result1) } else { unreachable!() } }, action1() ~=> |_| Err(5) <| Ok(2), map => |a, b, c, d| a + b + c + d }.expect("Failed to calculate sum"); println!("Calculated: {}", sum); }

```