use super::command::Command;
#[derive(Debug)]
pub struct UpdateResult<S, M> {
pub state: Option<S>,
pub command: Command<M>,
}
impl<S, M> UpdateResult<S, M> {
pub fn none() -> Self {
Self {
state: None,
command: Command::none(),
}
}
pub fn state(state: S) -> Self {
Self {
state: Some(state),
command: Command::none(),
}
}
pub fn command(command: Command<M>) -> Self {
Self {
state: None,
command,
}
}
pub fn with(state: S, command: Command<M>) -> Self {
Self {
state: Some(state),
command,
}
}
pub fn and_command(mut self, command: Command<M>) -> Self {
self.command = self.command.and(command);
self
}
pub fn map_state<T, F>(self, f: F) -> UpdateResult<T, M>
where
F: FnOnce(S) -> T,
{
UpdateResult {
state: self.state.map(f),
command: self.command,
}
}
pub fn map_message<N, F>(self, f: F) -> UpdateResult<S, N>
where
F: Fn(M) -> N + Clone + Send + 'static,
M: Send + 'static,
N: Send + 'static,
{
UpdateResult {
state: self.state,
command: self.command.map(f),
}
}
}
impl<S, M> Default for UpdateResult<S, M> {
fn default() -> Self {
Self::none()
}
}
pub trait Update {
type State;
type Message;
fn update(&self, state: &mut Self::State, msg: Self::Message) -> Command<Self::Message>;
}
pub struct FnUpdate<S, M, F>
where
F: Fn(&mut S, M) -> Command<M>,
{
f: F,
_phantom: std::marker::PhantomData<(S, M)>,
}
impl<S, M, F> FnUpdate<S, M, F>
where
F: Fn(&mut S, M) -> Command<M>,
{
pub fn new(f: F) -> Self {
Self {
f,
_phantom: std::marker::PhantomData,
}
}
}
impl<S, M, F> Update for FnUpdate<S, M, F>
where
F: Fn(&mut S, M) -> Command<M>,
{
type State = S;
type Message = M;
fn update(&self, state: &mut S, msg: M) -> Command<M> {
(self.f)(state, msg)
}
}
pub trait StateExt: Sized {
fn updated(self, cmd: Command<impl Clone>) -> UpdateResult<Self, impl Clone> {
UpdateResult {
state: Some(self),
command: cmd,
}
}
fn unchanged(self) -> UpdateResult<Self, ()> {
UpdateResult {
state: Some(self),
command: Command::none(),
}
}
}
impl<T> StateExt for T {}
#[cfg(test)]
mod tests;