mirror of https://github.com/linebender/xilem
Rename async_repeat into task (#528)
Following [the discussion in Zulip](https://xi.zulipchat.com/#narrow/stream/354396-xilem/topic/.60async_repeat.60.20name.20brainstorming), this PR renames `async_repeat` view into `task`, and its `future_future` argument into `init_future`. I also assumed we would want to do a corresponding rename in `xilem_web` for consistency.
This commit is contained in:
parent
42a6a320da
commit
f90772a0d2
|
@ -9,7 +9,7 @@ use std::time::Duration;
|
|||
use xilem::{
|
||||
tokio::time,
|
||||
view::{
|
||||
async_repeat, button, button_any_pointer, checkbox, flex, label, prose, textbox, Axis,
|
||||
button, button_any_pointer, checkbox, flex, label, prose, task, textbox, Axis,
|
||||
FlexExt as _, FlexSpacer,
|
||||
},
|
||||
Color, EventLoop, EventLoopBuilder, TextAlignment, WidgetView, Xilem,
|
||||
|
@ -92,10 +92,10 @@ fn app_logic(data: &mut AppData) -> impl WidgetView<AppData> {
|
|||
button("Reset", |data: &mut AppData| data.count = 0),
|
||||
flex((fizz_buzz_flex_sequence, flex_sequence)).direction(axis),
|
||||
)),
|
||||
// The following `async_repeat` view only exists whilst the example is in the "active" state, so
|
||||
// The following `task` view only exists whilst the example is in the "active" state, so
|
||||
// the updates it performs will only be running whilst we are in that state.
|
||||
data.active.then(|| {
|
||||
async_repeat(
|
||||
task(
|
||||
|proxy| async move {
|
||||
let mut interval = time::interval(Duration::from_secs(1));
|
||||
loop {
|
||||
|
|
|
@ -12,7 +12,7 @@ use tokio::time;
|
|||
use tracing::warn;
|
||||
use winit::error::EventLoopError;
|
||||
use winit::window::Window;
|
||||
use xilem::view::{async_repeat, button, flex, label, FlexSequence, FlexSpacer};
|
||||
use xilem::view::{button, flex, label, task, FlexSequence, FlexSpacer};
|
||||
use xilem::{WidgetView, Xilem};
|
||||
use xilem_core::fork;
|
||||
use xilem_core::one_of::Either;
|
||||
|
@ -117,7 +117,7 @@ fn app_logic(data: &mut Stopwatch) -> impl WidgetView<Stopwatch> {
|
|||
)),
|
||||
data.active.then(|| {
|
||||
// Only update while active.
|
||||
async_repeat(
|
||||
task(
|
||||
|proxy| async move {
|
||||
let mut interval = time::interval(Duration::from_millis(50));
|
||||
loop {
|
||||
|
|
|
@ -13,8 +13,7 @@ use time::{error::IndeterminateOffset, macros::format_description, OffsetDateTim
|
|||
use winit::error::EventLoopError;
|
||||
use xilem::{
|
||||
view::{
|
||||
async_repeat, button, flex, label, prose, sized_box, variable_label, Axis, FlexExt,
|
||||
FlexSpacer,
|
||||
button, flex, label, prose, sized_box, task, variable_label, Axis, FlexExt, FlexSpacer,
|
||||
},
|
||||
Color, EventLoop, EventLoopBuilder, WidgetView, Xilem,
|
||||
};
|
||||
|
@ -49,7 +48,7 @@ fn app_logic(data: &mut Clocks) -> impl WidgetView<Clocks> {
|
|||
));
|
||||
fork(
|
||||
view,
|
||||
async_repeat(
|
||||
task(
|
||||
|proxy| async move {
|
||||
// TODO: Synchronise with the actual "second" interval. This is expected to show the wrong second
|
||||
// ~50% of the time.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright 2024 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
mod async_repeat;
|
||||
pub use async_repeat::*;
|
||||
mod task;
|
||||
pub use task::*;
|
||||
|
||||
mod button;
|
||||
pub use button::*;
|
||||
|
|
|
@ -11,20 +11,17 @@ use xilem_core::{
|
|||
use crate::ViewCtx;
|
||||
|
||||
/// Launch a task which will run until the view is no longer in the tree.
|
||||
/// `future_future` is given a [`MessageProxy`], which it will store in the future it returns.
|
||||
/// `init_future` is given a [`MessageProxy`], which it will store in the future it returns.
|
||||
/// This `MessageProxy` can be used to send a message to `on_event`, which can then update
|
||||
/// the app's state.
|
||||
///
|
||||
/// For exampe, this can be used with the time functions in [`crate::tokio::time`].
|
||||
///
|
||||
/// Note that this task will not be updated if the view is rebuilt, so `future_future`
|
||||
/// Note that this task will not be updated if the view is rebuilt, so `init_future`
|
||||
/// cannot capture.
|
||||
// TODO: More thorough documentation.
|
||||
/// See [`run_once`](crate::core::run_once) for details.
|
||||
pub fn async_repeat<M, F, H, State, Action, Fut>(
|
||||
future_future: F,
|
||||
on_event: H,
|
||||
) -> AsyncRepeat<F, H, M>
|
||||
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,
|
||||
|
@ -34,12 +31,12 @@ where
|
|||
const {
|
||||
assert!(
|
||||
core::mem::size_of::<F>() == 0,
|
||||
"`async_repeat` will not be ran again when its captured variables are updated.\n\
|
||||
To ignore this warning, use `async_repeat_raw`."
|
||||
"`task` will not be ran again when its captured variables are updated.\n\
|
||||
To ignore this warning, use `task_raw`."
|
||||
);
|
||||
};
|
||||
AsyncRepeat {
|
||||
future_future,
|
||||
Task {
|
||||
init_future,
|
||||
on_event,
|
||||
message: PhantomData,
|
||||
}
|
||||
|
@ -47,33 +44,30 @@ where
|
|||
|
||||
/// Launch a task which will run until the view is no longer in the tree.
|
||||
///
|
||||
/// This is [`async_repeat`] without the capturing rules.
|
||||
/// See `async_repeat` for full documentation.
|
||||
pub fn async_repeat_raw<M, F, H, State, Action, Fut>(
|
||||
future_future: F,
|
||||
on_event: H,
|
||||
) -> AsyncRepeat<F, H, M>
|
||||
/// This is [`task`] without the capturing rules.
|
||||
/// See `task` for full documentation.
|
||||
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: Message + 'static,
|
||||
{
|
||||
AsyncRepeat {
|
||||
future_future,
|
||||
Task {
|
||||
init_future,
|
||||
on_event,
|
||||
message: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AsyncRepeat<F, H, M> {
|
||||
future_future: F,
|
||||
pub struct Task<F, H, M> {
|
||||
init_future: F,
|
||||
on_event: H,
|
||||
message: PhantomData<fn() -> M>,
|
||||
}
|
||||
|
||||
impl<F, H, M> ViewMarker for AsyncRepeat<F, H, M> {}
|
||||
impl<State, Action, F, H, M, Fut> View<State, Action, ViewCtx> for AsyncRepeat<F, H, 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,
|
||||
|
@ -90,7 +84,7 @@ where
|
|||
let proxy = ctx.proxy.clone();
|
||||
let handle = ctx
|
||||
.runtime()
|
||||
.spawn((self.future_future)(MessageProxy::new(proxy, path)));
|
||||
.spawn((self.init_future)(MessageProxy::new(proxy, path)));
|
||||
(NoElement, handle)
|
||||
}
|
||||
|
||||
|
@ -122,7 +116,7 @@ where
|
|||
) -> xilem_core::MessageResult<Action> {
|
||||
debug_assert!(
|
||||
id_path.is_empty(),
|
||||
"id path should be empty in AsyncRepeat::message"
|
||||
"id path should be empty in Task::message"
|
||||
);
|
||||
let message = message.downcast::<M>().unwrap();
|
||||
xilem_core::MessageResult::Action((self.on_event)(app_state, *message))
|
|
@ -3,10 +3,8 @@
|
|||
|
||||
//! Async views, allowing concurrent operations, like fetching data from a server
|
||||
|
||||
mod async_repeat;
|
||||
pub use async_repeat::{
|
||||
async_repeat, async_repeat_raw, AsyncRepeat, AsyncRepeatProxy, ShutdownSignal,
|
||||
};
|
||||
mod task;
|
||||
pub use task::{task, task_raw, ShutdownSignal, Task, TaskProxy};
|
||||
|
||||
mod interval;
|
||||
pub use interval::{interval, Interval};
|
||||
|
|
|
@ -12,20 +12,17 @@ use crate::{context::MessageThunk, DynMessage, Message, ViewCtx};
|
|||
|
||||
/// Spawn an async task to update state asynchronously
|
||||
///
|
||||
/// The `init_future` function is given an [`AsyncRepeatProxy`] and a [`ShutdownSignal`].
|
||||
/// The `AsyncRepeatProxy` can be used to send a message to `on_event`, which can then update
|
||||
/// The `init_future` function is given a [`TaskProxy`] and a [`ShutdownSignal`].
|
||||
/// The `TaskProxy` can be used to send a message to `on_event`, which can then update
|
||||
/// the app's state.
|
||||
/// The `ShutdownSignal` can be used to detect whether the view has disappeared and
|
||||
/// a shutdown request has been made (because a future cannot be canceled from the outside).
|
||||
///
|
||||
/// Note that this task will not be updated if the view is rebuilt, so `future`
|
||||
/// Note that this task will not be updated if the view is rebuilt, so `init_future`
|
||||
/// cannot capture.
|
||||
pub fn async_repeat<M, F, H, State, Action, Fut>(
|
||||
init_future: F,
|
||||
on_event: H,
|
||||
) -> AsyncRepeat<F, H, M>
|
||||
pub fn task<M, F, H, State, Action, Fut>(init_future: F, on_event: H) -> Task<F, H, M>
|
||||
where
|
||||
F: Fn(AsyncRepeatProxy, ShutdownSignal) -> Fut + 'static,
|
||||
F: Fn(TaskProxy, ShutdownSignal) -> Fut + 'static,
|
||||
Fut: Future<Output = ()> + 'static,
|
||||
H: Fn(&mut State, M) -> Action + 'static,
|
||||
M: Message,
|
||||
|
@ -33,11 +30,11 @@ where
|
|||
const {
|
||||
assert!(
|
||||
core::mem::size_of::<F>() == 0,
|
||||
"`async_repeat` will not be ran again when its captured variables are updated.\n\
|
||||
To ignore this warning, use `async_repeat_raw`."
|
||||
"`task` will not be ran again when its captured variables are updated.\n\
|
||||
To ignore this warning, use `task_raw`."
|
||||
);
|
||||
};
|
||||
AsyncRepeat {
|
||||
Task {
|
||||
init_future,
|
||||
on_event,
|
||||
message: PhantomData,
|
||||
|
@ -46,18 +43,15 @@ where
|
|||
|
||||
/// Spawn a future.
|
||||
///
|
||||
/// This is [`async_repeat`] without the capturing rules.
|
||||
/// See `async_repeat` for full documentation.
|
||||
pub fn async_repeat_raw<M, F, H, State, Action, Fut>(
|
||||
init_future: F,
|
||||
on_event: H,
|
||||
) -> AsyncRepeat<F, H, M>
|
||||
/// This is [`task`] without the capturing rules.
|
||||
/// See `task` for full documentation.
|
||||
pub fn task_raw<M, F, H, State, Action, Fut>(init_future: F, on_event: H) -> Task<F, H, M>
|
||||
where
|
||||
F: Fn(AsyncRepeatProxy, ShutdownSignal) -> Fut + 'static,
|
||||
F: Fn(TaskProxy, ShutdownSignal) -> Fut + 'static,
|
||||
Fut: Future<Output = ()> + 'static,
|
||||
H: Fn(&mut State, M) -> Action + 'static,
|
||||
{
|
||||
AsyncRepeat {
|
||||
Task {
|
||||
init_future,
|
||||
on_event,
|
||||
message: PhantomData,
|
||||
|
@ -100,21 +94,21 @@ impl ShutdownSignal {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct AsyncRepeat<F, H, M> {
|
||||
pub struct Task<F, H, M> {
|
||||
init_future: F,
|
||||
on_event: H,
|
||||
message: PhantomData<fn() -> M>,
|
||||
}
|
||||
|
||||
pub struct AsyncRepeatState {
|
||||
pub struct TaskState {
|
||||
abort_handle: Option<AbortHandle>,
|
||||
}
|
||||
|
||||
pub struct AsyncRepeatProxy {
|
||||
pub struct TaskProxy {
|
||||
thunk: Rc<MessageThunk>,
|
||||
}
|
||||
|
||||
impl AsyncRepeatProxy {
|
||||
impl TaskProxy {
|
||||
pub fn send_message<M>(&self, message: M)
|
||||
where
|
||||
M: Message,
|
||||
|
@ -126,28 +120,28 @@ impl AsyncRepeatProxy {
|
|||
}
|
||||
}
|
||||
|
||||
impl<F, H, M> ViewMarker for AsyncRepeat<F, H, M> {}
|
||||
impl<F, H, M> ViewMarker for Task<F, H, M> {}
|
||||
|
||||
impl<State, Action, F, H, M, Fut> View<State, Action, ViewCtx, DynMessage> for AsyncRepeat<F, H, M>
|
||||
impl<State, Action, F, H, M, Fut> View<State, Action, ViewCtx, DynMessage> for Task<F, H, M>
|
||||
where
|
||||
State: 'static,
|
||||
Action: 'static,
|
||||
F: Fn(AsyncRepeatProxy, ShutdownSignal) -> Fut + 'static,
|
||||
F: Fn(TaskProxy, ShutdownSignal) -> Fut + 'static,
|
||||
Fut: Future<Output = ()> + 'static,
|
||||
H: Fn(&mut State, M) -> Action + 'static,
|
||||
M: Message,
|
||||
{
|
||||
type Element = NoElement;
|
||||
|
||||
type ViewState = AsyncRepeatState;
|
||||
type ViewState = TaskState;
|
||||
|
||||
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
|
||||
let thunk = ctx.message_thunk();
|
||||
let (shutdown_signal, abort_handle) = ShutdownSignal::new();
|
||||
let view_state = AsyncRepeatState {
|
||||
let view_state = TaskState {
|
||||
abort_handle: Some(abort_handle),
|
||||
};
|
||||
let proxy = AsyncRepeatProxy {
|
||||
let proxy = TaskProxy {
|
||||
thunk: Rc::new(thunk),
|
||||
};
|
||||
spawn_local((self.init_future)(proxy, shutdown_signal));
|
|
@ -7,7 +7,7 @@
|
|||
use futures::{select, FutureExt};
|
||||
use gloo_timers::future::TimeoutFuture;
|
||||
use xilem_web::{
|
||||
concurrent::{async_repeat, AsyncRepeatProxy, ShutdownSignal},
|
||||
concurrent::{task, ShutdownSignal, TaskProxy},
|
||||
core::fork,
|
||||
core::one_of::Either,
|
||||
document_body,
|
||||
|
@ -31,7 +31,7 @@ enum Message {
|
|||
/// This is just to simulate some async behavior.
|
||||
/// If you just need an interval, you should use
|
||||
/// [`interval`](xilem_web::concurrent::interval) instead.
|
||||
async fn create_ping_task(proxy: AsyncRepeatProxy, shutdown_signal: ShutdownSignal) {
|
||||
async fn create_ping_task(proxy: TaskProxy, shutdown_signal: ShutdownSignal) {
|
||||
log::debug!("Start ping task");
|
||||
let mut abort = shutdown_signal.into_future().fuse();
|
||||
|
||||
|
@ -55,7 +55,7 @@ async fn create_ping_task(proxy: AsyncRepeatProxy, shutdown_signal: ShutdownSign
|
|||
}
|
||||
|
||||
fn app_logic(state: &mut AppState) -> impl Element<AppState> {
|
||||
let task = async_repeat(
|
||||
let task = task(
|
||||
create_ping_task,
|
||||
|state: &mut AppState, message: Message| match message {
|
||||
Message::Ping => {
|
||||
|
|
Loading…
Reference in New Issue