#![expect(missing_docs, reason = "TODO - Document these items")]
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;
use tokio::task::JoinHandle;
use crate::ViewCtx;
use crate::core::anymore::AnyDebug;
use crate::core::{
MessageContext, MessageProxy, MessageResult, Mut, NoElement, View, ViewId, ViewMarker,
ViewPathTracker,
};
pub fn task<M, F, H, State, Action, Fut>(init_future: F, on_event: H) -> Task<F, H, M>
where
F: Fn(MessageProxy<M>) -> Fut,
Fut: Future<Output = ()> + Send + 'static,
H: Fn(&mut State, M) -> Action + 'static,
M: AnyDebug + Send + 'static,
{
const {
assert!(
size_of::<F>() == 0,
"`task` will not be ran again when its captured variables are updated.\n\
To ignore this warning, use `task_raw`."
);
};
Task {
init_future,
on_event,
message: PhantomData,
}
}
pub fn task_raw<M, F, H, State, Action, Fut>(init_future: F, on_event: H) -> Task<F, H, M>
where
F: Fn(MessageProxy<M>) -> Fut,
Fut: Future<Output = ()> + Send + 'static,
H: Fn(&mut State, M) -> Action + 'static,
M: AnyDebug + Send + 'static,
{
Task {
init_future,
on_event,
message: PhantomData,
}
}
pub struct Task<F, H, M> {
init_future: F,
on_event: H,
message: PhantomData<fn() -> M>,
}
impl<F, H, M> ViewMarker for Task<F, H, M> {}
impl<State, Action, F, H, M, Fut> View<State, Action, ViewCtx> for Task<F, H, M>
where
F: Fn(MessageProxy<M>) -> Fut + 'static,
Fut: Future<Output = ()> + Send + 'static,
H: Fn(&mut State, M) -> Action + 'static,
M: AnyDebug + Send + 'static,
{
type Element = NoElement;
type ViewState = JoinHandle<()>;
fn build(&self, ctx: &mut ViewCtx, _: &mut State) -> (Self::Element, Self::ViewState) {
let path: Arc<[ViewId]> = ctx.view_path().into();
let proxy = ctx.proxy();
let handle = ctx
.runtime()
.spawn((self.init_future)(MessageProxy::new(proxy, path)));
(NoElement, handle)
}
fn rebuild(
&self,
_: &Self,
_: &mut Self::ViewState,
_: &mut ViewCtx,
(): Mut<'_, Self::Element>,
_: &mut State,
) {
}
fn teardown(
&self,
join_handle: &mut Self::ViewState,
_: &mut ViewCtx,
_: Mut<'_, Self::Element>,
) {
join_handle.abort();
}
fn message(
&self,
_: &mut Self::ViewState,
message: &mut MessageContext,
_element: Mut<'_, Self::Element>,
app_state: &mut State,
) -> MessageResult<Action> {
debug_assert!(
message.remaining_path().is_empty(),
"id path should be empty in Task::message"
);
let message = message.take_message::<M>().unwrap();
MessageResult::Action((self.on_event)(app_state, *message))
}
}