use std::future::Future;
use wasm_bindgen_futures::spawn_local;
use yew::{
agent::{Agent, AgentLink},
Callback, Component, ComponentLink,
};
pub trait LinkFuture {
type Message;
fn callback_future<FN, FU, IN, M>(&self, function: FN) -> Callback<IN>
where
M: Into<Self::Message>,
FU: Future<Output = M> + 'static,
FN: Fn(IN) -> FU + 'static;
fn callback_future_once<FN, FU, IN, M>(&self, function: FN) -> Callback<IN>
where
M: Into<Self::Message>,
FU: Future<Output = M> + 'static,
FN: FnOnce(IN) -> FU + 'static;
fn send_future<F, M>(&self, future: F)
where
M: Into<Self::Message>,
F: Future<Output = M> + 'static;
fn send_future_batch<F>(&self, future: F)
where
F: Future<Output = Vec<Self::Message>> + 'static;
}
impl<COMP: Component> LinkFuture for ComponentLink<COMP> {
type Message = COMP::Message;
fn callback_future<FN, FU, IN, M>(&self, function: FN) -> Callback<IN>
where
M: Into<Self::Message>,
FU: Future<Output = M> + 'static,
FN: Fn(IN) -> FU + 'static,
{
let link = self.clone();
let closure = move |input: IN| {
let future: FU = function(input);
link.send_future(future);
};
closure.into()
}
fn callback_future_once<FN, FU, IN, M>(&self, function: FN) -> Callback<IN>
where
M: Into<Self::Message>,
FU: Future<Output = M> + 'static,
FN: FnOnce(IN) -> FU + 'static,
{
let link = self.clone();
let closure = move |input: IN| {
let future: FU = function(input);
link.send_future(future);
};
Callback::once(closure)
}
fn send_future<F, M>(&self, future: F)
where
M: Into<Self::Message>,
F: Future<Output = M> + 'static,
{
let link: ComponentLink<COMP> = self.clone();
let js_future = async move {
let message: COMP::Message = future.await.into();
link.send_message(message);
};
spawn_local(js_future);
}
fn send_future_batch<F>(&self, future: F)
where
F: Future<Output = Vec<Self::Message>> + 'static,
{
let link: ComponentLink<COMP> = self.clone();
let js_future = async move {
let messages: Vec<COMP::Message> = future.await;
link.send_message_batch(messages);
};
spawn_local(js_future);
}
}
impl<AGN: Agent> LinkFuture for AgentLink<AGN> {
type Message = AGN::Message;
fn callback_future<FN, FU, IN, M>(&self, function: FN) -> Callback<IN>
where
M: Into<Self::Message>,
FU: Future<Output = M> + 'static,
FN: Fn(IN) -> FU + 'static,
{
let link = self.clone();
let closure = move |input: IN| {
let future: FU = function(input);
link.send_future(future);
};
closure.into()
}
fn callback_future_once<FN, FU, IN, M>(&self, function: FN) -> Callback<IN>
where
M: Into<Self::Message>,
FU: Future<Output = M> + 'static,
FN: FnOnce(IN) -> FU + 'static,
{
let link = self.clone();
let closure = move |input: IN| {
let future: FU = function(input);
link.send_future(future);
};
Callback::once(closure)
}
fn send_future<F, M>(&self, future: F)
where
M: Into<Self::Message>,
F: Future<Output = M> + 'static,
{
let link: AgentLink<AGN> = self.clone();
let js_future = async move {
let message: AGN::Message = future.await.into();
let cb = link.callback(|m: AGN::Message| m);
cb.emit(message);
};
spawn_local(js_future);
}
fn send_future_batch<F>(&self, _future: F)
where
F: Future<Output = Vec<Self::Message>> + 'static,
{
unimplemented!("Agents don't support batching their messages.")
}
}