pub struct Store<S, R> { /* private fields */ }Expand description
A reactive state container.
The only way to mutate the internal state managed by Store is by
dispatching actions on it.
The associated Reactor is notified upon every state transition.
§Example
use reducer::*;
use std::error::Error;
use std::io::{self, Write};
// The state of your app.
struct Calculator(i32);
// Actions the user can trigger.
struct Add(i32);
struct Sub(i32);
struct Mul(i32);
struct Div(i32);
impl Reducer<Add> for Calculator {
fn reduce(&mut self, Add(x): Add) {
self.0 += x;
}
}
impl Reducer<Sub> for Calculator {
fn reduce(&mut self, Sub(x): Sub) {
self.0 -= x;
}
}
impl Reducer<Mul> for Calculator {
fn reduce(&mut self, Mul(x): Mul) {
self.0 *= x;
}
}
impl Reducer<Div> for Calculator {
fn reduce(&mut self, Div(x): Div) {
self.0 /= x;
}
}
// The user interface.
struct Console;
impl Reactor<Calculator> for Console {
type Error = io::Error;
fn react(&mut self, state: &Calculator) -> io::Result<()> {
io::stdout().write_fmt(format_args!("{}\n", state.0))
}
}
fn main() -> Result<(), Box<dyn Error>> {
let mut store = Store::new(Calculator(0), Console);
store.dispatch(Add(5))?; // displays "5"
store.dispatch(Mul(3))?; // displays "15"
store.dispatch(Sub(1))?; // displays "14"
store.dispatch(Div(7))?; // displays "2"
Ok(())
}Implementations§
Source§impl<S, R> Store<S, R>
impl<S, R> Store<S, R>
Sourcepub fn into_task<A, E>(
self,
) -> (impl Future<Output = Result<(), E>>, impl Dispatcher<A, Output = Result<(), DispatchError>> + Sink<A, Error = DispatchError> + Clone)where
Self: Sink<A, Error = E>,
pub fn into_task<A, E>(
self,
) -> (impl Future<Output = Result<(), E>>, impl Dispatcher<A, Output = Result<(), DispatchError>> + Sink<A, Error = DispatchError> + Clone)where
Self: Sink<A, Error = E>,
Turns the Store into a task that can be spawned onto an executor
(requires async).
Once spawned, the task will receive actions dispatched through a lightweight
Dispatcher handle that can be cloned and sent to other threads.
The task completes
- successfully if the asynchronous
Dispatcher(or the last of its clones) is dropped or closed. - with an error if
Store::dispatchfails.
Turning a Store into an asynchronous task 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 reducer::*;
use futures::prelude::*;
use std::error::Error;
use std::io::{self, Write};
use tokio::task::spawn;
// 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,
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let store = Store::new(
Calculator(0),
AsyncReactor(sink::unfold((), |_, state: Calculator| async move {
writeln!(&mut io::stdout(), "{}", state.0)
})),
);
// Process incoming actions on a background task.
let (task, mut dispatcher) = store.into_task();
let handle = spawn(task);
dispatcher.dispatch(Action::Add(5))?; // asynchronously prints "5" to stdout
dispatcher.dispatch(Action::Mul(3))?; // asynchronously prints "15" to stdout
dispatcher.dispatch(Action::Sub(1))?; // asynchronously prints "14" to stdout
dispatcher.dispatch(Action::Div(7))?; // asynchronously prints "2" to stdout
// Closing the asynchronous dispatcher signals to the background task that
// it can terminate once all pending actions have been processed.
dispatcher.close().await?;
// Wait for the background task to terminate.
handle.await??;
Ok(())
}Trait Implementations§
Source§impl<A, S, R> Dispatcher<A> for Store<S, R>
impl<A, S, R> Dispatcher<A> for Store<S, R>
Source§impl<A, S, R, E> Sink<A> for Store<S, R>
View Store as a Sink of actions (requires async).
impl<A, S, R, E> Sink<A> for Store<S, R>
View Store as a Sink of actions (requires async).
Source§fn poll_ready(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>>
fn poll_ready( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll<Result<(), Self::Error>>
Attempts to prepare the
Sink to receive a value. Read moreSource§fn start_send(self: Pin<&mut Self>, action: A) -> Result<(), Self::Error>
fn start_send(self: Pin<&mut Self>, action: A) -> Result<(), Self::Error>
Begin the process of sending a value to the sink.
Each call to this function must be preceded by a successful call to
poll_ready which returned Poll::Ready(Ok(())). Read moreimpl<S: Copy, R: Copy> Copy for Store<S, R>
impl<S: Eq, R: Eq> Eq for Store<S, R>
impl<S, R> StructuralPartialEq for Store<S, R>
impl<'pin, S, R> Unpin for Store<S, R>where
PinnedFieldsOf<__Store<'pin, S, R>>: Unpin,
Auto Trait Implementations§
impl<S, R> Freeze for Store<S, R>
impl<S, R> RefUnwindSafe for Store<S, R>where
S: RefUnwindSafe,
R: RefUnwindSafe,
impl<S, R> Send for Store<S, R>
impl<S, R> Sync for Store<S, R>
impl<S, R> UnwindSafe for Store<S, R>where
S: UnwindSafe,
R: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, Item> SinkExt<Item> for T
impl<T, Item> SinkExt<Item> for T
Source§fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F>
fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F>
Composes a function in front of the sink. Read more
Source§fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F>
fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F>
Composes a function in front of the sink. Read more
Source§fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F>
fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F>
Transforms the error returned by the sink.
Source§fn sink_err_into<E>(self) -> SinkErrInto<Self, Item, E>
fn sink_err_into<E>(self) -> SinkErrInto<Self, Item, E>
Map this sink’s error to a different error type using the
Into trait. Read moreSource§fn buffer(self, capacity: usize) -> Buffer<Self, Item>where
Self: Sized,
fn buffer(self, capacity: usize) -> Buffer<Self, Item>where
Self: Sized,
Adds a fixed-size buffer to the current sink. Read more
Source§fn flush(&mut self) -> Flush<'_, Self, Item>where
Self: Unpin,
fn flush(&mut self) -> Flush<'_, Self, Item>where
Self: Unpin,
Flush the sink, processing all pending items. Read more
Source§fn send(&mut self, item: Item) -> Send<'_, Self, Item>where
Self: Unpin,
fn send(&mut self, item: Item) -> Send<'_, Self, Item>where
Self: Unpin,
A future that completes after the given item has been fully processed
into the sink, including flushing. Read more
Source§fn feed(&mut self, item: Item) -> Feed<'_, Self, Item>where
Self: Unpin,
fn feed(&mut self, item: Item) -> Feed<'_, Self, Item>where
Self: Unpin,
A future that completes after the given item has been received
by the sink. Read more
Source§fn send_all<'a, St>(&'a mut self, stream: &'a mut St) -> SendAll<'a, Self, St>
fn send_all<'a, St>(&'a mut self, stream: &'a mut St) -> SendAll<'a, Self, St>
A future that completes after the given stream has been fully processed
into the sink, including flushing. Read more
Source§fn right_sink<Si1>(self) -> Either<Si1, Self>
fn right_sink<Si1>(self) -> Either<Si1, Self>
Source§fn poll_ready_unpin(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>>where
Self: Unpin,
fn poll_ready_unpin(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Result<(), Self::Error>>where
Self: Unpin,
A convenience method for calling
Sink::poll_ready on Unpin
sink types.Source§fn start_send_unpin(&mut self, item: Item) -> Result<(), Self::Error>where
Self: Unpin,
fn start_send_unpin(&mut self, item: Item) -> Result<(), Self::Error>where
Self: Unpin,
A convenience method for calling
Sink::start_send on Unpin
sink types.