[−][src]Trait reducer::SpawnDispatcher
Trait for types that can spawn Dispatcher
s 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
.
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,
&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
- successfully if
AsyncDispatcher
(or the last of its clones) is dropped or closed. - successfully if
RemoteHandle
is is dropped, unlessRemoteHandle::forget
is called. - with an error if
Dispatcher::dispatch
fails.- The error can be retrieved by polling
RemoteHandle
to completion.
- The error can be retrieved by polling
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(()) }
Implementors
impl<A, E, S: ?Sized> SpawnDispatcher<A, (), E> for S where
A: Send + 'static,
E: Send + 'static,
S: Spawn,
[src]
A: Send + 'static,
E: Send + 'static,
S: Spawn,
type Handle = RemoteHandle<Result<(), E>>
fn spawn_dispatcher<D>(
&mut self,
d: D
) -> Result<(Self::Dispatcher, Self::Handle), SpawnError> where
D: Dispatcher<A, Output = Result<(), E>> + Sink<A, Error = E> + Send + 'static,
[src]
&mut self,
d: D
) -> Result<(Self::Dispatcher, Self::Handle), SpawnError> where
D: Dispatcher<A, Output = Result<(), E>> + Sink<A, Error = E> + Send + 'static,