1use std::io;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Deserialize, Serialize)]
6pub struct CsvWriterConfig {
7 #[serde(default = "default_csv_delimiter")]
8 pub delimiter: char,
9 #[serde(default)]
10 pub escape: Option<char>,
11 #[serde(default)]
12 pub flexible: bool,
13 #[serde(default = "default_csv_terminator")]
14 pub terminator: CsvTerminator,
15}
16
17impl Default for CsvWriterConfig {
18 fn default() -> Self {
19 Self {
20 delimiter: default_csv_delimiter(),
21 escape: None,
22 flexible: false,
23 terminator: default_csv_terminator(),
24 }
25 }
26}
27
28fn default_csv_delimiter() -> char {
29 ','
30}
31
32fn default_csv_terminator() -> CsvTerminator {
33 CsvTerminator::Any('\n')
34}
35
36#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
37pub enum CsvTerminator {
38 CRLF,
39 Any(char),
40}
41
42impl From<CsvTerminator> for csv::Terminator {
43 fn from(source: CsvTerminator) -> Self {
44 match source {
45 CsvTerminator::CRLF => Self::CRLF,
46 CsvTerminator::Any(c) => Self::Any(c as u8),
47 }
48 }
49}
50
51impl From<&CsvWriterConfig> for csv::WriterBuilder {
52 fn from(c: &CsvWriterConfig) -> Self {
53 let mut builder = csv::WriterBuilder::new();
54 builder.delimiter(c.delimiter as u8);
55 builder.terminator(c.terminator.into());
56 builder.flexible(c.flexible);
57 if let Some(escape) = c.escape {
58 builder.double_quote(false);
59 builder.escape(escape as u8);
60 } else {
61 builder.double_quote(true);
62 }
63 builder
64 }
65}
66
67pub enum CsvWriter {
68 File(csv::Writer<fs_err::File>),
69 Stdout(csv::Writer<io::Stdout>),
70}
71
72impl CsvWriter {
73 pub fn flush(&mut self) -> io::Result<()> {
74 match self {
75 Self::File(wtr) => wtr.flush(),
76 Self::Stdout(wtr) => wtr.flush(),
77 }
78 }
79
80 pub fn write_record<I, T>(&mut self, record: I) -> csv::Result<()>
81 where
82 I: IntoIterator<Item = T>,
83 T: AsRef<[u8]>,
84 {
85 match self {
86 Self::File(wtr) => wtr.write_record(record),
87 Self::Stdout(wtr) => wtr.write_record(record),
88 }
89 }
90}
91
92#[derive(Debug, Clone, Deserialize, Serialize)]
93pub enum FileMode {
94 Create,
95 Append,
96 Truncate,
97}
98
99impl Default for FileMode {
100 fn default() -> Self {
101 Self::Create
102 }
103}
104
105impl From<FileMode> for fs_err::OpenOptions {
106 fn from(mode: FileMode) -> Self {
107 let mut opts = fs_err::OpenOptions::new();
108 opts.write(true);
109 match mode {
110 FileMode::Create => opts.create_new(true),
111 FileMode::Append => opts.create(true).append(true),
112 FileMode::Truncate => opts.create(true).truncate(true),
113 };
114 opts
115 }
116}