use std::fmt::Debug;
use std::future::Future;
use std::sync::Arc;
use crate::component::AsyncComponent;
use crate::factory::{AsyncFactoryComponent, FactoryComponent};
use crate::{Component, Sender, ShutdownReceiver};
#[derive(Debug)]
struct ComponentSenderInner<Input, Output, CommandOutput>
where
Input: Debug,
CommandOutput: Send + 'static,
{
input: Sender<Input>,
output: Sender<Output>,
command: Sender<CommandOutput>,
shutdown: ShutdownReceiver,
}
impl<Input, Output, CommandOutput> ComponentSenderInner<Input, Output, CommandOutput>
where
Input: Debug,
CommandOutput: Send + 'static,
{
#[must_use]
fn input_sender(&self) -> &Sender<Input> {
&self.input
}
#[must_use]
fn output_sender(&self) -> &Sender<Output> {
&self.output
}
#[must_use]
fn command_sender(&self) -> &Sender<CommandOutput> {
&self.command
}
fn input(&self, message: Input) {
self.input.send(message).expect("The runtime of the component was shutdown. Maybe you accidentally dropped a controller?");
}
fn output(&self, message: Output) -> Result<(), Output> {
self.output.send(message)
}
fn command<Cmd, Fut>(&self, cmd: Cmd)
where
Cmd: FnOnce(Sender<CommandOutput>, ShutdownReceiver) -> Fut + Send + 'static,
Fut: Future<Output = ()> + Send,
{
let recipient = self.shutdown.clone();
let sender = self.command.clone();
crate::spawn(async move {
cmd(sender, recipient).await;
});
}
fn spawn_command<Cmd>(&self, cmd: Cmd)
where
Cmd: FnOnce(Sender<CommandOutput>) + Send + 'static,
{
let sender = self.command.clone();
crate::spawn_blocking(move || cmd(sender));
}
fn oneshot_command<Fut>(&self, future: Fut)
where
Fut: Future<Output = CommandOutput> + Send + 'static,
{
self.command(move |out, shutdown| {
shutdown
.register(async move { out.send(future.await) })
.drop_on_shutdown()
});
}
fn spawn_oneshot_command<Cmd>(&self, cmd: Cmd)
where
Cmd: FnOnce() -> CommandOutput + Send + 'static,
{
let handle = crate::spawn_blocking(cmd);
self.oneshot_command(async move { handle.await.unwrap() })
}
}
macro_rules! sender_impl {
($name:ident, $trait:ident) => {
#[derive(Debug)]
pub struct $name<C: $trait> {
shared: Arc<ComponentSenderInner<C::Input, C::Output, C::CommandOutput>>,
}
impl<C: $trait> $name<C> {
pub(crate) fn new(
input: Sender<C::Input>,
output: Sender<C::Output>,
command: Sender<C::CommandOutput>,
shutdown: ShutdownReceiver,
) -> Self {
Self {
shared: Arc::new(ComponentSenderInner {
input,
output,
command,
shutdown,
}),
}
}
#[must_use]
pub fn input_sender(&self) -> &Sender<C::Input> {
self.shared.input_sender()
}
#[must_use]
pub fn output_sender(&self) -> &Sender<C::Output> {
self.shared.output_sender()
}
#[must_use]
pub fn command_sender(&self) -> &Sender<C::CommandOutput> {
self.shared.command_sender()
}
pub fn input(&self, message: C::Input) {
self.shared.input(message);
}
pub fn output(&self, message: C::Output) -> Result<(), C::Output> {
self.shared.output(message)
}
pub fn command<Cmd, Fut>(&self, cmd: Cmd)
where
Cmd: FnOnce(Sender<C::CommandOutput>, ShutdownReceiver) -> Fut + Send + 'static,
Fut: Future<Output = ()> + Send,
{
self.shared.command(cmd)
}
pub fn spawn_command<Cmd>(&self, cmd: Cmd)
where
Cmd: FnOnce(Sender<C::CommandOutput>) + Send + 'static,
{
self.shared.spawn_command(cmd)
}
pub fn oneshot_command<Fut>(&self, future: Fut)
where
Fut: Future<Output = C::CommandOutput> + Send + 'static,
{
self.shared.oneshot_command(future)
}
pub fn spawn_oneshot_command<Cmd>(&self, cmd: Cmd)
where
Cmd: FnOnce() -> C::CommandOutput + Send + 'static,
{
self.shared.spawn_oneshot_command(cmd)
}
}
impl<C: $trait> Clone for $name<C> {
fn clone(&self) -> Self {
Self {
shared: Arc::clone(&self.shared),
}
}
}
};
}
sender_impl!(ComponentSender, Component);
sender_impl!(AsyncComponentSender, AsyncComponent);
sender_impl!(FactorySender, FactoryComponent);
sender_impl!(AsyncFactorySender, AsyncFactoryComponent);