1use std::io;
2
3use io::BufWriter;
4use io::Write;
5
6use io::BufRead;
7
8use serde_json::Deserializer;
9use serde_json::Map;
10use serde_json::Number;
11use serde_json::Value;
12
13use rust_xlsxwriter::Workbook;
14use rust_xlsxwriter::Worksheet;
15
16use rust_xlsxwriter::ColNum;
17use rust_xlsxwriter::RowNum;
18
19#[derive(Debug, Clone)]
20pub enum XErr {
21 UnableToWriteBool(String),
22 UnableToWriteDouble(String),
23 UnableToWriteString(String),
24 UnableToConvertArrayToJson(String),
25 UnableToConvertObjectToJson(String),
26 InvalidString,
27 InvalidNumber(String),
28 ColumnOverflow(String),
29 RowOverflow(String),
30 UnableToParseLine(String),
31 InvalidSheetName(String),
32 UnableToSaveToBuffer(String),
33 UnableToWriteToWriter,
34 UnableToFlush,
35 EmptyInput,
36}
37
38pub struct Sheet<'a> {
39 pub ws: &'a mut Worksheet,
40}
41
42impl<'a> Sheet<'a> {
43 pub fn write_null(&mut self, row: RowNum, col: ColNum) {
44 self.ws.clear_cell(row, col);
45 }
46}
47
48impl<'a> Sheet<'a> {
49 pub fn write_bool(&mut self, row: RowNum, col: ColNum, val: bool) -> Result<(), XErr> {
50 self.ws
51 .write_boolean(row, col, val)
52 .map_err(|_| XErr::UnableToWriteBool(format!("rejected value: {val}")))
53 .map(|_| ())
54 }
55
56 pub fn write_double(&mut self, row: RowNum, col: ColNum, val: f64) -> Result<(), XErr> {
57 self.ws
58 .write_number(row, col, val)
59 .map_err(|_| XErr::UnableToWriteDouble(format!("rejected value: {val}")))
60 .map(|_| ())
61 }
62
63 pub fn write_number(&mut self, row: RowNum, col: ColNum, val: Number) -> Result<(), XErr> {
64 let o: Option<f64> = val.as_f64();
65 let f: f64 = o.ok_or_else(|| XErr::InvalidNumber(format!("rejected value: {val}")))?;
66 self.write_double(row, col, f)
67 }
68
69 pub fn write_string(&mut self, row: RowNum, col: ColNum, val: String) -> Result<(), XErr> {
70 self.write_str(row, col, &val)
71 }
72
73 pub fn write_str(&mut self, row: RowNum, col: ColNum, val: &str) -> Result<(), XErr> {
74 self.ws
75 .write_string(row, col, val)
76 .map_err(|_| XErr::UnableToWriteString(format!("rejected value: {val}")))
77 .map(|_| ())
78 }
79
80 pub fn write_array(
81 &mut self,
82 row: RowNum,
83 col: ColNum,
84 val: Vec<Value>,
85 buf: &mut Vec<u8>,
86 ) -> Result<(), XErr> {
87 buf.clear();
88 serde_json::to_writer(buf.by_ref(), &val)
89 .map_err(|e| XErr::UnableToConvertArrayToJson(e.to_string()))?;
90 let bs: &[u8] = buf;
91 let s: &str = std::str::from_utf8(bs).map_err(|_| XErr::InvalidString)?;
92 self.write_str(row, col, s)
93 }
94
95 pub fn write_object(
96 &mut self,
97 row: RowNum,
98 col: ColNum,
99 val: Map<String, Value>,
100 buf: &mut Vec<u8>,
101 ) -> Result<(), XErr> {
102 buf.clear();
103 serde_json::to_writer(buf.by_ref(), &val)
104 .map_err(|e| XErr::UnableToConvertObjectToJson(e.to_string()))?;
105 let bs: &[u8] = buf;
106 let s: &str = std::str::from_utf8(bs).map_err(|_| XErr::InvalidString)?;
107 self.write_str(row, col, s)
108 }
109}
110
111impl<'a> Sheet<'a> {
112 pub fn write_value(
113 &mut self,
114 row: RowNum,
115 col: ColNum,
116 val: Value,
117 buf: &mut Vec<u8>,
118 ) -> Result<(), XErr> {
119 match val {
120 Value::Null => {
121 self.write_null(row, col);
122 Ok(())
123 }
124 Value::Bool(val) => self.write_bool(row, col, val),
125 Value::Number(val) => self.write_number(row, col, val),
126 Value::String(val) => self.write_string(row, col, val),
127 Value::Array(val) => self.write_array(row, col, val, buf),
128 Value::Object(val) => self.write_object(row, col, val, buf),
129 }
130 }
131}
132
133impl<'a> Sheet<'a> {
134 pub fn write_row(
135 &mut self,
136 row: RowNum,
137 val: Map<String, Value>,
138 buf: &mut Vec<u8>,
139 ) -> Result<(), XErr> {
140 for (cno, pair) in val.into_iter().enumerate() {
141 let col: u16 = cno
142 .try_into()
143 .map_err(|_| XErr::ColumnOverflow(format!("rejected column index: {cno}")))?;
144 let val: Value = pair.1;
145 let colnum: ColNum = col;
146 self.write_value(row, colnum, val, buf)?;
147 }
148 Ok(())
149 }
150
151 pub fn write_header<I>(&mut self, headers: I) -> Result<(), XErr>
152 where
153 I: IntoIterator<Item = String>,
154 {
155 for (cno, hdr) in headers.into_iter().enumerate() {
156 let col: u16 = cno
157 .try_into()
158 .map_err(|_| XErr::ColumnOverflow(format!("rejected column index: {cno}")))?;
159 let key: &String = &hdr;
160 let colnum: ColNum = col;
161 self.write_str(0, colnum, key)?;
162 }
163 Ok(())
164 }
165
166 pub fn write_rows<I, K>(&mut self, values: I, buf: &mut Vec<u8>, keys: K) -> Result<(), XErr>
167 where
168 I: Iterator<Item = Result<Map<String, Value>, XErr>>,
169 K: IntoIterator<Item = String>,
170 {
171 self.write_header(keys)?;
172 for (rno, rslt) in values.enumerate() {
173 let rix: usize = rno + 1; let ru: u32 = rix
175 .try_into()
176 .map_err(|_| XErr::RowOverflow(format!("rejected row index: {rix}")))?;
177 let rno: RowNum = ru;
178
179 let val: Map<_, _> = rslt?;
180 self.write_row(rno, val, buf)?;
181 }
182 Ok(())
183 }
184}
185
186pub fn rdr2jsons<R>(rdr: R) -> impl Iterator<Item = Result<Map<String, Value>, XErr>>
187where
188 R: BufRead,
189{
190 Deserializer::from_reader(rdr)
191 .into_iter()
192 .map(|rslt| rslt.map_err(|e| XErr::UnableToParseLine(e.to_string())))
193}
194
195pub struct Book {
196 pub wb: Workbook,
197}
198
199impl Default for Book {
200 fn default() -> Self {
201 Self {
202 wb: Workbook::new(),
203 }
204 }
205}
206
207impl Book {
208 pub fn jsons2sheet<I, K>(
209 &mut self,
210 jsons: I,
211 sheet_name: String,
212 buf: &mut Vec<u8>,
213 keys: K,
214 ) -> Result<(), XErr>
215 where
216 I: Iterator<Item = Result<Map<String, Value>, XErr>>,
217 K: IntoIterator<Item = String>,
218 {
219 let ws: &mut Worksheet = self.wb.add_worksheet();
220 ws.set_name(sheet_name)
221 .map_err(|e| XErr::InvalidSheetName(format!("unable to set the sheet name: {e}")))?;
222 let mut s = Sheet { ws };
223 s.write_rows(jsons, buf, keys)?;
224 Ok(())
225 }
226}
227
228impl Book {
229 pub fn save_to_buffer(&mut self) -> Result<Vec<u8>, XErr> {
230 self.wb
231 .save_to_buffer()
232 .map_err(|e| XErr::UnableToSaveToBuffer(e.to_string()))
233 }
234
235 pub fn save_to_writer<W>(&mut self, mut w: W) -> Result<(), XErr>
236 where
237 W: Write,
238 {
239 let buf: Vec<u8> = self.save_to_buffer()?;
240 w.write_all(&buf).map_err(|_| XErr::UnableToWriteToWriter)?;
241 w.flush().map_err(|_| XErr::UnableToFlush)
242 }
243}
244
245pub fn reader2jsons2sheet2writer<R, W>(
246 rdr: R,
247 sheet_name: String,
248 output: W,
249 buf: &mut Vec<u8>,
250) -> Result<(), XErr>
251where
252 R: BufRead,
253 W: Write,
254{
255 let jsons = rdr2jsons(rdr); let mut pjsons = jsons.peekable();
257 let o1st: Option<&Result<Map<_, _>, _>> = pjsons.peek();
258 let rslt1st: &Result<_, _> = o1st.ok_or(XErr::EmptyInput)?;
259 let m1st: &Map<_, _> = match rslt1st {
260 Ok(m) => Ok(m),
261 Err(e) => Err(e.clone()),
262 }?;
263 let keys: Vec<String> = m1st.keys().cloned().collect();
264 let mut bk: Book = Book::default();
265 bk.jsons2sheet(pjsons, sheet_name, buf, keys)?;
266 bk.save_to_writer(output)
267}
268
269pub fn stdin2jsons2sheet2stdout(sheet_name: String, buf: &mut Vec<u8>) -> Result<(), XErr> {
270 let o = io::stdout();
271 let mut ol = o.lock();
272 reader2jsons2sheet2writer(io::stdin().lock(), sheet_name, BufWriter::new(&mut ol), buf)?;
273 ol.flush().map_err(|_| XErr::UnableToFlush)
274}
275
276pub const SHEET_NAME_DEFAULT: &str = "Sheet1";
277pub const BUF_CAP_DEFAULT: usize = 0;
278
279pub fn stdin2jsons2sheet2stdout_default() -> Result<(), XErr> {
280 let mut buf: Vec<u8> = Vec::with_capacity(BUF_CAP_DEFAULT);
281 stdin2jsons2sheet2stdout(SHEET_NAME_DEFAULT.into(), &mut buf)
282}