feat: add initial effects support

This commit is contained in:
JasterV 2026-01-29 01:45:38 +01:00
parent 48802b9e98
commit 72e166a42b
2 changed files with 14 additions and 10 deletions

View file

@ -58,8 +58,8 @@ mod view;
/// - A `view` function, responsible for constructing the view from the model.
///
/// - An `effects` function responsible for handling side effects.
pub fn start<M, Msg, Eff, UF, VF, EF>(
model: M,
pub fn start<M, Msg, Eff, IF, UF, VF, EF>(
init_fn: IF,
update_fn: UF,
view_fn: VF,
effects_fn: EF,
@ -68,12 +68,15 @@ where
M: Clone + Send + Sync + 'static,
Eff: Send + Sync + 'static,
Msg: From<crossterm::event::Event> + Sync + Send + 'static,
IF: Fn() -> (M, Option<Eff>) + Send + Sync + 'static,
UF: Fn(M, Msg) -> Result<Update<M, Eff>> + Send + Sync + 'static,
VF: Fn(&M) -> Result<View> + Send + Sync + 'static,
EF: Fn(&M, Eff) -> Result<Option<Msg>> + Send + Sync + 'static,
{
let terminal = ratatui::init();
let (model, effect) = init_fn();
// Channel for signaling when a task completes
let (shutdown_tx, shutdown_rx) = channel::<Result<()>>();
@ -93,7 +96,7 @@ where
);
spawn_thread(
|| update::run(model, update_fn, update_rx, view_tx, effects_tx),
|| update::run(model, effect, update_fn, update_rx, view_tx, effects_tx),
shutdown_tx.clone(),
);

View file

@ -6,17 +6,15 @@ use std::sync::mpsc::{Receiver, Sender};
///
/// If `Update::Exit` is returned, the program will exit.
///
/// If `Update::Next(M)` is returned, the view will be rendered with the new model.
///
/// If `Update::NextWithEffect` is returned, the view will be rendered with the new model and a side effect will be executed.
/// If `Update::Next(M, Option<E>)` is returned, the view will be rendered with the new model and a side effect might be executed.
pub enum Update<M, E> {
Exit,
Next(M),
NextWithEffect(M, E),
Next(M, Option<E>),
}
pub(crate) fn run<M, Msg, Eff, F>(
mut model: M,
initial_effect: Option<Eff>,
update_fn: F,
rx: Receiver<Msg>,
view_tx: Sender<M>,
@ -27,6 +25,10 @@ where
Eff: Sync + Send + 'static,
M: Clone + Sync + Send + 'static,
{
if let Some(effect) = initial_effect {
effects_tx.send((model.clone(), effect))?;
}
loop {
let Ok(msg) = rx.recv() else {
return Ok(());
@ -36,8 +38,7 @@ where
let (new_model, effect) = match update {
Update::Exit => return Ok(()),
Update::Next(new_model) => (new_model, None),
Update::NextWithEffect(new_model, effect) => (new_model, Some(effect)),
Update::Next(new_model, effect) => (new_model, effect),
};
// Send the new model to the view