From 49785feeb0478cc631a21a9b1914166c3e5dbad2 Mon Sep 17 00:00:00 2001 From: Kaede Hoshikawa Date: Sun, 20 Aug 2023 17:46:16 +0900 Subject: [PATCH] Implement ScopeExt for Reactor. --- packages/yew-agent/src/lib.rs | 8 +- packages/yew-agent/src/oneshot/hooks.rs | 14 +-- packages/yew-agent/src/oneshot/mod.rs | 2 +- packages/yew-agent/src/reactor/mod.rs | 4 +- packages/yew-agent/src/scope_ext.rs | 111 +++++++++++++++--------- 5 files changed, 84 insertions(+), 55 deletions(-) diff --git a/packages/yew-agent/src/lib.rs b/packages/yew-agent/src/lib.rs index 3426ff211ea..a6c5321867d 100644 --- a/packages/yew-agent/src/lib.rs +++ b/packages/yew-agent/src/lib.rs @@ -96,13 +96,13 @@ pub mod prelude { //! Prelude module to be imported when working with `yew-agent`. //! //! This module re-exports the frequently used types from the crate. - pub use crate::oneshot::{oneshot, use_bridge_oneshot, UseBridgeOneshotHandle}; + pub use crate::oneshot::{oneshot, use_oneshot_bridge, UseOneshotBridgeHandle}; pub use crate::reach::Reach; pub use crate::reactor::{ - use_reactor_bridge, use_reactor_subscription, ReactorEvent, UseReactorBridgeHandle, - UseReactorSubscriptionHandle, + reactor, use_reactor_bridge, use_reactor_subscription, ReactorEvent, + UseReactorBridgeHandle, UseReactorSubscriptionHandle, }; - pub use crate::scope_ext::{AgentScopeExt, /* ReactorBridgeHandle, */ WorkerBridgeHandle}; + pub use crate::scope_ext::{AgentScopeExt, ReactorBridgeHandle, WorkerBridgeHandle}; pub use crate::worker::{ use_worker_bridge, use_worker_subscription, UseWorkerBridgeHandle, UseWorkerSubscriptionHandle, diff --git a/packages/yew-agent/src/oneshot/hooks.rs b/packages/yew-agent/src/oneshot/hooks.rs index 96ff0471268..77beaeaef79 100644 --- a/packages/yew-agent/src/oneshot/hooks.rs +++ b/packages/yew-agent/src/oneshot/hooks.rs @@ -3,16 +3,16 @@ use yew::prelude::*; use super::provider::OneshotProviderState; use super::Oneshot; -/// Handle for [use_bridge_oneshot] +/// Handle for [use_oneshot_bridge] #[derive(Debug)] -pub struct UseBridgeOneshotHandle +pub struct UseOneshotBridgeHandle where T: Oneshot + 'static, { state: OneshotProviderState, } -impl UseBridgeOneshotHandle +impl UseOneshotBridgeHandle where T: Oneshot + 'static, { @@ -22,7 +22,7 @@ where } } -impl Clone for UseBridgeOneshotHandle +impl Clone for UseOneshotBridgeHandle where T: Oneshot + 'static, { @@ -33,7 +33,7 @@ where } } -impl PartialEq for UseBridgeOneshotHandle +impl PartialEq for UseOneshotBridgeHandle where T: Oneshot, { @@ -44,11 +44,11 @@ where /// A hook to bridge to an oneshot agent. #[hook] -pub fn use_bridge_oneshot() -> UseBridgeOneshotHandle +pub fn use_oneshot_bridge() -> UseOneshotBridgeHandle where T: Oneshot + 'static, { let state = use_context::>().expect("failed to find worker context"); - UseBridgeOneshotHandle { state } + UseOneshotBridgeHandle { state } } diff --git a/packages/yew-agent/src/oneshot/mod.rs b/packages/yew-agent/src/oneshot/mod.rs index 523d6c4a53c..679f8478963 100644 --- a/packages/yew-agent/src/oneshot/mod.rs +++ b/packages/yew-agent/src/oneshot/mod.rs @@ -5,7 +5,7 @@ mod provider; #[doc(inline)] pub use gloo_worker::oneshot::{Oneshot, OneshotBridge, OneshotRegistrar, OneshotSpawner}; -pub use hooks::{use_bridge_oneshot, UseBridgeOneshotHandle}; +pub use hooks::{use_oneshot_bridge, UseOneshotBridgeHandle}; pub use provider::OneshotProvider; pub(crate) use provider::OneshotProviderState; /// A procedural macro to create oneshot agents. diff --git a/packages/yew-agent/src/reactor/mod.rs b/packages/yew-agent/src/reactor/mod.rs index f67e31d1169..8931e7257c8 100644 --- a/packages/yew-agent/src/reactor/mod.rs +++ b/packages/yew-agent/src/reactor/mod.rs @@ -17,8 +17,7 @@ //! # #[derive(Serialize, Deserialize)] //! # pub struct ReactorOutput {} //! # -//! use yew_agent::reactor; -//! use yew_agent::reactor::{ReactorReceiver, ReactorSender}; +//! use yew_agent::reactor::{reactor, ReactorReceiver, ReactorSender}; //! #[reactor(MyReactor)] //! pub async fn my_reactor(rx: ReactorReceiver, tx: ReactorSender) { //! while let Some(input) = rx.next().await { @@ -47,5 +46,6 @@ pub use hooks::{ UseReactorSubscriptionHandle, }; pub use provider::ReactorProvider; +pub(crate) use provider::ReactorProviderState; /// A procedural macro to create reactor agents. pub use yew_agent_macro::reactor; diff --git a/packages/yew-agent/src/scope_ext.rs b/packages/yew-agent/src/scope_ext.rs index a6a54e577fa..c6029143a38 100644 --- a/packages/yew-agent/src/scope_ext.rs +++ b/packages/yew-agent/src/scope_ext.rs @@ -1,14 +1,18 @@ //! This module contains extensions to the component scope for agent access. +use std::fmt; +use std::rc::Rc; + +use futures::stream::SplitSink; +use futures::{SinkExt, StreamExt}; use wasm_bindgen::UnwrapThrowExt; use yew::html::Scope; +use yew::platform::pinned::RwLock; use yew::platform::spawn_local; use yew::prelude::*; -// use crate::reactor::{ -// Reactor, ReactorInput, ReactorOutput, ReactorReceivable, ReactorSendable, ReactorWorker, -// }; use crate::oneshot::{Oneshot, OneshotProviderState}; +use crate::reactor::{Reactor, ReactorBridge, ReactorEvent, ReactorProviderState, ReactorScoped}; use crate::worker::{Worker, WorkerBridge, WorkerProviderState}; /// A Worker Bridge Handle. @@ -30,24 +34,40 @@ where } } -// /// A Reactor Bridge Handle. -// #[derive(Debug)] -// pub struct ReactorBridgeHandle -// where -// R: Reactor + 'static, -// { -// inner: WorkerBridge>, -// } - -// impl ReactorBridgeHandle -// where -// R: Reactor + 'static, -// { -// /// Sends a message to the reactor agent. -// pub fn send(&self, input: ::Input) { -// self.inner.send(ReactorInput::Input(input)) -// } -// } +type ReactorTx = + Rc, <::Scope as ReactorScoped>::Input>>>; + +/// A Reactor Bridge Handle. +pub struct ReactorBridgeHandle +where + R: Reactor + 'static, +{ + tx: ReactorTx, +} + +impl fmt::Debug for ReactorBridgeHandle +where + R: Reactor + 'static, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ReactorBridgeHandle<_>") + .finish_non_exhaustive() + } +} + +impl ReactorBridgeHandle +where + R: Reactor + 'static, +{ + /// Sends a message to the reactor agent. + pub fn send(&self, input: ::Input) { + let tx = self.tx.clone(); + spawn_local(async move { + let mut tx = tx.write().await; + let _ = tx.send(input).await; + }); + } +} /// An extension to [`Scope`](yew::html::Scope) that provides communication mechanism to agents. /// @@ -58,14 +78,11 @@ pub trait AgentScopeExt { where W: Worker + 'static; - // /// Bridges to a Reactor Agent. - // fn bridge_reactor( - // &self, - // callback: Callback::Output>>, - // ) -> ReactorBridgeHandle - // where - // R: Reactor + 'static, - // ::Output: 'static; + /// Bridges to a Reactor Agent. + fn bridge_reactor(&self, callback: Callback>) -> ReactorBridgeHandle + where + R: Reactor + 'static, + ::Output: 'static; /// Runs a task in a Task Agent. fn run_task(&self, input: T::Input, callback: Callback) @@ -90,18 +107,30 @@ where WorkerBridgeHandle { inner } } - // fn bridge_reactor( - // &self, - // callback: Callback::Output>>, - // ) -> ReactorBridgeHandle - // where - // R: Reactor, - // ::Output: 'static, - // { - // let inner = self.bridge_worker::>(callback).inner; - - // ReactorBridgeHandle { inner } - // } + fn bridge_reactor(&self, callback: Callback>) -> ReactorBridgeHandle + where + R: Reactor + 'static, + ::Output: 'static, + { + let (tx, mut rx) = self + .context::>((|_| {}).into()) + .expect_throw("failed to bridge to agent.") + .0 + .create_bridge() + .split(); + + spawn_local(async move { + while let Some(m) = rx.next().await { + callback.emit(ReactorEvent::::Output(m)); + } + + callback.emit(ReactorEvent::::Finished); + }); + + let tx = Rc::new(RwLock::new(tx)); + + ReactorBridgeHandle { tx } + } fn run_task(&self, input: T::Input, callback: Callback) where