use std::io;
use std::io::{stdout, Write};
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender};
use crate::console::component::ConsoleSendable;
use crate::console::ConsoleMessage;
pub trait ConsoleReceiver {
fn send(&self, component: &dyn ConsoleSendable) -> io::Result<()>;
}
pub struct ConsoleSender {
tx: Sender<ConsoleMessage>,
rx: Receiver<ConsoleMessage>,
console: Box<dyn ConsoleReceiver>,
format: Option<Arc<dyn Fn(&dyn ConsoleSendable) -> ConsoleMessage + Send + Sync>>,
}
impl ConsoleSender {
pub fn new<R: ConsoleReceiver + 'static>(receiver: R) -> ConsoleSender {
let (tx, rx) = std::sync::mpsc::channel();
ConsoleSender {
tx,
rx,
console: Box::new(receiver),
format: None,
}
}
pub fn tx(&self) -> Sender<ConsoleMessage> {
self.tx.clone()
}
pub fn set_format<F>(&mut self, formatter: F)
where
F: Fn(&dyn ConsoleSendable) -> ConsoleMessage + Send + Sync + 'static
{
self.format = Some(Arc::new(formatter));
}
pub fn try_send<M: ConsoleSendable>(&self, msg: M) -> io::Result<()> {
if let Some(formatter) = &self.format {
self.console.send(&formatter(&msg))
} else {
self.console.send(&msg)
}
}
pub fn send<M: ConsoleSendable>(&self, msg: M) {
if let Err(e) = self.try_send(msg) {
eprintln!("Console send error: {}", e);
}
}
pub fn send_ref<M: ConsoleSendable>(&self, msg: &M) -> io::Result<()> {
if let Some(formatter) = &self.format {
self.console.send(&formatter(msg))
} else {
self.console.send(msg)
}
}
}
impl ConsoleReceiver for io::Stdout {
fn send(&self, msg: &dyn ConsoleSendable) -> io::Result<()> {
let mut stdout = stdout();
writeln!(stdout, "{}", msg)?;
Ok(())
}
}
impl ConsoleReceiver for ConsoleSender {
fn send(&self, msg: &dyn ConsoleSendable) -> io::Result<()> {
self.console.send(msg)
}
}