use crate::{Fallback, LoggerStatus, Message, Service};
use std::any::Any;
use std::sync::Mutex;
use crate::service::ServiceError;
use crate::service::write::{StandardMessageFormatter, MessageFormatter};
struct BoxedFmtServiceData<F>
where
F: MessageFormatter,
{
writer: Box<dyn std::fmt::Write + Send + Sync>,
formatter: F,
}
pub struct BoxedFmt<F>
where
F: MessageFormatter,
{
writer: Mutex<BoxedFmtServiceData<F>>,
}
impl<F> BoxedFmt<F>
where
F: MessageFormatter,
{
pub fn new(writer: Box<dyn std::fmt::Write + Send + Sync>) -> Box<Self> {
Box::new(Self {
writer: Mutex::new(BoxedFmtServiceData {
writer,
formatter: Default::default(),
}),
})
}
pub fn with_formatter(
writer: Box<dyn std::fmt::Write + Send + Sync>,
formatter: F,
) -> Box<Self> {
Box::new(Self {
writer: Mutex::new(BoxedFmtServiceData { writer, formatter }),
})
}
pub fn inspect_writer<R>(
&self,
f: impl FnOnce(&Box<dyn std::fmt::Write + Send + Sync>) -> R,
) -> Option<R> {
self.writer.lock().ok().map(|data| f(&data.writer))
}
pub fn take_writer(self) -> Result<Box<dyn std::fmt::Write + Send + Sync>, ServiceError> {
let data = self.writer.into_inner();
match data {
Ok(data) => Ok(data.writer),
Err(_) => Err(ServiceError::LockPoisoned),
}
}
}
impl<F> Service for BoxedFmt<F>
where
F: MessageFormatter + 'static,
{
fn status(&self) -> LoggerStatus {
LoggerStatus::Running
}
fn work(&self, msg: &Message) -> Result<(), ServiceError> {
let mut guard = self.writer.lock()?;
let BoxedFmtServiceData {
formatter, writer, ..
} = &mut *guard;
formatter.format_fmt(msg, writer.as_mut())?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl<F> Fallback for BoxedFmt<F>
where
F: MessageFormatter + 'static,
{
fn fallback(&self, error: &ServiceError, msg: &Message) {
if let Ok(mut guard) = self.writer.lock() {
let mut out = std::io::stdout();
let _ = guard.formatter.format_io(msg, &mut out);
let _ = eprintln!("BoxedFmtWriteService Fallback [Error: {}]", error);
}
}
}
pub type StandardBoxedFmt = BoxedFmt<StandardMessageFormatter>;