Skip to main content

rs_jsonl2xlsx/
lib.rs

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; // 1,2,3, ...(0: header)
174            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); // impl Iterator<Item=Result<Map, XErr>>
256    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}