1use crate::errors::Error;
8use crate::vba::VbaProject;
9use crate::{
10 open_workbook, open_workbook_from_rs, Data, DataRef, HeaderRow, Metadata, Ods, Range, Reader,
11 ReaderRef, Xls, Xlsb, Xlsx,
12};
13use std::fs::File;
14use std::io::BufReader;
15use std::path::Path;
16
17pub enum Sheets<RS> {
19 Xls(Xls<RS>),
21 Xlsx(Xlsx<RS>),
23 Xlsb(Xlsb<RS>),
25 Ods(Ods<RS>),
27}
28
29pub fn open_workbook_auto<P>(path: P) -> Result<Sheets<BufReader<File>>, Error>
33where
34 P: AsRef<Path>,
35{
36 let path = path.as_ref();
37 Ok(match path.extension().and_then(|e| e.to_str()) {
38 Some("xls" | "xla") => Sheets::Xls(open_workbook(path).map_err(Error::Xls)?),
39 Some("xlsx" | "xlsm" | "xlam") => Sheets::Xlsx(open_workbook(path).map_err(Error::Xlsx)?),
40 Some("xlsb") => Sheets::Xlsb(open_workbook(path).map_err(Error::Xlsb)?),
41 Some("ods") => Sheets::Ods(open_workbook(path).map_err(Error::Ods)?),
42 _ => {
43 if let Ok(ret) = open_workbook::<Xls<_>, _>(path) {
44 return Ok(Sheets::Xls(ret));
45 } else if let Ok(ret) = open_workbook::<Xlsx<_>, _>(path) {
46 return Ok(Sheets::Xlsx(ret));
47 } else if let Ok(ret) = open_workbook::<Xlsb<_>, _>(path) {
48 return Ok(Sheets::Xlsb(ret));
49 } else if let Ok(ret) = open_workbook::<Ods<_>, _>(path) {
50 return Ok(Sheets::Ods(ret));
51 } else {
52 return Err(Error::Msg("Cannot detect file format"));
53 };
54 }
55 })
56}
57
58pub fn open_workbook_auto_from_rs<RS>(data: RS) -> Result<Sheets<RS>, Error>
62where
63 RS: std::io::Read + std::io::Seek + Clone,
64{
65 if let Ok(ret) = open_workbook_from_rs::<Xls<RS>, RS>(data.clone()) {
66 Ok(Sheets::Xls(ret))
67 } else if let Ok(ret) = open_workbook_from_rs::<Xlsx<RS>, RS>(data.clone()) {
68 Ok(Sheets::Xlsx(ret))
69 } else if let Ok(ret) = open_workbook_from_rs::<Xlsb<RS>, RS>(data.clone()) {
70 Ok(Sheets::Xlsb(ret))
71 } else if let Ok(ret) = open_workbook_from_rs::<Ods<RS>, RS>(data) {
72 Ok(Sheets::Ods(ret))
73 } else {
74 Err(Error::Msg("Cannot detect file format"))
75 }
76}
77
78impl<RS> Reader<RS> for Sheets<RS>
79where
80 RS: std::io::Read + std::io::Seek,
81{
82 type Error = Error;
83
84 fn new(_reader: RS) -> Result<Self, Self::Error> {
86 Err(Error::Msg("Sheets must be created from a Path"))
87 }
88
89 fn with_header_row(&mut self, header_row: HeaderRow) -> &mut Self {
90 match self {
91 Sheets::Xls(e) => {
92 e.with_header_row(header_row);
93 }
94 Sheets::Xlsx(e) => {
95 e.with_header_row(header_row);
96 }
97 Sheets::Xlsb(e) => {
98 e.with_header_row(header_row);
99 }
100 Sheets::Ods(e) => {
101 e.with_header_row(header_row);
102 }
103 }
104 self
105 }
106
107 fn vba_project(&mut self) -> Result<Option<VbaProject>, Self::Error> {
109 match self {
110 Sheets::Xls(e) => e.vba_project().map_err(Error::Xls),
111 Sheets::Xlsx(e) => e.vba_project().map_err(Error::Xlsx),
112 Sheets::Xlsb(e) => e.vba_project().map_err(Error::Xlsb),
113 Sheets::Ods(e) => e.vba_project().map_err(Error::Ods),
114 }
115 }
116
117 fn metadata(&self) -> &Metadata {
119 match self {
120 Sheets::Xls(e) => e.metadata(),
121 Sheets::Xlsx(e) => e.metadata(),
122 Sheets::Xlsb(e) => e.metadata(),
123 Sheets::Ods(e) => e.metadata(),
124 }
125 }
126
127 fn worksheet_range(&mut self, name: &str) -> Result<Range<Data>, Self::Error> {
129 match self {
130 Sheets::Xls(e) => e.worksheet_range(name).map_err(Error::Xls),
131 Sheets::Xlsx(e) => e.worksheet_range(name).map_err(Error::Xlsx),
132 Sheets::Xlsb(e) => e.worksheet_range(name).map_err(Error::Xlsb),
133 Sheets::Ods(e) => e.worksheet_range(name).map_err(Error::Ods),
134 }
135 }
136
137 fn worksheet_formula(&mut self, name: &str) -> Result<Range<String>, Self::Error> {
139 match self {
140 Sheets::Xls(e) => e.worksheet_formula(name).map_err(Error::Xls),
141 Sheets::Xlsx(e) => e.worksheet_formula(name).map_err(Error::Xlsx),
142 Sheets::Xlsb(e) => e.worksheet_formula(name).map_err(Error::Xlsb),
143 Sheets::Ods(e) => e.worksheet_formula(name).map_err(Error::Ods),
144 }
145 }
146
147 fn worksheets(&mut self) -> Vec<(String, Range<Data>)> {
148 match self {
149 Sheets::Xls(e) => e.worksheets(),
150 Sheets::Xlsx(e) => e.worksheets(),
151 Sheets::Xlsb(e) => e.worksheets(),
152 Sheets::Ods(e) => e.worksheets(),
153 }
154 }
155
156 #[cfg(feature = "picture")]
157 fn pictures(&self) -> Option<Vec<(String, Vec<u8>)>> {
158 match self {
159 Sheets::Xls(e) => e.pictures(),
160 Sheets::Xlsx(e) => e.pictures(),
161 Sheets::Xlsb(e) => e.pictures(),
162 Sheets::Ods(e) => e.pictures(),
163 }
164 }
165}
166
167impl<RS> ReaderRef<RS> for Sheets<RS>
168where
169 RS: std::io::Read + std::io::Seek,
170{
171 fn worksheet_range_ref<'a>(
172 &'a mut self,
173 name: &str,
174 ) -> Result<Range<DataRef<'a>>, Self::Error> {
175 match self {
176 Sheets::Xlsx(e) => e.worksheet_range_ref(name).map_err(Error::Xlsx),
177 Sheets::Xlsb(e) => e.worksheet_range_ref(name).map_err(Error::Xlsb),
178 Sheets::Xls(_) => unimplemented!(),
179 Sheets::Ods(_) => unimplemented!(),
180 }
181 }
182}