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
sourceimpl<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::dispatch
fails.
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
sourceimpl<A, S, R> Dispatcher<A> for Store<S, R> where
S: Reducer<A>,
R: Reactor<S>,
impl<A, S, R> Dispatcher<A> for Store<S, R> where
S: Reducer<A>,
R: Reactor<S>,
sourcefn dispatch(&mut self, action: A) -> Self::Output
fn dispatch(&mut self, action: A) -> Self::Output
Updates the state via Reducer::reduce
and notifies the Reactor
,
returning the result of calling Reactor::react
with a reference
to the new state.
type Output = Result<(), R::Error>
sourceimpl<A, S, R, E> Sink<A> for Store<S, R> where
S: Reducer<A>,
R: for<'s> Sink<&'s S, Error = E>,
impl<A, S, R, E> Sink<A> for Store<S, R> where
S: Reducer<A>,
R: for<'s> Sink<&'s S, Error = E>,
View Store as a Sink of actions (requires async
).
type Error = E
type Error = E
The type of value produced by the sink when an error occurs.
sourcefn 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 more
sourcefn 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 more
impl<S: Copy, R: Copy> Copy for Store<S, R>
impl<S: Eq, R: Eq> Eq for Store<S, R>
impl<S, R> StructuralEq for Store<S, R>
impl<S, R> StructuralPartialEq for Store<S, R>
impl<'pin, S, R> Unpin for Store<S, R> where
__Store<'pin, S, R>: Unpin,
Auto Trait Implementations
impl<S, R> RefUnwindSafe for Store<S, R> where
R: RefUnwindSafe,
S: RefUnwindSafe,
impl<S, R> Send for Store<S, R> where
R: Send,
S: Send,
impl<S, R> Sync for Store<S, R> where
R: Sync,
S: Sync,
impl<S, R> UnwindSafe for Store<S, R> where
R: UnwindSafe,
S: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
impl<T, Item> SinkExt<Item> for T where
T: Sink<Item> + ?Sized,
impl<T, Item> SinkExt<Item> for T where
T: Sink<Item> + ?Sized,
fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F> where
F: FnMut(U) -> Fut,
Fut: Future<Output = Result<Item, E>>,
E: From<Self::Error>,
fn with<U, Fut, F, E>(self, f: F) -> With<Self, Item, U, Fut, F> where
F: FnMut(U) -> Fut,
Fut: Future<Output = Result<Item, E>>,
E: From<Self::Error>,
Composes a function in front of the sink. Read more
fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F> where
F: FnMut(U) -> St,
St: Stream<Item = Result<Item, Self::Error>>,
fn with_flat_map<U, St, F>(self, f: F) -> WithFlatMap<Self, Item, U, St, F> where
F: FnMut(U) -> St,
St: Stream<Item = Result<Item, Self::Error>>,
Composes a function in front of the sink. Read more
fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F> where
F: FnOnce(Self::Error) -> E,
fn sink_map_err<E, F>(self, f: F) -> SinkMapErr<Self, F> where
F: FnOnce(Self::Error) -> E,
Transforms the error returned by the sink.
fn sink_err_into<E>(self) -> SinkErrInto<Self, Item, E> where
Self::Error: Into<E>,
fn sink_err_into<E>(self) -> SinkErrInto<Self, Item, E> where
Self::Error: Into<E>,
Map this sink’s error to a different error type using the Into
trait. Read more
fn buffer(self, capacity: usize) -> Buffer<Self, Item>
fn buffer(self, capacity: usize) -> Buffer<Self, Item>
Adds a fixed-size buffer to the current sink. Read more
fn fanout<Si>(self, other: Si) -> Fanout<Self, Si> where
Item: Clone,
Si: Sink<Item, Error = Self::Error>,
fn fanout<Si>(self, other: Si) -> Fanout<Self, Si> where
Item: Clone,
Si: Sink<Item, Error = Self::Error>,
Fanout items to multiple sinks. Read more
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
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
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
fn send_all<St>(&'a mut self, stream: &'a mut St) -> SendAll<'a, Self, St> where
St: TryStream<Ok = Item, Error = Self::Error> + Stream + Unpin + ?Sized,
Self: Unpin,
fn send_all<St>(&'a mut self, stream: &'a mut St) -> SendAll<'a, Self, St> where
St: TryStream<Ok = Item, Error = Self::Error> + Stream + Unpin + ?Sized,
Self: Unpin,
A future that completes after the given stream has been fully processed into the sink, including flushing. Read more
fn left_sink<Si2>(self) -> Either<Self, Si2> where
Si2: Sink<Item, Error = Self::Error>,
fn left_sink<Si2>(self) -> Either<Self, Si2> where
Si2: Sink<Item, Error = Self::Error>,
Wrap this sink in an Either
sink, making it the left-hand variant
of that Either
. Read more
fn right_sink<Si1>(self) -> Either<Si1, Self> where
Si1: Sink<Item, Error = Self::Error>,
fn right_sink<Si1>(self) -> Either<Si1, Self> where
Si1: Sink<Item, Error = Self::Error>,
Wrap this stream in an Either
stream, making it the right-hand variant
of that Either
. Read more
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,
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,
sourceimpl<T> ToOwned for T where
T: Clone,
impl<T> ToOwned for T where
T: Clone,
type Owned = T
type Owned = T
The resulting type after obtaining ownership.
sourcefn clone_into(&self, target: &mut T)
fn clone_into(&self, target: &mut T)
toowned_clone_into
)Uses borrowed data to replace owned data, usually by cloning. Read more