use crate::service::ServiceError;
use crate::service::fallback::Fallback;
use crate::service::write::{StandardMessageFormatter, MessageFormatter};
use crate::{LoggerStatus, Message, Service};
use std::any::Any;
use std::sync::Mutex;
struct FmtData<W, F>
where
W: std::fmt::Write + Send + Sync,
F: MessageFormatter,
{
writer: W,
formatter: F,
}
pub struct Fmt<W, F>
where
W: std::fmt::Write + Send + Sync,
F: MessageFormatter,
{
writer: Mutex<FmtData<W, F>>,
}
impl<W, F> Fmt<W, F>
where
W: std::fmt::Write + Send + Sync,
F: MessageFormatter + Default,
{
pub fn new(writer: W) -> Box<Self> {
Box::new(Self {
writer: Mutex::new(FmtData {
writer,
formatter: F::default(),
}),
})
}
pub fn with_formatter(writer: W, formatter: F) -> Box<Self> {
Box::new(Self {
writer: Mutex::new(FmtData { writer, formatter }),
})
}
pub fn inspect_writer<R>(&self, f: impl FnOnce(&W) -> R) -> Option<R> {
self.writer.lock().ok().map(|data| f(&data.writer))
}
pub fn recover_writer(self) -> Result<W, ServiceError> {
let data = self.writer.into_inner();
match data {
Ok(data) => Ok(data.writer),
Err(_) => Err(ServiceError::LockPoisoned),
}
}
pub fn clear_writer(&self)
where
W: Default,
{
if let Ok(mut data) = self.writer.lock() {
data.writer = W::default();
}
}
}
impl<W, F> Service for Fmt<W, F>
where
W: std::fmt::Write + Send + Sync + 'static,
F: MessageFormatter + 'static,
{
fn status(&self) -> LoggerStatus {
LoggerStatus::Running
}
fn work(&self, msg: &Message) -> Result<(), ServiceError> {
let mut guard = self.writer.lock()?;
let FmtData {
formatter, writer, ..
} = &mut *guard;
formatter.format_fmt(msg, writer)?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl<W, F> Fallback for Fmt<W, F>
where
W: std::fmt::Write + Send + Sync + 'static,
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!("FmtWriteService Error: {}", error);
}
}
}
#[allow(type_alias_bounds)]
pub type StringFmt<F: MessageFormatter> = Fmt<String, F>;
pub type StandardStringFmt = Fmt<String, StandardMessageFormatter>;