1use crate::errors::Error;
4use crate::vba::VbaProject;
5use crate::{
6 open_workbook, open_workbook_from_rs, DataType, Metadata, Ods, Range, Reader, Xls, Xlsb, Xlsx,
7};
8use std::borrow::Cow;
9use std::fs::File;
10use std::io::BufReader;
11use std::path::Path;
12
13pub enum Sheets<RS> {
15 Xls(Xls<RS>),
17 Xlsx(Xlsx<RS>),
19 Xlsb(Xlsb<RS>),
21 Ods(Ods<RS>),
23}
24
25pub fn open_workbook_auto<P>(path: P) -> Result<Sheets<BufReader<File>>, Error>
29where
30 P: AsRef<Path>,
31{
32 let path = path.as_ref();
33 Ok(match path.extension().and_then(|e| e.to_str()) {
34 Some("xls") | Some("xla") => Sheets::Xls(open_workbook(path).map_err(Error::Xls)?),
35 Some("xlsx") | Some("xlsm") | Some("xlam") => {
36 Sheets::Xlsx(open_workbook(path).map_err(Error::Xlsx)?)
37 }
38 Some("xlsb") => Sheets::Xlsb(open_workbook(path).map_err(Error::Xlsb)?),
39 Some("ods") => Sheets::Ods(open_workbook(path).map_err(Error::Ods)?),
40 _ => {
41 if let Ok(ret) = open_workbook::<Xls<_>, _>(path) {
42 return Ok(Sheets::Xls(ret));
43 } else if let Ok(ret) = open_workbook::<Xlsx<_>, _>(path) {
44 return Ok(Sheets::Xlsx(ret));
45 } else if let Ok(ret) = open_workbook::<Xlsb<_>, _>(path) {
46 return Ok(Sheets::Xlsb(ret));
47 } else if let Ok(ret) = open_workbook::<Ods<_>, _>(path) {
48 return Ok(Sheets::Ods(ret));
49 } else {
50 return Err(Error::Msg("Cannot detect file format"));
51 };
52 }
53 })
54}
55
56pub fn open_workbook_auto_from_rs<RS>(data: RS) -> Result<Sheets<RS>, Error>
60where
61 RS: std::io::Read + std::io::Seek + Clone,
62{
63 if let Ok(ret) = open_workbook_from_rs::<Xls<RS>, RS>(data.clone()) {
64 return Ok(Sheets::Xls(ret));
65 } else if let Ok(ret) = open_workbook_from_rs::<Xlsx<RS>, RS>(data.clone()) {
66 return Ok(Sheets::Xlsx(ret));
67 } else if let Ok(ret) = open_workbook_from_rs::<Xlsb<RS>, RS>(data.clone()) {
68 return Ok(Sheets::Xlsb(ret));
69 } else if let Ok(ret) = open_workbook_from_rs::<Ods<RS>, RS>(data) {
70 return Ok(Sheets::Ods(ret));
71 } else {
72 return Err(Error::Msg("Cannot detect file format"));
73 };
74}
75
76impl<RS> Reader<RS> for Sheets<RS>
77where
78 RS: std::io::Read + std::io::Seek,
79{
80 type Error = Error;
81
82 fn new(_reader: RS) -> Result<Self, Self::Error> {
84 Err(Error::Msg("Sheets must be created from a Path"))
85 }
86
87 fn vba_project(&mut self) -> Option<Result<Cow<'_, VbaProject>, Self::Error>> {
89 match *self {
90 Sheets::Xls(ref mut e) => e.vba_project().map(|vba| vba.map_err(Error::Xls)),
91 Sheets::Xlsx(ref mut e) => e.vba_project().map(|vba| vba.map_err(Error::Xlsx)),
92 Sheets::Xlsb(ref mut e) => e.vba_project().map(|vba| vba.map_err(Error::Xlsb)),
93 Sheets::Ods(ref mut e) => e.vba_project().map(|vba| vba.map_err(Error::Ods)),
94 }
95 }
96
97 fn metadata(&self) -> &Metadata {
99 match *self {
100 Sheets::Xls(ref e) => e.metadata(),
101 Sheets::Xlsx(ref e) => e.metadata(),
102 Sheets::Xlsb(ref e) => e.metadata(),
103 Sheets::Ods(ref e) => e.metadata(),
104 }
105 }
106
107 fn worksheet_range(&mut self, name: &str) -> Option<Result<Range<DataType>, Self::Error>> {
109 match *self {
110 Sheets::Xls(ref mut e) => e.worksheet_range(name).map(|r| r.map_err(Error::Xls)),
111 Sheets::Xlsx(ref mut e) => e.worksheet_range(name).map(|r| r.map_err(Error::Xlsx)),
112 Sheets::Xlsb(ref mut e) => e.worksheet_range(name).map(|r| r.map_err(Error::Xlsb)),
113 Sheets::Ods(ref mut e) => e.worksheet_range(name).map(|r| r.map_err(Error::Ods)),
114 }
115 }
116
117 fn worksheet_formula(&mut self, name: &str) -> Option<Result<Range<String>, Self::Error>> {
119 match *self {
120 Sheets::Xls(ref mut e) => e.worksheet_formula(name).map(|r| r.map_err(Error::Xls)),
121 Sheets::Xlsx(ref mut e) => e.worksheet_formula(name).map(|r| r.map_err(Error::Xlsx)),
122 Sheets::Xlsb(ref mut e) => e.worksheet_formula(name).map(|r| r.map_err(Error::Xlsb)),
123 Sheets::Ods(ref mut e) => e.worksheet_formula(name).map(|r| r.map_err(Error::Ods)),
124 }
125 }
126
127 fn worksheets(&mut self) -> Vec<(String, Range<DataType>)> {
128 match *self {
129 Sheets::Xls(ref mut e) => e.worksheets(),
130 Sheets::Xlsx(ref mut e) => e.worksheets(),
131 Sheets::Xlsb(ref mut e) => e.worksheets(),
132 Sheets::Ods(ref mut e) => e.worksheets(),
133 }
134 }
135
136 #[cfg(feature = "picture")]
137 fn pictures(&self) -> Option<Vec<(String, Vec<u8>)>> {
138 match *self {
139 Sheets::Xls(ref e) => e.pictures(),
140 Sheets::Xlsx(ref e) => e.pictures(),
141 Sheets::Xlsb(ref e) => e.pictures(),
142 Sheets::Ods(ref e) => e.pictures(),
143 }
144 }
145}