use std::fs::{File, OpenOptions};
use std::io::{BufWriter, Write};
use std::path::Path;
use std::sync::Mutex;
use super::{flush_locked, write_locked, Sink};
use crate::error::Result;
use crate::format::Format;
use crate::record::Record;
pub struct WriterSink<W: Write + Send, F: Format> {
format: F,
target: Mutex<W>,
}
impl<W: Write + Send, F: Format> WriterSink<W, F> {
pub fn new(writer: W, format: F) -> Self {
Self {
format,
target: Mutex::new(writer),
}
}
}
impl<W: Write + Send, F: Format> Sink for WriterSink<W, F> {
fn write_record(&self, record: &Record<'_>) -> Result<()> {
write_locked(&self.target, &self.format, record)
}
fn flush(&self) -> Result<()> {
flush_locked(&self.target)
}
}
impl<W: Write + Send, F: Format + core::fmt::Debug> core::fmt::Debug for WriterSink<W, F> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("WriterSink")
.field("format", &self.format)
.finish()
}
}
pub struct FileSink<F: Format> {
format: F,
target: Mutex<BufWriter<File>>,
}
impl<F: Format> FileSink<F> {
pub fn append<P: AsRef<Path>>(path: P, format: F) -> Result<Self> {
let file = OpenOptions::new().create(true).append(true).open(path)?;
Ok(Self {
format,
target: Mutex::new(BufWriter::new(file)),
})
}
pub fn create<P: AsRef<Path>>(path: P, format: F) -> Result<Self> {
let file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(path)?;
Ok(Self {
format,
target: Mutex::new(BufWriter::new(file)),
})
}
}
impl<F: Format> Sink for FileSink<F> {
fn write_record(&self, record: &Record<'_>) -> Result<()> {
write_locked(&self.target, &self.format, record)
}
fn flush(&self) -> Result<()> {
flush_locked(&self.target)
}
}
impl<F: Format + core::fmt::Debug> core::fmt::Debug for FileSink<F> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("FileSink")
.field("format", &self.format)
.finish()
}
}
#[derive(Debug, Default)]
pub struct NullSink;
impl NullSink {
pub const fn new() -> Self {
Self
}
}
impl Sink for NullSink {
fn write_record(&self, _record: &Record<'_>) -> Result<()> {
Ok(())
}
fn flush(&self) -> Result<()> {
Ok(())
}
}