-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
197 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2024 the Xilem Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::{future::Future, marker::PhantomData}; | ||
|
||
use xilem_core::{DynMessage, Message, MessageResult, NoElement, View, ViewMarker}; | ||
|
||
use crate::{context::MessageThunk, ViewCtx}; | ||
|
||
pub fn async_repeat<M, F, H, State, Action, Fut>( | ||
future_future: F, | ||
on_event: H, | ||
) -> AsyncRepeat<F, H, M> | ||
where | ||
F: Fn(MessageThunk) -> Fut + 'static, | ||
Fut: Future<Output = ()> + 'static, | ||
H: Fn(&mut State, M) -> Action + 'static, | ||
M: Message + 'static, | ||
{ | ||
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`." | ||
); | ||
}; | ||
AsyncRepeat { | ||
future_future, | ||
on_event, | ||
message: PhantomData, | ||
} | ||
} | ||
|
||
pub struct AsyncRepeat<F, H, M> { | ||
future_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, DynMessage> for AsyncRepeat<F, H, M> | ||
where | ||
State: 'static, | ||
Action: 'static, | ||
F: Fn(MessageThunk) -> Fut + 'static, | ||
Fut: Future<Output = ()> + 'static, | ||
H: Fn(&mut State, M) -> Action + 'static, | ||
M: Message + 'static, | ||
{ | ||
type Element = NoElement; | ||
|
||
type ViewState = (); | ||
|
||
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) { | ||
let thunk = ctx.message_thunk(); | ||
wasm_bindgen_futures::spawn_local((self.future_future)(thunk)); | ||
(NoElement, ()) | ||
} | ||
|
||
fn rebuild<'el>( | ||
&self, | ||
_: &Self, | ||
(): &mut Self::ViewState, | ||
_: &mut ViewCtx, | ||
(): xilem_core::Mut<'el, Self::Element>, | ||
) -> xilem_core::Mut<'el, Self::Element> { | ||
// Nothing to do | ||
} | ||
|
||
fn teardown( | ||
&self, | ||
(): &mut Self::ViewState, | ||
_: &mut ViewCtx, | ||
_: xilem_core::Mut<'_, Self::Element>, | ||
) { | ||
// Nothing to do | ||
} | ||
|
||
fn message( | ||
&self, | ||
_: &mut Self::ViewState, | ||
id_path: &[xilem_core::ViewId], | ||
message: DynMessage, | ||
app_state: &mut State, | ||
) -> xilem_core::MessageResult<Action> { | ||
debug_assert!( | ||
id_path.is_empty(), | ||
"id path should be empty in AsyncRepeat::message" | ||
); | ||
let message = message.downcast::<M>().unwrap(); | ||
MessageResult::Action((self.on_event)(app_state, *message)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
[package] | ||
name = "async_repeat" | ||
version = "0.0.0" # not versioned | ||
publish = false | ||
license.workspace = true | ||
edition.workspace = true | ||
|
||
[lints] | ||
workspace = true | ||
|
||
[dependencies] | ||
console_error_panic_hook = "0.1.7" | ||
console_log = { version = "1.0.0", features = ["color"] } | ||
gloo-timers = { version = "0.3.0", features = ["futures"] } | ||
log = "0.4.22" | ||
xilem_web = { path = "../.." } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Async repeat example | Xilem Web</title> | ||
</head> | ||
<body></body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2024 the Xilem Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use gloo_timers::future::TimeoutFuture; | ||
use xilem_web::{ | ||
concurrent::async_repeat, core::fork, document_body, elements::html, interfaces::Element, App, | ||
}; | ||
|
||
#[derive(Default)] | ||
struct AppState { | ||
ping_count: usize, | ||
} | ||
|
||
#[derive(Debug)] | ||
enum Message { | ||
Ping, | ||
} | ||
|
||
fn app_logic(state: &mut AppState) -> impl Element<AppState> { | ||
let task = async_repeat( | ||
|thunk| async move { | ||
loop { | ||
TimeoutFuture::new(1_000).await; | ||
thunk.push_message(Message::Ping); | ||
} | ||
}, | ||
|state: &mut AppState, message: Message| match message { | ||
Message::Ping => { | ||
state.ping_count += 1; | ||
} | ||
}, | ||
); | ||
|
||
fork(html::div(format!("Ping count: {}", state.ping_count)), task) | ||
} | ||
|
||
pub fn main() { | ||
_ = console_log::init_with_level(log::Level::Debug); | ||
console_error_panic_hook::set_once(); | ||
log::info!("Start web application"); | ||
App::new(document_body(), AppState::default(), app_logic).run(); | ||
} |