Skip to main content

rs_xsheet2txt/
lib.rs

1use std::io;
2use std::path::Path;
3
4use io::BufWriter;
5use io::Write;
6
7use calamine::CellType;
8use calamine::Data;
9use calamine::Range;
10use calamine::Reader;
11use calamine::Rows;
12use calamine::Xlsx;
13
14pub struct XlRange<T>(pub Range<T>);
15
16impl<T> XlRange<T>
17where
18    T: CellType,
19{
20    pub fn cell_pos_end(&self) -> Option<(u32, u32)> {
21        self.0.end()
22    }
23
24    pub fn cell_pos_start(&self) -> Option<(u32, u32)> {
25        self.0.start()
26    }
27}
28
29impl<T> XlRange<T>
30where
31    T: CellType,
32{
33    pub fn rows(&self) -> Rows<'_, T> {
34        self.0.rows()
35    }
36}
37
38impl XlRange<Data> {
39    pub fn rows2writer<W>(&self, wtr: &mut W) -> Result<(), io::Error>
40    where
41        W: FnMut(usize, usize, &Data) -> Result<(), io::Error>,
42    {
43        let irow = self.rows();
44        for (rno, row) in irow.enumerate() {
45            for (cno, cell) in row.iter().enumerate() {
46                wtr(rno, cno, cell)?;
47            }
48        }
49        Ok(())
50    }
51}
52
53impl XlRange<Data> {
54    pub fn rows2io_writer<W>(&self, mut wtr: W) -> Result<(), io::Error>
55    where
56        W: Write,
57    {
58        self.rows2writer(&mut |rno: usize, cno: usize, dat: &Data| match dat {
59            Data::Int(i) => write_int(&mut wtr, rno, cno, *i),
60            Data::Float(f) => write_float(&mut wtr, rno, cno, *f),
61            Data::String(s) => write_str(&mut wtr, rno, cno, s),
62            Data::Bool(b) => write_bool(&mut wtr, rno, cno, *b),
63            Data::DateTime(e) => write_datetime(&mut wtr, rno, cno, *e),
64            Data::DateTimeIso(t) => write_datetime_iso(&mut wtr, rno, cno, t),
65            Data::DurationIso(d) => write_duration_iso(&mut wtr, rno, cno, d),
66            Data::Error(e) => write_error(&mut wtr, rno, cno, e),
67            Data::Empty => write_empty(&mut wtr, rno, cno),
68        })?;
69        wtr.flush()
70    }
71}
72
73pub fn write_int<W: Write>(w: &mut W, rno: usize, cno: usize, val: i64) -> io::Result<()> {
74    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:int\tval:{val}")
75}
76
77pub fn write_float<W: Write>(w: &mut W, rno: usize, cno: usize, val: f64) -> io::Result<()> {
78    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:float\tval:{val}")
79}
80
81pub fn write_str<W: Write>(w: &mut W, rno: usize, cno: usize, val: &str) -> io::Result<()> {
82    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:str\tval:{val}")
83}
84
85pub fn write_bool<W: Write>(w: &mut W, rno: usize, cno: usize, val: bool) -> io::Result<()> {
86    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:bool\tval:{val}")
87}
88
89pub fn write_datetime<W: Write>(
90    w: &mut W,
91    rno: usize,
92    cno: usize,
93    val: calamine::ExcelDateTime,
94) -> io::Result<()> {
95    if let Some(ndt) = val.as_datetime() {
96        writeln!(w, "row:{rno}\tcol:{cno}\ttyp:date\tval:{ndt}")
97    } else {
98        writeln!(w, "row:{rno}\tcol:{cno}\ttyp:edate\tval:{val}")
99    }
100}
101
102pub fn write_datetime_iso<W: Write>(
103    w: &mut W,
104    rno: usize,
105    cno: usize,
106    val: &str,
107) -> io::Result<()> {
108    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:date_iso\tval:{val}")
109}
110
111pub fn write_duration_iso<W: Write>(
112    w: &mut W,
113    rno: usize,
114    cno: usize,
115    val: &str,
116) -> io::Result<()> {
117    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:dur_iso\tval:{val}")
118}
119
120pub fn write_error<W: Write>(
121    w: &mut W,
122    rno: usize,
123    cno: usize,
124    val: &calamine::CellErrorType,
125) -> io::Result<()> {
126    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:err\terr:{val}")
127}
128
129pub fn write_empty<W: Write>(w: &mut W, rno: usize, cno: usize) -> io::Result<()> {
130    writeln!(w, "row:{rno}\tcol:{cno}\ttyp:empty\t")
131}
132
133pub fn xpath2sheet2rows2writer<P, W>(xpath: P, sheet: &str, wtr: W) -> Result<(), io::Error>
134where
135    W: Write,
136    P: AsRef<Path>,
137{
138    let mut wkbk: Xlsx<_> = calamine::open_workbook(xpath).map_err(io::Error::other)?;
139    let rng: Range<Data> = wkbk.worksheet_range(sheet).map_err(io::Error::other)?;
140    XlRange(rng).rows2io_writer(wtr)?;
141    Ok(())
142}
143
144pub fn xpath2sheet2rows2stdout<P>(xpath: P, sheet: &str) -> Result<(), io::Error>
145where
146    P: AsRef<Path>,
147{
148    let o = io::stdout();
149    let mut ol = o.lock();
150    xpath2sheet2rows2writer(xpath, sheet, BufWriter::new(&mut ol))?;
151    ol.flush()
152}