1use std::fs::{File, OpenOptions};
4use std::io::{BufWriter, Write};
5use std::path::Path;
6use std::sync::Mutex;
7
8use super::{flush_locked, write_locked, Sink};
9use crate::error::Result;
10use crate::format::Format;
11use crate::record::Record;
12
13pub struct WriterSink<W: Write + Send, F: Format> {
19 format: F,
20 target: Mutex<W>,
21}
22
23impl<W: Write + Send, F: Format> WriterSink<W, F> {
24 pub fn new(writer: W, format: F) -> Self {
26 Self {
27 format,
28 target: Mutex::new(writer),
29 }
30 }
31}
32
33impl<W: Write + Send, F: Format> Sink for WriterSink<W, F> {
34 fn write_record(&self, record: &Record<'_>) -> Result<()> {
35 write_locked(&self.target, &self.format, record)
36 }
37 fn flush(&self) -> Result<()> {
38 flush_locked(&self.target)
39 }
40}
41
42impl<W: Write + Send, F: Format + core::fmt::Debug> core::fmt::Debug for WriterSink<W, F> {
43 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44 f.debug_struct("WriterSink")
45 .field("format", &self.format)
46 .finish()
47 }
48}
49
50pub struct FileSink<F: Format> {
57 format: F,
58 target: Mutex<BufWriter<File>>,
59}
60
61impl<F: Format> FileSink<F> {
62 pub fn append<P: AsRef<Path>>(path: P, format: F) -> Result<Self> {
65 let file = OpenOptions::new().create(true).append(true).open(path)?;
66 Ok(Self {
67 format,
68 target: Mutex::new(BufWriter::new(file)),
69 })
70 }
71
72 pub fn create<P: AsRef<Path>>(path: P, format: F) -> Result<Self> {
74 let file = OpenOptions::new()
75 .create(true)
76 .write(true)
77 .truncate(true)
78 .open(path)?;
79 Ok(Self {
80 format,
81 target: Mutex::new(BufWriter::new(file)),
82 })
83 }
84}
85
86impl<F: Format> Sink for FileSink<F> {
87 fn write_record(&self, record: &Record<'_>) -> Result<()> {
88 write_locked(&self.target, &self.format, record)
89 }
90 fn flush(&self) -> Result<()> {
91 flush_locked(&self.target)
92 }
93}
94
95impl<F: Format + core::fmt::Debug> core::fmt::Debug for FileSink<F> {
96 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97 f.debug_struct("FileSink")
98 .field("format", &self.format)
99 .finish()
100 }
101}
102
103#[derive(Debug, Default)]
105pub struct NullSink;
106
107impl NullSink {
108 pub const fn new() -> Self {
110 Self
111 }
112}
113
114impl Sink for NullSink {
115 fn write_record(&self, _record: &Record<'_>) -> Result<()> {
116 Ok(())
117 }
118 fn flush(&self) -> Result<()> {
119 Ok(())
120 }
121}