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, StyleRange, WorksheetLayout, 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 worksheet_style(&mut self, name: &str) -> Result<StyleRange, Self::Error> {
148 match self {
149 Sheets::Xls(ref mut e) => e.worksheet_style(name).map_err(Error::Xls),
150 Sheets::Xlsx(ref mut e) => e.worksheet_style(name).map_err(Error::Xlsx),
151 Sheets::Xlsb(ref mut e) => e.worksheet_style(name).map_err(Error::Xlsb),
152 Sheets::Ods(ref mut e) => e.worksheet_style(name).map_err(Error::Ods),
153 }
154 }
155
156 fn worksheet_layout(&mut self, name: &str) -> Result<WorksheetLayout, Self::Error> {
157 match self {
158 Sheets::Xls(ref mut e) => e.worksheet_layout(name).map_err(Error::Xls),
159 Sheets::Xlsx(ref mut e) => e.worksheet_layout(name).map_err(Error::Xlsx),
160 Sheets::Xlsb(ref mut e) => e.worksheet_layout(name).map_err(Error::Xlsb),
161 Sheets::Ods(ref mut e) => e.worksheet_layout(name).map_err(Error::Ods),
162 }
163 }
164
165 fn worksheets(&mut self) -> Vec<(String, Range<Data>)> {
166 match self {
167 Sheets::Xls(e) => e.worksheets(),
168 Sheets::Xlsx(e) => e.worksheets(),
169 Sheets::Xlsb(e) => e.worksheets(),
170 Sheets::Ods(e) => e.worksheets(),
171 }
172 }
173
174 #[cfg(feature = "picture")]
175 fn pictures(&self) -> Option<Vec<(String, Vec<u8>)>> {
176 match self {
177 Sheets::Xls(e) => e.pictures(),
178 Sheets::Xlsx(e) => e.pictures(),
179 Sheets::Xlsb(e) => e.pictures(),
180 Sheets::Ods(e) => e.pictures(),
181 }
182 }
183}
184
185impl<RS> ReaderRef<RS> for Sheets<RS>
186where
187 RS: std::io::Read + std::io::Seek,
188{
189 fn worksheet_range_ref<'a>(
190 &'a mut self,
191 name: &str,
192 ) -> Result<Range<DataRef<'a>>, Self::Error> {
193 match self {
194 Sheets::Xlsx(e) => e.worksheet_range_ref(name).map_err(Error::Xlsx),
195 Sheets::Xlsb(e) => e.worksheet_range_ref(name).map_err(Error::Xlsb),
196 Sheets::Xls(_) => unimplemented!(),
197 Sheets::Ods(_) => unimplemented!(),
198 }
199 }
200}