[][src]Trait reducer::SpawnDispatcher

pub trait SpawnDispatcher<A, O, E> {
    type Handle: TryFuture<Ok = O, Error = E>;
    type Dispatcher: Dispatcher<A>;
    fn spawn_dispatcher<D>(
        &mut self,
        d: D
    ) -> Result<(Self::Dispatcher, Self::Handle), SpawnError>
    where
        D: Dispatcher<A, Output = Result<O, E>> + Sink<A, Error = E> + Send + 'static
; }

Trait for types that can spawn Dispatchers as an asynchronous task (requires async).

Associated Types

type Handle: TryFuture<Ok = O, Error = E>

The type of the result handle returned by spawn_dispatcher.

type Dispatcher: Dispatcher<A>

The type of the Dispatcher returned by spawn_dispatcher.

Loading content...

Required methods

fn spawn_dispatcher<D>(
    &mut self,
    d: D
) -> Result<(Self::Dispatcher, Self::Handle), SpawnError> where
    D: Dispatcher<A, Output = Result<O, E>> + Sink<A, Error = E> + Send + 'static, 

Spawns a Dispatcher as a task that will listen to actions dispatched through the AsyncDispatcher returned.

The task completes

Spawning a Dispatcher requires all actions to be of the same type A; an effective way of fulfilling this requirement is to define actions as enum variants.

Example

use futures::executor::*;
use futures::prelude::*;
use futures::task::*;
use reducer::*;
use std::error::Error;
use std::io::{self, Write};
use std::pin::Pin;

// The state of your app.
#[derive(Clone)]
struct Calculator(i32);

// Actions the user can trigger.
enum Action {
    Add(i32),
    Sub(i32),
    Mul(i32),
    Div(i32),
}

impl Reducer<Action> for Calculator {
    fn reduce(&mut self, action: Action) {
        match action {
            Action::Add(x) => self.0 += x,
            Action::Sub(x) => self.0 -= x,
            Action::Mul(x) => self.0 *= x,
            Action::Div(x) => self.0 /= x,
        }
    }
}

// The user interface.
struct Console;

// Implementing Sink for Console, means it can asynchronously react to state changes.
impl Sink<Calculator> for Console {
    type Error = io::Error;

    fn poll_ready(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    fn start_send(mut self: Pin<&mut Self>, state: Calculator) -> io::Result<()> {
        io::stdout().write_fmt(format_args!("{}\n", state.0))
    }

    fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }

    fn poll_close(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
        Poll::Ready(Ok(()))
    }
}

fn main() -> Result<(), Box<dyn Error>> {
    let store = Store::new(Calculator(0), Reactor::<_, Error = _>::from_sink(Console));

    // Spin up a thread-pool.
    let mut executor = ThreadPool::new()?;

    // Process incoming actions on a background task.
    let (mut dispatcher, handle) = executor.spawn_dispatcher(store)?;

    dispatcher.dispatch(Action::Add(5))?; // eventually displays "5"
    dispatcher.dispatch(Action::Mul(3))?; // eventually displays "15"
    dispatcher.dispatch(Action::Sub(1))?; // eventually displays "14"
    dispatcher.dispatch(Action::Div(7))?; // eventually displays "2"

    // Closing the AsyncDispatcher signals to the background task that
    // it can terminate once all pending actions have been processed.
    block_on(dispatcher.close())?;

    // Wait for the background task to terminate.
    block_on(handle)?;

    Ok(())
}
Loading content...

Implementors

impl<A, E, S: ?Sized> SpawnDispatcher<A, (), E> for S where
    A: Send + 'static,
    E: Send + 'static,
    S: Spawn
[src]

type Handle = RemoteHandle<Result<(), E>>

Loading content...