From 51cacaaa7222343392d9785e26dcc5255d0a7e6f Mon Sep 17 00:00:00 2001 From: Luka Peschke Date: Wed, 13 Dec 2023 14:06:58 +0100 Subject: [PATCH 1/6] feat(datatype): make DataTypeRef public Signed-off-by: Luka Peschke --- src/datatype.rs | 164 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 +- 2 files changed, 165 insertions(+), 2 deletions(-) diff --git a/src/datatype.rs b/src/datatype.rs index f3d508e2..27aa5b29 100644 --- a/src/datatype.rs +++ b/src/datatype.rs @@ -389,6 +389,170 @@ pub enum DataTypeRef<'a> { Empty, } +impl DataTypeRef<'_> { + /// Assess if datatype is empty + pub fn is_empty(&self) -> bool { + *self == DataTypeRef::Empty + } + /// Assess if datatype is a int + pub fn is_int(&self) -> bool { + matches!(*self, DataTypeRef::Int(_)) + } + /// Assess if datatype is a float + pub fn is_float(&self) -> bool { + matches!(*self, DataTypeRef::Float(_)) + } + /// Assess if datatype is a bool + pub fn is_bool(&self) -> bool { + matches!(*self, DataTypeRef::Bool(_)) + } + /// Assess if datatype is a string + pub fn is_string(&self) -> bool { + matches!(*self, DataTypeRef::String(_) | DataTypeRef::SharedString(_)) + } + + /// Try getting int value + pub fn get_int(&self) -> Option { + if let DataTypeRef::Int(v) = self { + Some(*v) + } else { + None + } + } + /// Try getting float value + pub fn get_float(&self) -> Option { + if let DataTypeRef::Float(v) = self { + Some(*v) + } else { + None + } + } + /// Try getting bool value + pub fn get_bool(&self) -> Option { + if let DataTypeRef::Bool(v) = self { + Some(*v) + } else { + None + } + } + /// Try getting string value + pub fn get_string(&self) -> Option<&str> { + match self { + DataTypeRef::String(v) => Some(&**v), + DataTypeRef::SharedString(v) => Some(v), + _ => None, + } + } + + /// Try converting data type into a string + pub fn as_string(&self) -> Option { + match self { + DataTypeRef::Float(v) => Some(v.to_string()), + DataTypeRef::Int(v) => Some(v.to_string()), + DataTypeRef::String(v) => Some(v.clone()), + DataTypeRef::SharedString(v) => Some(v.to_string()), + _ => None, + } + } + /// Try converting data type into an int + pub fn as_i64(&self) -> Option { + match self { + DataTypeRef::Int(v) => Some(*v), + DataTypeRef::Float(v) => Some(*v as i64), + DataTypeRef::String(v) => v.parse::().ok(), + DataTypeRef::SharedString(v) => v.parse::().ok(), + _ => None, + } + } + /// Try converting data type into a float + pub fn as_f64(&self) -> Option { + match self { + DataTypeRef::Int(v) => Some(*v as f64), + DataTypeRef::Float(v) => Some(*v), + DataTypeRef::String(v) => v.parse::().ok(), + DataTypeRef::SharedString(v) => v.parse::().ok(), + _ => None, + } + } + /// Try converting data type into a date + #[cfg(feature = "dates")] + pub fn as_date(&self) -> Option { + use std::str::FromStr; + match self { + DataTypeRef::DateTimeIso(s) => self + .as_datetime() + .map(|dt| dt.date()) + .or_else(|| chrono::NaiveDate::from_str(s).ok()), + _ => self.as_datetime().map(|dt| dt.date()), + } + } + + /// Try converting data type into a time + #[cfg(feature = "dates")] + pub fn as_time(&self) -> Option { + use std::str::FromStr; + match self { + DataTypeRef::DateTimeIso(s) => self + .as_datetime() + .map(|dt| dt.time()) + .or_else(|| chrono::NaiveTime::from_str(s).ok()), + DataTypeRef::DurationIso(s) => { + chrono::NaiveTime::parse_from_str(s, "PT%HH%MM%S%.fS").ok() + } + _ => self.as_datetime().map(|dt| dt.time()), + } + } + + /// Try converting data type into a duration + #[cfg(feature = "dates")] + pub fn as_duration(&self) -> Option { + use chrono::Timelike; + + match self { + DataTypeRef::Duration(days) => { + let ms = days * MS_MULTIPLIER; + Some(chrono::Duration::milliseconds(ms.round() as i64)) + } + // need replace in the future to smth like chrono::Duration::from_str() + // https://github.com/chronotope/chrono/issues/579 + DataTypeRef::DurationIso(_) => self.as_time().map(|t| { + chrono::Duration::nanoseconds( + t.num_seconds_from_midnight() as i64 * 1_000_000_000 + t.nanosecond() as i64, + ) + }), + _ => None, + } + } + + /// Try converting data type into a datetime + #[cfg(feature = "dates")] + pub fn as_datetime(&self) -> Option { + use std::str::FromStr; + + match self { + DataTypeRef::Int(x) => { + let days = x - 25569; + let secs = days * 86400; + chrono::NaiveDateTime::from_timestamp_opt(secs, 0) + } + DataTypeRef::Float(f) | DataTypeRef::DateTime(f) => { + let excel_epoch = EXCEL_EPOCH.get_or_init(|| { + chrono::NaiveDate::from_ymd_opt(1899, 12, 30) + .unwrap() + .and_hms_opt(0, 0, 0) + .unwrap() + }); + let f = if *f >= 60.0 { *f } else { *f + 1.0 }; + let ms = f * MS_MULTIPLIER; + let excel_duration = chrono::Duration::milliseconds(ms.round() as i64); + excel_epoch.checked_add_signed(excel_duration) + } + DataTypeRef::DateTimeIso(s) => chrono::NaiveDateTime::from_str(s).ok(), + _ => None, + } + } +} + impl<'a> From> for DataType { fn from(value: DataTypeRef<'a>) -> Self { match value { diff --git a/src/lib.rs b/src/lib.rs index 6ab55fcf..56fccd75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,7 +73,6 @@ mod de; mod errors; pub mod vba; -use datatype::DataTypeRef; use serde::de::DeserializeOwned; use std::borrow::Cow; use std::cmp::{max, min}; @@ -84,7 +83,7 @@ use std::ops::{Index, IndexMut}; use std::path::Path; pub use crate::auto::{open_workbook_auto, open_workbook_auto_from_rs, Sheets}; -pub use crate::datatype::DataType; +pub use crate::datatype::{DataType, DataTypeRef}; pub use crate::de::{DeError, RangeDeserializer, RangeDeserializerBuilder, ToCellDeserializer}; pub use crate::errors::Error; pub use crate::ods::{Ods, OdsError}; From 96b456103345ad7f7a8c59e2481cb043986e86b2 Mon Sep 17 00:00:00 2001 From: Luka Peschke Date: Wed, 13 Dec 2023 14:21:08 +0100 Subject: [PATCH 2/6] feat: introduce DataTypeTrait Signed-off-by: Luka Peschke --- src/datatype.rs | 170 +++++++++++++++++++++++++++++------------------- src/lib.rs | 2 +- src/ods.rs | 2 +- 3 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/datatype.rs b/src/datatype.rs index 27aa5b29..9336c448 100644 --- a/src/datatype.rs +++ b/src/datatype.rs @@ -40,54 +40,47 @@ pub enum DataType { Empty, } -impl DataType { - /// Assess if datatype is empty - pub fn is_empty(&self) -> bool { +/// An enum to represent all different data types that can appear as +/// a value in a worksheet cell +impl DataTypeTrait for DataType { + fn is_empty(&self) -> bool { *self == DataType::Empty } - /// Assess if datatype is a int - pub fn is_int(&self) -> bool { + fn is_int(&self) -> bool { matches!(*self, DataType::Int(_)) } - /// Assess if datatype is a float - pub fn is_float(&self) -> bool { + fn is_float(&self) -> bool { matches!(*self, DataType::Float(_)) } - /// Assess if datatype is a bool - pub fn is_bool(&self) -> bool { + fn is_bool(&self) -> bool { matches!(*self, DataType::Bool(_)) } - /// Assess if datatype is a string - pub fn is_string(&self) -> bool { + fn is_string(&self) -> bool { matches!(*self, DataType::String(_)) } - /// Try getting int value - pub fn get_int(&self) -> Option { + fn get_int(&self) -> Option { if let DataType::Int(v) = self { Some(*v) } else { None } } - /// Try getting float value - pub fn get_float(&self) -> Option { + fn get_float(&self) -> Option { if let DataType::Float(v) = self { Some(*v) } else { None } } - /// Try getting bool value - pub fn get_bool(&self) -> Option { + fn get_bool(&self) -> Option { if let DataType::Bool(v) = self { Some(*v) } else { None } } - /// Try getting string value - pub fn get_string(&self) -> Option<&str> { + fn get_string(&self) -> Option<&str> { if let DataType::String(v) = self { Some(&**v) } else { @@ -95,8 +88,7 @@ impl DataType { } } - /// Try converting data type into a string - pub fn as_string(&self) -> Option { + fn as_string(&self) -> Option { match self { DataType::Float(v) => Some(v.to_string()), DataType::Int(v) => Some(v.to_string()), @@ -104,8 +96,8 @@ impl DataType { _ => None, } } - /// Try converting data type into an int - pub fn as_i64(&self) -> Option { + + fn as_i64(&self) -> Option { match self { DataType::Int(v) => Some(*v), DataType::Float(v) => Some(*v as i64), @@ -113,8 +105,8 @@ impl DataType { _ => None, } } - /// Try converting data type into a float - pub fn as_f64(&self) -> Option { + + fn as_f64(&self) -> Option { match self { DataType::Int(v) => Some(*v as f64), DataType::Float(v) => Some(*v), @@ -122,9 +114,8 @@ impl DataType { _ => None, } } - /// Try converting data type into a date #[cfg(feature = "dates")] - pub fn as_date(&self) -> Option { + fn as_date(&self) -> Option { use std::str::FromStr; match self { DataType::DateTimeIso(s) => self @@ -135,9 +126,8 @@ impl DataType { } } - /// Try converting data type into a time #[cfg(feature = "dates")] - pub fn as_time(&self) -> Option { + fn as_time(&self) -> Option { use std::str::FromStr; match self { DataType::DateTimeIso(s) => self @@ -149,9 +139,8 @@ impl DataType { } } - /// Try converting data type into a duration #[cfg(feature = "dates")] - pub fn as_duration(&self) -> Option { + fn as_duration(&self) -> Option { use chrono::Timelike; match self { @@ -170,9 +159,8 @@ impl DataType { } } - /// Try converting data type into a datetime #[cfg(feature = "dates")] - pub fn as_datetime(&self) -> Option { + fn as_datetime(&self) -> Option { use std::str::FromStr; match self { @@ -389,54 +377,52 @@ pub enum DataTypeRef<'a> { Empty, } -impl DataTypeRef<'_> { - /// Assess if datatype is empty - pub fn is_empty(&self) -> bool { +impl DataTypeTrait for DataTypeRef<'_> { + fn is_empty(&self) -> bool { *self == DataTypeRef::Empty } - /// Assess if datatype is a int - pub fn is_int(&self) -> bool { + + fn is_int(&self) -> bool { matches!(*self, DataTypeRef::Int(_)) } - /// Assess if datatype is a float - pub fn is_float(&self) -> bool { + + fn is_float(&self) -> bool { matches!(*self, DataTypeRef::Float(_)) } - /// Assess if datatype is a bool - pub fn is_bool(&self) -> bool { + + fn is_bool(&self) -> bool { matches!(*self, DataTypeRef::Bool(_)) } - /// Assess if datatype is a string - pub fn is_string(&self) -> bool { + + fn is_string(&self) -> bool { matches!(*self, DataTypeRef::String(_) | DataTypeRef::SharedString(_)) } - /// Try getting int value - pub fn get_int(&self) -> Option { + fn get_int(&self) -> Option { if let DataTypeRef::Int(v) = self { Some(*v) } else { None } } - /// Try getting float value - pub fn get_float(&self) -> Option { + + fn get_float(&self) -> Option { if let DataTypeRef::Float(v) = self { Some(*v) } else { None } } - /// Try getting bool value - pub fn get_bool(&self) -> Option { + + fn get_bool(&self) -> Option { if let DataTypeRef::Bool(v) = self { Some(*v) } else { None } } - /// Try getting string value - pub fn get_string(&self) -> Option<&str> { + + fn get_string(&self) -> Option<&str> { match self { DataTypeRef::String(v) => Some(&**v), DataTypeRef::SharedString(v) => Some(v), @@ -444,8 +430,7 @@ impl DataTypeRef<'_> { } } - /// Try converting data type into a string - pub fn as_string(&self) -> Option { + fn as_string(&self) -> Option { match self { DataTypeRef::Float(v) => Some(v.to_string()), DataTypeRef::Int(v) => Some(v.to_string()), @@ -454,8 +439,8 @@ impl DataTypeRef<'_> { _ => None, } } - /// Try converting data type into an int - pub fn as_i64(&self) -> Option { + + fn as_i64(&self) -> Option { match self { DataTypeRef::Int(v) => Some(*v), DataTypeRef::Float(v) => Some(*v as i64), @@ -464,8 +449,8 @@ impl DataTypeRef<'_> { _ => None, } } - /// Try converting data type into a float - pub fn as_f64(&self) -> Option { + + fn as_f64(&self) -> Option { match self { DataTypeRef::Int(v) => Some(*v as f64), DataTypeRef::Float(v) => Some(*v), @@ -474,9 +459,9 @@ impl DataTypeRef<'_> { _ => None, } } - /// Try converting data type into a date + #[cfg(feature = "dates")] - pub fn as_date(&self) -> Option { + fn as_date(&self) -> Option { use std::str::FromStr; match self { DataTypeRef::DateTimeIso(s) => self @@ -487,9 +472,8 @@ impl DataTypeRef<'_> { } } - /// Try converting data type into a time #[cfg(feature = "dates")] - pub fn as_time(&self) -> Option { + fn as_time(&self) -> Option { use std::str::FromStr; match self { DataTypeRef::DateTimeIso(s) => self @@ -503,9 +487,8 @@ impl DataTypeRef<'_> { } } - /// Try converting data type into a duration #[cfg(feature = "dates")] - pub fn as_duration(&self) -> Option { + fn as_duration(&self) -> Option { use chrono::Timelike; match self { @@ -524,9 +507,8 @@ impl DataTypeRef<'_> { } } - /// Try converting data type into a datetime #[cfg(feature = "dates")] - pub fn as_datetime(&self) -> Option { + fn as_datetime(&self) -> Option { use std::str::FromStr; match self { @@ -553,6 +535,62 @@ impl DataTypeRef<'_> { } } +/// A trait to represent all different data types that can appear as +/// a value in a worksheet cell +pub trait DataTypeTrait { + /// Assess if datatype is empty + fn is_empty(&self) -> bool; + + /// Assess if datatype is a int + fn is_int(&self) -> bool; + + /// Assess if datatype is a float + fn is_float(&self) -> bool; + + /// Assess if datatype is a bool + fn is_bool(&self) -> bool; + + /// Assess if datatype is a string + fn is_string(&self) -> bool; + + /// Try getting int value + fn get_int(&self) -> Option; + + /// Try getting float value + fn get_float(&self) -> Option; + + /// Try getting bool value + fn get_bool(&self) -> Option; + + /// Try getting string value + fn get_string(&self) -> Option<&str>; + + /// Try converting data type into a string + fn as_string(&self) -> Option; + + /// Try converting data type into an int + fn as_i64(&self) -> Option; + + /// Try converting data type into a float + fn as_f64(&self) -> Option; + + /// Try converting data type into a date + #[cfg(feature = "dates")] + fn as_date(&self) -> Option; + + /// Try converting data type into a time + #[cfg(feature = "dates")] + fn as_time(&self) -> Option; + + /// Try converting data type into a duration + #[cfg(feature = "dates")] + fn as_duration(&self) -> Option; + + /// Try converting data type into a datetime + #[cfg(feature = "dates")] + fn as_datetime(&self) -> Option; +} + impl<'a> From> for DataType { fn from(value: DataTypeRef<'a>) -> Self { match value { diff --git a/src/lib.rs b/src/lib.rs index 56fccd75..c811ecc9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,7 +83,7 @@ use std::ops::{Index, IndexMut}; use std::path::Path; pub use crate::auto::{open_workbook_auto, open_workbook_auto_from_rs, Sheets}; -pub use crate::datatype::{DataType, DataTypeRef}; +pub use crate::datatype::{DataType, DataTypeRef, DataTypeTrait}; pub use crate::de::{DeError, RangeDeserializer, RangeDeserializerBuilder, ToCellDeserializer}; pub use crate::errors::Error; pub use crate::ods::{Ods, OdsError}; diff --git a/src/ods.rs b/src/ods.rs index 45c436d2..3cec3ed3 100644 --- a/src/ods.rs +++ b/src/ods.rs @@ -16,7 +16,7 @@ use zip::read::{ZipArchive, ZipFile}; use zip::result::ZipError; use crate::vba::VbaProject; -use crate::{DataType, Metadata, Range, Reader, Sheet, SheetType, SheetVisible}; +use crate::{DataType, DataTypeTrait, Metadata, Range, Reader, Sheet, SheetType, SheetVisible}; use std::marker::PhantomData; const MIMETYPE: &[u8] = b"application/vnd.oasis.opendocument.spreadsheet"; From 6ceb976a07bcbbbf17880b0a455f35be395e1193 Mon Sep 17 00:00:00 2001 From: Luka Peschke Date: Wed, 13 Dec 2023 14:36:22 +0100 Subject: [PATCH 3/6] feat: introduce is_x methods for date and time variants --- src/datatype.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/test.rs | 3 ++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/datatype.rs b/src/datatype.rs index 9336c448..fd1ba7ba 100644 --- a/src/datatype.rs +++ b/src/datatype.rs @@ -59,6 +59,26 @@ impl DataTypeTrait for DataType { matches!(*self, DataType::String(_)) } + #[cfg(feature = "dates")] + fn is_duration(&self) -> bool { + matches!(*self, DataType::Duration(_)) + } + + #[cfg(feature = "dates")] + fn is_duration_iso(&self) -> bool { + matches!(*self, DataType::DurationIso(_)) + } + + #[cfg(feature = "dates")] + fn is_datetime(&self) -> bool { + matches!(*self, DataType::DateTime(_)) + } + + #[cfg(feature = "dates")] + fn is_datetime_iso(&self) -> bool { + matches!(*self, DataType::DateTimeIso(_)) + } + fn get_int(&self) -> Option { if let DataType::Int(v) = self { Some(*v) @@ -398,6 +418,26 @@ impl DataTypeTrait for DataTypeRef<'_> { matches!(*self, DataTypeRef::String(_) | DataTypeRef::SharedString(_)) } + #[cfg(feature = "dates")] + fn is_duration(&self) -> bool { + matches!(*self, DataTypeRef::Duration(_)) + } + + #[cfg(feature = "dates")] + fn is_duration_iso(&self) -> bool { + matches!(*self, DataTypeRef::DurationIso(_)) + } + + #[cfg(feature = "dates")] + fn is_datetime(&self) -> bool { + matches!(*self, DataTypeRef::DateTime(_)) + } + + #[cfg(feature = "dates")] + fn is_datetime_iso(&self) -> bool { + matches!(*self, DataTypeRef::DateTimeIso(_)) + } + fn get_int(&self) -> Option { if let DataTypeRef::Int(v) = self { Some(*v) @@ -553,6 +593,22 @@ pub trait DataTypeTrait { /// Assess if datatype is a string fn is_string(&self) -> bool; + /// Assess if datatype is a duration + #[cfg(feature = "dates")] + fn is_duration(&self) -> bool; + + /// Assess if datatype is an ISO8601 duration + #[cfg(feature = "dates")] + fn is_duration_iso(&self) -> bool; + + /// Assess if datatype is a datetime + #[cfg(feature = "dates")] + fn is_datetime(&self) -> bool; + + /// Assess if datatype is an ISO8601 datetime + #[cfg(feature = "dates")] + fn is_datetime_iso(&self) -> bool; + /// Try getting int value fn get_int(&self) -> Option; diff --git a/tests/test.rs b/tests/test.rs index 5f317f23..446098e0 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -2,7 +2,8 @@ use calamine::DataType::{ Bool, DateTime, DateTimeIso, Duration, DurationIso, Empty, Error, Float, String, }; use calamine::{ - open_workbook, open_workbook_auto, Ods, Reader, Sheet, SheetType, SheetVisible, Xls, Xlsb, Xlsx, + open_workbook, open_workbook_auto, DataTypeTrait, Ods, Reader, Sheet, SheetType, SheetVisible, + Xls, Xlsb, Xlsx, }; use calamine::{CellErrorType::*, DataType}; use std::io::Cursor; From 6d2b17f20305d484558f0436bd563a46a96fc6c4 Mon Sep 17 00:00:00 2001 From: Luka Peschke Date: Mon, 15 Jan 2024 09:42:18 +0100 Subject: [PATCH 4/6] refactor: rename according to @tafia's comment Rename the following: * DataTypeTrait -> DataType * DataType -> Data * DataTypeRef -> DataRef Signed-off-by: Luka Peschke --- examples/excel_to_csv.rs | 20 +-- examples/search_errors.rs | 4 +- src/auto.rs | 6 +- src/datatype.rs | 302 +++++++++++++++++++------------------- src/de.rs | 120 +++++++-------- src/formats.rs | 20 +-- src/lib.rs | 48 +++--- src/ods.rs | 34 ++--- src/xls.rs | 56 +++---- src/xlsb/cells_reader.rs | 18 +-- src/xlsb/mod.rs | 12 +- src/xlsx/cells_reader.rs | 32 ++-- src/xlsx/mod.rs | 14 +- tests/test.rs | 34 ++--- 14 files changed, 360 insertions(+), 360 deletions(-) diff --git a/examples/excel_to_csv.rs b/examples/excel_to_csv.rs index da68fcc3..2c595ce3 100644 --- a/examples/excel_to_csv.rs +++ b/examples/excel_to_csv.rs @@ -1,4 +1,4 @@ -use calamine::{open_workbook_auto, DataType, Range, Reader}; +use calamine::{open_workbook_auto, Data, Range, Reader}; use std::env; use std::fs::File; use std::io::{BufWriter, Write}; @@ -29,21 +29,21 @@ fn main() { write_range(&mut dest, &range).unwrap(); } -fn write_range(dest: &mut W, range: &Range) -> std::io::Result<()> { +fn write_range(dest: &mut W, range: &Range) -> std::io::Result<()> { let n = range.get_size().1 - 1; for r in range.rows() { for (i, c) in r.iter().enumerate() { match *c { - DataType::Empty => Ok(()), - DataType::String(ref s) - | DataType::DateTimeIso(ref s) - | DataType::DurationIso(ref s) => write!(dest, "{}", s), - DataType::Float(ref f) | DataType::DateTime(ref f) | DataType::Duration(ref f) => { + Data::Empty => Ok(()), + Data::String(ref s) | Data::DateTimeIso(ref s) | Data::DurationIso(ref s) => { + write!(dest, "{}", s) + } + Data::Float(ref f) | Data::DateTime(ref f) | Data::Duration(ref f) => { write!(dest, "{}", f) } - DataType::Int(ref i) => write!(dest, "{}", i), - DataType::Error(ref e) => write!(dest, "{:?}", e), - DataType::Bool(ref b) => write!(dest, "{}", b), + Data::Int(ref i) => write!(dest, "{}", i), + Data::Error(ref e) => write!(dest, "{:?}", e), + Data::Bool(ref b) => write!(dest, "{}", b), }?; if i != n { write!(dest, ";")?; diff --git a/examples/search_errors.rs b/examples/search_errors.rs index 2b068022..08a6b18a 100644 --- a/examples/search_errors.rs +++ b/examples/search_errors.rs @@ -3,7 +3,7 @@ use std::fs::File; use std::io::{BufWriter, Write}; use std::path::PathBuf; -use calamine::{open_workbook_auto, DataType, Error, Reader}; +use calamine::{open_workbook_auto, Data, Error, Reader}; use glob::{glob, GlobError, GlobResult}; #[derive(Debug)] @@ -79,7 +79,7 @@ fn run(f: GlobResult) -> Result<(PathBuf, Option, usize), FileStatus> { .rows() .flat_map(|r| { r.iter().filter(|c| { - if let DataType::Error(_) = **c { + if let Data::Error(_) = **c { true } else { false diff --git a/src/auto.rs b/src/auto.rs index 61f14d60..e2dad5d9 100644 --- a/src/auto.rs +++ b/src/auto.rs @@ -3,7 +3,7 @@ use crate::errors::Error; use crate::vba::VbaProject; use crate::{ - open_workbook, open_workbook_from_rs, DataType, Metadata, Ods, Range, Reader, Xls, Xlsb, Xlsx, + open_workbook, open_workbook_from_rs, Data, Metadata, Ods, Range, Reader, Xls, Xlsb, Xlsx, }; use std::borrow::Cow; use std::fs::File; @@ -105,7 +105,7 @@ where } /// Read worksheet data in corresponding worksheet path - fn worksheet_range(&mut self, name: &str) -> Result, Self::Error> { + fn worksheet_range(&mut self, name: &str) -> Result, Self::Error> { match *self { Sheets::Xls(ref mut e) => e.worksheet_range(name).map_err(Error::Xls), Sheets::Xlsx(ref mut e) => e.worksheet_range(name).map_err(Error::Xlsx), @@ -124,7 +124,7 @@ where } } - fn worksheets(&mut self) -> Vec<(String, Range)> { + fn worksheets(&mut self) -> Vec<(String, Range)> { match *self { Sheets::Xls(ref mut e) => e.worksheets(), Sheets::Xlsx(ref mut e) => e.worksheets(), diff --git a/src/datatype.rs b/src/datatype.rs index fd1ba7ba..a2cc842a 100644 --- a/src/datatype.rs +++ b/src/datatype.rs @@ -16,7 +16,7 @@ const MS_MULTIPLIER: f64 = 24f64 * 60f64 * 60f64 * 1e+3f64; /// An enum to represent all different data types that can appear as /// a value in a worksheet cell #[derive(Debug, Clone, PartialEq, Default)] -pub enum DataType { +pub enum Data { /// Signed integer Int(i64), /// Float @@ -42,66 +42,66 @@ pub enum DataType { /// An enum to represent all different data types that can appear as /// a value in a worksheet cell -impl DataTypeTrait for DataType { +impl DataType for Data { fn is_empty(&self) -> bool { - *self == DataType::Empty + *self == Data::Empty } fn is_int(&self) -> bool { - matches!(*self, DataType::Int(_)) + matches!(*self, Data::Int(_)) } fn is_float(&self) -> bool { - matches!(*self, DataType::Float(_)) + matches!(*self, Data::Float(_)) } fn is_bool(&self) -> bool { - matches!(*self, DataType::Bool(_)) + matches!(*self, Data::Bool(_)) } fn is_string(&self) -> bool { - matches!(*self, DataType::String(_)) + matches!(*self, Data::String(_)) } #[cfg(feature = "dates")] fn is_duration(&self) -> bool { - matches!(*self, DataType::Duration(_)) + matches!(*self, Data::Duration(_)) } #[cfg(feature = "dates")] fn is_duration_iso(&self) -> bool { - matches!(*self, DataType::DurationIso(_)) + matches!(*self, Data::DurationIso(_)) } #[cfg(feature = "dates")] fn is_datetime(&self) -> bool { - matches!(*self, DataType::DateTime(_)) + matches!(*self, Data::DateTime(_)) } #[cfg(feature = "dates")] fn is_datetime_iso(&self) -> bool { - matches!(*self, DataType::DateTimeIso(_)) + matches!(*self, Data::DateTimeIso(_)) } fn get_int(&self) -> Option { - if let DataType::Int(v) = self { + if let Data::Int(v) = self { Some(*v) } else { None } } fn get_float(&self) -> Option { - if let DataType::Float(v) = self { + if let Data::Float(v) = self { Some(*v) } else { None } } fn get_bool(&self) -> Option { - if let DataType::Bool(v) = self { + if let Data::Bool(v) = self { Some(*v) } else { None } } fn get_string(&self) -> Option<&str> { - if let DataType::String(v) = self { + if let Data::String(v) = self { Some(&**v) } else { None @@ -110,27 +110,27 @@ impl DataTypeTrait for DataType { fn as_string(&self) -> Option { match self { - DataType::Float(v) => Some(v.to_string()), - DataType::Int(v) => Some(v.to_string()), - DataType::String(v) => Some(v.clone()), + Data::Float(v) => Some(v.to_string()), + Data::Int(v) => Some(v.to_string()), + Data::String(v) => Some(v.clone()), _ => None, } } fn as_i64(&self) -> Option { match self { - DataType::Int(v) => Some(*v), - DataType::Float(v) => Some(*v as i64), - DataType::String(v) => v.parse::().ok(), + Data::Int(v) => Some(*v), + Data::Float(v) => Some(*v as i64), + Data::String(v) => v.parse::().ok(), _ => None, } } fn as_f64(&self) -> Option { match self { - DataType::Int(v) => Some(*v as f64), - DataType::Float(v) => Some(*v), - DataType::String(v) => v.parse::().ok(), + Data::Int(v) => Some(*v as f64), + Data::Float(v) => Some(*v), + Data::String(v) => v.parse::().ok(), _ => None, } } @@ -138,7 +138,7 @@ impl DataTypeTrait for DataType { fn as_date(&self) -> Option { use std::str::FromStr; match self { - DataType::DateTimeIso(s) => self + Data::DateTimeIso(s) => self .as_datetime() .map(|dt| dt.date()) .or_else(|| chrono::NaiveDate::from_str(s).ok()), @@ -150,11 +150,11 @@ impl DataTypeTrait for DataType { fn as_time(&self) -> Option { use std::str::FromStr; match self { - DataType::DateTimeIso(s) => self + Data::DateTimeIso(s) => self .as_datetime() .map(|dt| dt.time()) .or_else(|| chrono::NaiveTime::from_str(s).ok()), - DataType::DurationIso(s) => chrono::NaiveTime::parse_from_str(s, "PT%HH%MM%S%.fS").ok(), + Data::DurationIso(s) => chrono::NaiveTime::parse_from_str(s, "PT%HH%MM%S%.fS").ok(), _ => self.as_datetime().map(|dt| dt.time()), } } @@ -164,13 +164,13 @@ impl DataTypeTrait for DataType { use chrono::Timelike; match self { - DataType::Duration(days) => { + Data::Duration(days) => { let ms = days * MS_MULTIPLIER; Some(chrono::Duration::milliseconds(ms.round() as i64)) } // need replace in the future to smth like chrono::Duration::from_str() // https://github.com/chronotope/chrono/issues/579 - DataType::DurationIso(_) => self.as_time().map(|t| { + Data::DurationIso(_) => self.as_time().map(|t| { chrono::Duration::nanoseconds( t.num_seconds_from_midnight() as i64 * 1_000_000_000 + t.nanosecond() as i64, ) @@ -184,12 +184,12 @@ impl DataTypeTrait for DataType { use std::str::FromStr; match self { - DataType::Int(x) => { + Data::Int(x) => { let days = x - 25569; let secs = days * 86400; chrono::NaiveDateTime::from_timestamp_opt(secs, 0) } - DataType::Float(f) | DataType::DateTime(f) => { + Data::Float(f) | Data::DateTime(f) => { let excel_epoch = EXCEL_EPOCH.get_or_init(|| { chrono::NaiveDate::from_ymd_opt(1899, 12, 30) .unwrap() @@ -201,99 +201,99 @@ impl DataTypeTrait for DataType { let excel_duration = chrono::Duration::milliseconds(ms.round() as i64); excel_epoch.checked_add_signed(excel_duration) } - DataType::DateTimeIso(s) => chrono::NaiveDateTime::from_str(s).ok(), + Data::DateTimeIso(s) => chrono::NaiveDateTime::from_str(s).ok(), _ => None, } } } -impl PartialEq<&str> for DataType { +impl PartialEq<&str> for Data { fn eq(&self, other: &&str) -> bool { match *self { - DataType::String(ref s) if s == other => true, + Data::String(ref s) if s == other => true, _ => false, } } } -impl PartialEq for DataType { +impl PartialEq for Data { fn eq(&self, other: &str) -> bool { - matches!(*self, DataType::String(ref s) if s == other) + matches!(*self, Data::String(ref s) if s == other) } } -impl PartialEq for DataType { +impl PartialEq for Data { fn eq(&self, other: &f64) -> bool { - matches!(*self, DataType::Float(ref s) if *s == *other) + matches!(*self, Data::Float(ref s) if *s == *other) } } -impl PartialEq for DataType { +impl PartialEq for Data { fn eq(&self, other: &bool) -> bool { - matches!(*self, DataType::Bool(ref s) if *s == *other) + matches!(*self, Data::Bool(ref s) if *s == *other) } } -impl PartialEq for DataType { +impl PartialEq for Data { fn eq(&self, other: &i64) -> bool { - matches!(*self, DataType::Int(ref s) if *s == *other) + matches!(*self, Data::Int(ref s) if *s == *other) } } -impl fmt::Display for DataType { +impl fmt::Display for Data { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> { match *self { - DataType::Int(ref e) => write!(f, "{}", e), - DataType::Float(ref e) => write!(f, "{}", e), - DataType::String(ref e) => write!(f, "{}", e), - DataType::Bool(ref e) => write!(f, "{}", e), - DataType::DateTime(ref e) => write!(f, "{}", e), - DataType::Duration(ref e) => write!(f, "{}", e), - DataType::DateTimeIso(ref e) => write!(f, "{}", e), - DataType::DurationIso(ref e) => write!(f, "{}", e), - DataType::Error(ref e) => write!(f, "{}", e), - DataType::Empty => Ok(()), + Data::Int(ref e) => write!(f, "{}", e), + Data::Float(ref e) => write!(f, "{}", e), + Data::String(ref e) => write!(f, "{}", e), + Data::Bool(ref e) => write!(f, "{}", e), + Data::DateTime(ref e) => write!(f, "{}", e), + Data::Duration(ref e) => write!(f, "{}", e), + Data::DateTimeIso(ref e) => write!(f, "{}", e), + Data::DurationIso(ref e) => write!(f, "{}", e), + Data::Error(ref e) => write!(f, "{}", e), + Data::Empty => Ok(()), } } } -impl<'de> Deserialize<'de> for DataType { +impl<'de> Deserialize<'de> for Data { #[inline] - fn deserialize(deserializer: D) -> Result + fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { - struct DataTypeVisitor; + struct DataVisitor; - impl<'de> Visitor<'de> for DataTypeVisitor { - type Value = DataType; + impl<'de> Visitor<'de> for DataVisitor { + type Value = Data; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("any valid JSON value") } #[inline] - fn visit_bool(self, value: bool) -> Result { - Ok(DataType::Bool(value)) + fn visit_bool(self, value: bool) -> Result { + Ok(Data::Bool(value)) } #[inline] - fn visit_i64(self, value: i64) -> Result { - Ok(DataType::Int(value)) + fn visit_i64(self, value: i64) -> Result { + Ok(Data::Int(value)) } #[inline] - fn visit_u64(self, value: u64) -> Result { - Ok(DataType::Int(value as i64)) + fn visit_u64(self, value: u64) -> Result { + Ok(Data::Int(value as i64)) } #[inline] - fn visit_f64(self, value: f64) -> Result { - Ok(DataType::Float(value)) + fn visit_f64(self, value: f64) -> Result { + Ok(Data::Float(value)) } #[inline] - fn visit_str(self, value: &str) -> Result + fn visit_str(self, value: &str) -> Result where E: serde::de::Error, { @@ -301,17 +301,17 @@ impl<'de> Deserialize<'de> for DataType { } #[inline] - fn visit_string(self, value: String) -> Result { - Ok(DataType::String(value)) + fn visit_string(self, value: String) -> Result { + Ok(Data::String(value)) } #[inline] - fn visit_none(self) -> Result { - Ok(DataType::Empty) + fn visit_none(self) -> Result { + Ok(Data::Empty) } #[inline] - fn visit_some(self, deserializer: D) -> Result + fn visit_some(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { @@ -319,18 +319,18 @@ impl<'de> Deserialize<'de> for DataType { } #[inline] - fn visit_unit(self) -> Result { - Ok(DataType::Empty) + fn visit_unit(self) -> Result { + Ok(Data::Empty) } } - deserializer.deserialize_any(DataTypeVisitor) + deserializer.deserialize_any(DataVisitor) } } macro_rules! define_from { ($variant:path, $ty:ty) => { - impl From<$ty> for DataType { + impl From<$ty> for Data { fn from(v: $ty) -> Self { $variant(v) } @@ -338,32 +338,32 @@ macro_rules! define_from { }; } -define_from!(DataType::Int, i64); -define_from!(DataType::Float, f64); -define_from!(DataType::String, String); -define_from!(DataType::Bool, bool); -define_from!(DataType::Error, CellErrorType); +define_from!(Data::Int, i64); +define_from!(Data::Float, f64); +define_from!(Data::String, String); +define_from!(Data::Bool, bool); +define_from!(Data::Error, CellErrorType); -impl<'a> From<&'a str> for DataType { +impl<'a> From<&'a str> for Data { fn from(v: &'a str) -> Self { - DataType::String(String::from(v)) + Data::String(String::from(v)) } } -impl From<()> for DataType { +impl From<()> for Data { fn from(_: ()) -> Self { - DataType::Empty + Data::Empty } } -impl From> for DataType +impl From> for Data where - DataType: From, + Data: From, { fn from(v: Option) -> Self { match v { Some(v) => From::from(v), - None => DataType::Empty, + None => Data::Empty, } } } @@ -371,7 +371,7 @@ where /// An enum to represent all different data types that can appear as /// a value in a worksheet cell #[derive(Debug, Clone, PartialEq, Default)] -pub enum DataTypeRef<'a> { +pub enum DataRef<'a> { /// Signed integer Int(i64), /// Float @@ -397,49 +397,49 @@ pub enum DataTypeRef<'a> { Empty, } -impl DataTypeTrait for DataTypeRef<'_> { +impl DataType for DataRef<'_> { fn is_empty(&self) -> bool { - *self == DataTypeRef::Empty + *self == DataRef::Empty } fn is_int(&self) -> bool { - matches!(*self, DataTypeRef::Int(_)) + matches!(*self, DataRef::Int(_)) } fn is_float(&self) -> bool { - matches!(*self, DataTypeRef::Float(_)) + matches!(*self, DataRef::Float(_)) } fn is_bool(&self) -> bool { - matches!(*self, DataTypeRef::Bool(_)) + matches!(*self, DataRef::Bool(_)) } fn is_string(&self) -> bool { - matches!(*self, DataTypeRef::String(_) | DataTypeRef::SharedString(_)) + matches!(*self, DataRef::String(_) | DataRef::SharedString(_)) } #[cfg(feature = "dates")] fn is_duration(&self) -> bool { - matches!(*self, DataTypeRef::Duration(_)) + matches!(*self, DataRef::Duration(_)) } #[cfg(feature = "dates")] fn is_duration_iso(&self) -> bool { - matches!(*self, DataTypeRef::DurationIso(_)) + matches!(*self, DataRef::DurationIso(_)) } #[cfg(feature = "dates")] fn is_datetime(&self) -> bool { - matches!(*self, DataTypeRef::DateTime(_)) + matches!(*self, DataRef::DateTime(_)) } #[cfg(feature = "dates")] fn is_datetime_iso(&self) -> bool { - matches!(*self, DataTypeRef::DateTimeIso(_)) + matches!(*self, DataRef::DateTimeIso(_)) } fn get_int(&self) -> Option { - if let DataTypeRef::Int(v) = self { + if let DataRef::Int(v) = self { Some(*v) } else { None @@ -447,7 +447,7 @@ impl DataTypeTrait for DataTypeRef<'_> { } fn get_float(&self) -> Option { - if let DataTypeRef::Float(v) = self { + if let DataRef::Float(v) = self { Some(*v) } else { None @@ -455,7 +455,7 @@ impl DataTypeTrait for DataTypeRef<'_> { } fn get_bool(&self) -> Option { - if let DataTypeRef::Bool(v) = self { + if let DataRef::Bool(v) = self { Some(*v) } else { None @@ -464,38 +464,38 @@ impl DataTypeTrait for DataTypeRef<'_> { fn get_string(&self) -> Option<&str> { match self { - DataTypeRef::String(v) => Some(&**v), - DataTypeRef::SharedString(v) => Some(v), + DataRef::String(v) => Some(&**v), + DataRef::SharedString(v) => Some(v), _ => None, } } fn as_string(&self) -> Option { match self { - DataTypeRef::Float(v) => Some(v.to_string()), - DataTypeRef::Int(v) => Some(v.to_string()), - DataTypeRef::String(v) => Some(v.clone()), - DataTypeRef::SharedString(v) => Some(v.to_string()), + DataRef::Float(v) => Some(v.to_string()), + DataRef::Int(v) => Some(v.to_string()), + DataRef::String(v) => Some(v.clone()), + DataRef::SharedString(v) => Some(v.to_string()), _ => None, } } fn as_i64(&self) -> Option { match self { - DataTypeRef::Int(v) => Some(*v), - DataTypeRef::Float(v) => Some(*v as i64), - DataTypeRef::String(v) => v.parse::().ok(), - DataTypeRef::SharedString(v) => v.parse::().ok(), + DataRef::Int(v) => Some(*v), + DataRef::Float(v) => Some(*v as i64), + DataRef::String(v) => v.parse::().ok(), + DataRef::SharedString(v) => v.parse::().ok(), _ => None, } } fn as_f64(&self) -> Option { match self { - DataTypeRef::Int(v) => Some(*v as f64), - DataTypeRef::Float(v) => Some(*v), - DataTypeRef::String(v) => v.parse::().ok(), - DataTypeRef::SharedString(v) => v.parse::().ok(), + DataRef::Int(v) => Some(*v as f64), + DataRef::Float(v) => Some(*v), + DataRef::String(v) => v.parse::().ok(), + DataRef::SharedString(v) => v.parse::().ok(), _ => None, } } @@ -504,7 +504,7 @@ impl DataTypeTrait for DataTypeRef<'_> { fn as_date(&self) -> Option { use std::str::FromStr; match self { - DataTypeRef::DateTimeIso(s) => self + DataRef::DateTimeIso(s) => self .as_datetime() .map(|dt| dt.date()) .or_else(|| chrono::NaiveDate::from_str(s).ok()), @@ -516,11 +516,11 @@ impl DataTypeTrait for DataTypeRef<'_> { fn as_time(&self) -> Option { use std::str::FromStr; match self { - DataTypeRef::DateTimeIso(s) => self + DataRef::DateTimeIso(s) => self .as_datetime() .map(|dt| dt.time()) .or_else(|| chrono::NaiveTime::from_str(s).ok()), - DataTypeRef::DurationIso(s) => { + DataRef::DurationIso(s) => { chrono::NaiveTime::parse_from_str(s, "PT%HH%MM%S%.fS").ok() } _ => self.as_datetime().map(|dt| dt.time()), @@ -532,13 +532,13 @@ impl DataTypeTrait for DataTypeRef<'_> { use chrono::Timelike; match self { - DataTypeRef::Duration(days) => { + DataRef::Duration(days) => { let ms = days * MS_MULTIPLIER; Some(chrono::Duration::milliseconds(ms.round() as i64)) } // need replace in the future to smth like chrono::Duration::from_str() // https://github.com/chronotope/chrono/issues/579 - DataTypeRef::DurationIso(_) => self.as_time().map(|t| { + DataRef::DurationIso(_) => self.as_time().map(|t| { chrono::Duration::nanoseconds( t.num_seconds_from_midnight() as i64 * 1_000_000_000 + t.nanosecond() as i64, ) @@ -552,12 +552,12 @@ impl DataTypeTrait for DataTypeRef<'_> { use std::str::FromStr; match self { - DataTypeRef::Int(x) => { + DataRef::Int(x) => { let days = x - 25569; let secs = days * 86400; chrono::NaiveDateTime::from_timestamp_opt(secs, 0) } - DataTypeRef::Float(f) | DataTypeRef::DateTime(f) => { + DataRef::Float(f) | DataRef::DateTime(f) => { let excel_epoch = EXCEL_EPOCH.get_or_init(|| { chrono::NaiveDate::from_ymd_opt(1899, 12, 30) .unwrap() @@ -569,7 +569,7 @@ impl DataTypeTrait for DataTypeRef<'_> { let excel_duration = chrono::Duration::milliseconds(ms.round() as i64); excel_epoch.checked_add_signed(excel_duration) } - DataTypeRef::DateTimeIso(s) => chrono::NaiveDateTime::from_str(s).ok(), + DataRef::DateTimeIso(s) => chrono::NaiveDateTime::from_str(s).ok(), _ => None, } } @@ -577,7 +577,7 @@ impl DataTypeTrait for DataTypeRef<'_> { /// A trait to represent all different data types that can appear as /// a value in a worksheet cell -pub trait DataTypeTrait { +pub trait DataType { /// Assess if datatype is empty fn is_empty(&self) -> bool; @@ -647,20 +647,20 @@ pub trait DataTypeTrait { fn as_datetime(&self) -> Option; } -impl<'a> From> for DataType { - fn from(value: DataTypeRef<'a>) -> Self { +impl<'a> From> for Data { + fn from(value: DataRef<'a>) -> Self { match value { - DataTypeRef::Int(v) => DataType::Int(v), - DataTypeRef::Float(v) => DataType::Float(v), - DataTypeRef::String(v) => DataType::String(v), - DataTypeRef::SharedString(v) => DataType::String(v.into()), - DataTypeRef::Bool(v) => DataType::Bool(v), - DataTypeRef::DateTime(v) => DataType::DateTime(v), - DataTypeRef::Duration(v) => DataType::Duration(v), - DataTypeRef::DateTimeIso(v) => DataType::DateTimeIso(v), - DataTypeRef::DurationIso(v) => DataType::DurationIso(v), - DataTypeRef::Error(v) => DataType::Error(v), - DataTypeRef::Empty => DataType::Empty, + DataRef::Int(v) => Data::Int(v), + DataRef::Float(v) => Data::Float(v), + DataRef::String(v) => Data::String(v), + DataRef::SharedString(v) => Data::String(v.into()), + DataRef::Bool(v) => Data::Bool(v), + DataRef::DateTime(v) => Data::DateTime(v), + DataRef::Duration(v) => Data::Duration(v), + DataRef::DateTimeIso(v) => Data::DateTimeIso(v), + DataRef::DurationIso(v) => Data::DurationIso(v), + DataRef::Error(v) => Data::Error(v), + DataRef::Empty => Data::Empty, } } } @@ -673,7 +673,7 @@ mod date_tests { fn test_dates() { use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime}; - let unix_epoch = DataType::Float(25569.); + let unix_epoch = Data::Float(25569.); assert_eq!( unix_epoch.as_datetime(), Some(NaiveDateTime::new( @@ -683,7 +683,7 @@ mod date_tests { ); // test for https://github.com/tafia/calamine/issues/251 - let unix_epoch_precision = DataType::Float(44484.7916666667); + let unix_epoch_precision = Data::Float(44484.7916666667); assert_eq!( unix_epoch_precision.as_datetime(), Some(NaiveDateTime::new( @@ -694,18 +694,18 @@ mod date_tests { // test rounding assert_eq!( - DataType::Float(0.18737500000000001).as_time(), + Data::Float(0.18737500000000001).as_time(), Some(NaiveTime::from_hms_milli_opt(4, 29, 49, 200).unwrap()) ); assert_eq!( - DataType::Float(0.25951736111111101).as_time(), + Data::Float(0.25951736111111101).as_time(), Some(NaiveTime::from_hms_milli_opt(6, 13, 42, 300).unwrap()) ); // test overflow - assert_eq!(DataType::Float(1e20).as_time(), None); + assert_eq!(Data::Float(1e20).as_time(), None); - let unix_epoch_15h30m = DataType::Float(25569.645833333333333); + let unix_epoch_15h30m = Data::Float(25569.645833333333333); let chrono_dt = NaiveDateTime::new( NaiveDate::from_ymd_opt(1970, 1, 1).unwrap(), NaiveTime::from_hms_opt(15, 30, 0).unwrap(), @@ -718,7 +718,7 @@ mod date_tests { fn test_int_dates() { use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; - let unix_epoch = DataType::Int(25569); + let unix_epoch = Data::Int(25569); assert_eq!( unix_epoch.as_datetime(), Some(NaiveDateTime::new( @@ -727,7 +727,7 @@ mod date_tests { )) ); - let time = DataType::Int(44060); + let time = Data::Int(44060); assert_eq!( time.as_datetime(), Some(NaiveDateTime::new( @@ -744,10 +744,10 @@ mod tests { #[test] fn test_partial_eq() { - assert_eq!(DataType::String("value".to_string()), "value"); - assert_eq!(DataType::String("value".to_string()), "value"[..]); - assert_eq!(DataType::Float(100.0), 100.0f64); - assert_eq!(DataType::Bool(true), true); - assert_eq!(DataType::Int(100), 100i64); + assert_eq!(Data::String("value".to_string()), "value"); + assert_eq!(Data::String("value".to_string()), "value"[..]); + assert_eq!(Data::Float(100.0), 100.0f64); + assert_eq!(Data::Bool(true), true); + assert_eq!(Data::Int(100), 100i64); } } diff --git a/src/de.rs b/src/de.rs index 3debf558..de4df9dc 100644 --- a/src/de.rs +++ b/src/de.rs @@ -4,7 +4,7 @@ use serde::{self, forward_to_deserialize_any, Deserialize}; use std::marker::PhantomData; use std::{fmt, slice, str}; -use super::{CellErrorType, CellType, DataType, Range, Rows}; +use super::{CellErrorType, CellType, Data, Range, Rows}; /// A cell deserialization specific error enum #[derive(Debug)] @@ -106,7 +106,7 @@ impl RangeDeserializerBuilder<'static, &'static str> { /// # Example /// /// ``` - /// # use calamine::{DataType, Error, open_workbook, Xlsx, Reader, RangeDeserializerBuilder}; + /// # use calamine::{Data, Error, open_workbook, Xlsx, Reader, RangeDeserializerBuilder}; /// fn main() -> Result<(), Error> { /// let path = format!("{}/tests/temperature.xlsx", env!("CARGO_MANIFEST_DIR")); /// let mut workbook: Xlsx<_> = open_workbook(path)?; @@ -117,15 +117,15 @@ impl RangeDeserializerBuilder<'static, &'static str> { /// .from_range(&range)?; /// /// if let Some(result) = iter.next() { - /// let row: Vec = result?; - /// assert_eq!(row, [DataType::from("label"), DataType::from("value")]); + /// let row: Vec = result?; + /// assert_eq!(row, [Data::from("label"), Data::from("value")]); /// } else { /// return Err(From::from("expected at least three records but got none")); /// } /// /// if let Some(result) = iter.next() { - /// let row: Vec = result?; - /// assert_eq!(row, [DataType::from("celsius"), DataType::from(22.2222)]); + /// let row: Vec = result?; + /// assert_eq!(row, [Data::from("celsius"), Data::from(22.2222)]); /// } else { /// return Err(From::from("expected at least three records but got one")); /// } @@ -496,11 +496,11 @@ pub trait ToCellDeserializer<'a>: CellType { fn is_empty(&self) -> bool; } -impl<'a> ToCellDeserializer<'a> for DataType { - type Deserializer = DataTypeDeserializer<'a>; +impl<'a> ToCellDeserializer<'a> for Data { + type Deserializer = DataDeserializer<'a>; - fn to_cell_deserializer(&'a self, pos: (u32, u32)) -> DataTypeDeserializer<'a> { - DataTypeDeserializer { + fn to_cell_deserializer(&'a self, pos: (u32, u32)) -> DataDeserializer<'a> { + DataDeserializer { data_type: self, pos, } @@ -508,7 +508,7 @@ impl<'a> ToCellDeserializer<'a> for DataType { #[inline] fn is_empty(&self) -> bool { - matches!(self, DataType::Empty) + matches!(self, Data::Empty) } } @@ -519,15 +519,15 @@ macro_rules! deserialize_num { V: Visitor<'de>, { match self.data_type { - DataType::Float(v) => visitor.$visit(*v as $typ), - DataType::Int(v) => visitor.$visit(*v as $typ), - DataType::String(ref s) => { + Data::Float(v) => visitor.$visit(*v as $typ), + Data::Int(v) => visitor.$visit(*v as $typ), + Data::String(ref s) => { let v = s.parse().map_err(|_| { DeError::Custom(format!("Expecting {}, got '{}'", stringify!($typ), s)) })?; visitor.$visit(v) } - DataType::Error(ref err) => Err(DeError::CellError { + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -541,13 +541,13 @@ macro_rules! deserialize_num { }; } -/// A deserializer for the `DataType` type. -pub struct DataTypeDeserializer<'a> { - data_type: &'a DataType, +/// A deserializer for the `Data` type. +pub struct DataDeserializer<'a> { + data_type: &'a Data, pos: (u32, u32), } -impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { +impl<'a, 'de> serde::Deserializer<'de> for DataDeserializer<'a> { type Error = DeError; fn deserialize_any(self, visitor: V) -> Result @@ -555,16 +555,16 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { V: Visitor<'de>, { match self.data_type { - DataType::String(v) => visitor.visit_str(v), - DataType::Float(v) => visitor.visit_f64(*v), - DataType::Bool(v) => visitor.visit_bool(*v), - DataType::Int(v) => visitor.visit_i64(*v), - DataType::Empty => visitor.visit_unit(), - DataType::DateTime(v) => visitor.visit_f64(*v), - DataType::Duration(v) => visitor.visit_f64(*v), - DataType::DateTimeIso(v) => visitor.visit_str(v), - DataType::DurationIso(v) => visitor.visit_str(v), - DataType::Error(ref err) => Err(DeError::CellError { + Data::String(v) => visitor.visit_str(v), + Data::Float(v) => visitor.visit_f64(*v), + Data::Bool(v) => visitor.visit_bool(*v), + Data::Int(v) => visitor.visit_i64(*v), + Data::Empty => visitor.visit_unit(), + Data::DateTime(v) => visitor.visit_f64(*v), + Data::Duration(v) => visitor.visit_f64(*v), + Data::DateTimeIso(v) => visitor.visit_str(v), + Data::DurationIso(v) => visitor.visit_str(v), + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -576,16 +576,16 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { V: Visitor<'de>, { match self.data_type { - DataType::String(v) => visitor.visit_str(v), - DataType::Empty => visitor.visit_str(""), - DataType::Float(v) => visitor.visit_str(&v.to_string()), - DataType::Int(v) => visitor.visit_str(&v.to_string()), - DataType::Bool(v) => visitor.visit_str(&v.to_string()), - DataType::DateTime(v) => visitor.visit_str(&v.to_string()), - DataType::Duration(v) => visitor.visit_str(&v.to_string()), - DataType::DateTimeIso(v) => visitor.visit_str(v), - DataType::DurationIso(v) => visitor.visit_str(v), - DataType::Error(ref err) => Err(DeError::CellError { + Data::String(v) => visitor.visit_str(v), + Data::Empty => visitor.visit_str(""), + Data::Float(v) => visitor.visit_str(&v.to_string()), + Data::Int(v) => visitor.visit_str(&v.to_string()), + Data::Bool(v) => visitor.visit_str(&v.to_string()), + Data::DateTime(v) => visitor.visit_str(&v.to_string()), + Data::Duration(v) => visitor.visit_str(&v.to_string()), + Data::DateTimeIso(v) => visitor.visit_str(v), + Data::DurationIso(v) => visitor.visit_str(v), + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -597,9 +597,9 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { V: Visitor<'de>, { match self.data_type { - DataType::String(v) => visitor.visit_bytes(v.as_bytes()), - DataType::Empty => visitor.visit_bytes(&[]), - DataType::Error(ref err) => Err(DeError::CellError { + Data::String(v) => visitor.visit_bytes(v.as_bytes()), + Data::Empty => visitor.visit_bytes(&[]), + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -626,20 +626,20 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { V: Visitor<'de>, { match self.data_type { - DataType::Bool(v) => visitor.visit_bool(*v), - DataType::String(ref v) => match &**v { + Data::Bool(v) => visitor.visit_bool(*v), + Data::String(ref v) => match &**v { "TRUE" | "true" | "True" => visitor.visit_bool(true), "FALSE" | "false" | "False" => visitor.visit_bool(false), d => Err(DeError::Custom(format!("Expecting bool, got '{}'", d))), }, - DataType::Empty => visitor.visit_bool(false), - DataType::Float(v) => visitor.visit_bool(*v != 0.), - DataType::Int(v) => visitor.visit_bool(*v != 0), - DataType::DateTime(v) => visitor.visit_bool(*v != 0.), - DataType::Duration(v) => visitor.visit_bool(*v != 0.), - DataType::DateTimeIso(_) => visitor.visit_bool(true), - DataType::DurationIso(_) => visitor.visit_bool(true), - DataType::Error(ref err) => Err(DeError::CellError { + Data::Empty => visitor.visit_bool(false), + Data::Float(v) => visitor.visit_bool(*v != 0.), + Data::Int(v) => visitor.visit_bool(*v != 0), + Data::DateTime(v) => visitor.visit_bool(*v != 0.), + Data::Duration(v) => visitor.visit_bool(*v != 0.), + Data::DateTimeIso(_) => visitor.visit_bool(true), + Data::DurationIso(_) => visitor.visit_bool(true), + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -651,10 +651,10 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { V: Visitor<'de>, { match self.data_type { - DataType::String(ref s) if s.len() == 1 => { + Data::String(ref s) if s.len() == 1 => { visitor.visit_char(s.chars().next().expect("s not empty")) } - DataType::Error(ref err) => Err(DeError::CellError { + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -667,8 +667,8 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { V: Visitor<'de>, { match self.data_type { - DataType::Empty => visitor.visit_unit(), - DataType::Error(ref err) => Err(DeError::CellError { + Data::Empty => visitor.visit_unit(), + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -681,7 +681,7 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { V: Visitor<'de>, { match self.data_type { - DataType::Empty => visitor.visit_none(), + Data::Empty => visitor.visit_none(), _ => visitor.visit_some(self), } } @@ -709,8 +709,8 @@ impl<'a, 'de> serde::Deserializer<'de> for DataTypeDeserializer<'a> { use serde::de::IntoDeserializer; match self.data_type { - DataType::String(s) => visitor.visit_enum(s.as_str().into_deserializer()), - DataType::Error(ref err) => Err(DeError::CellError { + Data::String(s) => visitor.visit_enum(s.as_str().into_deserializer()), + Data::Error(ref err) => Err(DeError::CellError { err: err.clone(), pos: self.pos, }), @@ -748,7 +748,7 @@ mod tests { assert_eq!( Content::deserialize( - super::DataType::String("Foo".to_string()).to_cell_deserializer((0, 0)) + super::Data::String("Foo".to_string()).to_cell_deserializer((0, 0)) ) .unwrap(), Content::Foo diff --git a/src/formats.rs b/src/formats.rs index 3cfae549..90fc0cf3 100644 --- a/src/formats.rs +++ b/src/formats.rs @@ -1,4 +1,4 @@ -use crate::{datatype::DataTypeRef, DataType}; +use crate::{datatype::DataRef, Data}; /// https://learn.microsoft.com/en-us/office/troubleshoot/excel/1900-and-1904-date-system static EXCEL_1900_1904_DIFF: i64 = 1462; @@ -89,17 +89,17 @@ pub fn builtin_format_by_code(code: u16) -> CellFormat { } // convert i64 to date, if format == Date -pub fn format_excel_i64(value: i64, format: Option<&CellFormat>, is_1904: bool) -> DataType { +pub fn format_excel_i64(value: i64, format: Option<&CellFormat>, is_1904: bool) -> Data { match format { - Some(CellFormat::DateTime) => DataType::DateTime( + Some(CellFormat::DateTime) => Data::DateTime( (if is_1904 { value + EXCEL_1900_1904_DIFF } else { value }) as f64, ), - Some(CellFormat::TimeDelta) => DataType::Duration(value as f64), - _ => DataType::Int(value), + Some(CellFormat::TimeDelta) => Data::Duration(value as f64), + _ => Data::Int(value), } } @@ -109,20 +109,20 @@ pub fn format_excel_f64_ref<'a>( value: f64, format: Option<&CellFormat>, is_1904: bool, -) -> DataTypeRef<'static> { +) -> DataRef<'static> { match format { - Some(CellFormat::DateTime) => DataTypeRef::DateTime(if is_1904 { + Some(CellFormat::DateTime) => DataRef::DateTime(if is_1904 { value + EXCEL_1900_1904_DIFF as f64 } else { value }), - Some(CellFormat::TimeDelta) => DataTypeRef::Duration(value), - _ => DataTypeRef::Float(value), + Some(CellFormat::TimeDelta) => DataRef::Duration(value), + _ => DataRef::Float(value), } } // convert f64 to date, if format == Date -pub fn format_excel_f64(value: f64, format: Option<&CellFormat>, is_1904: bool) -> DataType { +pub fn format_excel_f64(value: f64, format: Option<&CellFormat>, is_1904: bool) -> Data { format_excel_f64_ref(value, format, is_1904).into() } diff --git a/src/lib.rs b/src/lib.rs index c811ecc9..44c5537c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! //! # Examples //! ``` -//! use calamine::{Reader, open_workbook, Xlsx, DataType}; +//! use calamine::{Reader, open_workbook, Xlsx, Data}; //! //! // opens a new workbook //! # let path = format!("{}/tests/issue3.xlsm", env!("CARGO_MANIFEST_DIR")); @@ -22,7 +22,7 @@ //! total_cells, non_empty_cells); //! // alternatively, we can manually filter rows //! assert_eq!(non_empty_cells, range.rows() -//! .flat_map(|r| r.iter().filter(|&c| c != &DataType::Empty)).count()); +//! .flat_map(|r| r.iter().filter(|&c| c != &Data::Empty)).count()); //! } //! //! // Check if the workbook has a vba project @@ -83,7 +83,7 @@ use std::ops::{Index, IndexMut}; use std::path::Path; pub use crate::auto::{open_workbook_auto, open_workbook_auto_from_rs, Sheets}; -pub use crate::datatype::{DataType, DataTypeRef, DataTypeTrait}; +pub use crate::datatype::{Data, DataRef, DataType}; pub use crate::de::{DeError, RangeDeserializer, RangeDeserializerBuilder, ToCellDeserializer}; pub use crate::errors::Error; pub use crate::ods::{Ods, OdsError}; @@ -222,10 +222,10 @@ where fn metadata(&self) -> &Metadata; /// Read worksheet data in corresponding worksheet path - fn worksheet_range(&mut self, name: &str) -> Result, Self::Error>; + fn worksheet_range(&mut self, name: &str) -> Result, Self::Error>; /// Fetch all worksheet data & paths - fn worksheets(&mut self) -> Vec<(String, Range)>; + fn worksheets(&mut self) -> Vec<(String, Range)>; /// Read worksheet formula in corresponding worksheet path fn worksheet_formula(&mut self, _: &str) -> Result, Self::Error>; @@ -260,7 +260,7 @@ where /// Get the nth worksheet. Shortcut for getting the nth /// sheet_name, then the corresponding worksheet. - fn worksheet_range_at(&mut self, n: usize) -> Option, Self::Error>> { + fn worksheet_range_at(&mut self, n: usize) -> Option, Self::Error>> { let name = self.sheet_names().get(n)?.to_string(); Some(self.worksheet_range(&name)) } @@ -292,8 +292,8 @@ where /// A trait to constrain cells pub trait CellType: Default + Clone + PartialEq {} -impl CellType for DataType {} -impl<'a> CellType for DataTypeRef<'a> {} +impl CellType for Data {} +impl<'a> CellType for DataRef<'a> {} impl CellType for String {} impl CellType for usize {} // for tests @@ -477,12 +477,12 @@ impl Range { /// /// # Examples /// ``` - /// use calamine::{Range, DataType}; + /// use calamine::{Range, Data}; /// /// let mut range = Range::new((0, 0), (5, 2)); - /// assert_eq!(range.get_value((2, 1)), Some(&DataType::Empty)); - /// range.set_value((2, 1), DataType::Float(1.0)); - /// assert_eq!(range.get_value((2, 1)), Some(&DataType::Float(1.0))); + /// assert_eq!(range.get_value((2, 1)), Some(&Data::Empty)); + /// range.set_value((2, 1), Data::Float(1.0)); + /// assert_eq!(range.get_value((2, 1)), Some(&Data::Float(1.0))); /// ``` pub fn set_value(&mut self, absolute_position: (u32, u32), value: T) { assert!( @@ -553,7 +553,7 @@ impl Range { /// /// # Examples /// ``` - /// use calamine::{Range, DataType}; + /// use calamine::{Range, Data}; /// /// let range: Range = Range::new((1, 0), (5, 2)); /// assert_eq!(range.get_value((0, 0)), None); @@ -589,10 +589,10 @@ impl Range { /// /// # Examples /// ``` - /// use calamine::{Range, DataType}; + /// use calamine::{Range, Data}; /// - /// let range: Range = Range::new((0, 0), (5, 2)); - /// // with rows item row: &[DataType] + /// let range: Range = Range::new((0, 0), (5, 2)); + /// // with rows item row: &[Data] /// assert_eq!(range.rows().map(|r| r.len()).sum::(), 18); /// ``` pub fn rows(&self) -> Rows<'_, T> { @@ -662,19 +662,19 @@ impl Range { /// # Example /// /// ``` - /// # use calamine::{Range, DataType}; + /// # use calamine::{Range, Data}; /// let mut a = Range::new((1, 1), (3, 3)); - /// a.set_value((1, 1), DataType::Bool(true)); - /// a.set_value((2, 2), DataType::Bool(true)); + /// a.set_value((1, 1), Data::Bool(true)); + /// a.set_value((2, 2), Data::Bool(true)); /// /// let b = a.range((2, 2), (5, 5)); - /// assert_eq!(b.get_value((2, 2)), Some(&DataType::Bool(true))); - /// assert_eq!(b.get_value((3, 3)), Some(&DataType::Empty)); + /// assert_eq!(b.get_value((2, 2)), Some(&Data::Bool(true))); + /// assert_eq!(b.get_value((3, 3)), Some(&Data::Empty)); /// /// let c = a.range((0, 0), (2, 2)); - /// assert_eq!(c.get_value((0, 0)), Some(&DataType::Empty)); - /// assert_eq!(c.get_value((1, 1)), Some(&DataType::Bool(true))); - /// assert_eq!(c.get_value((2, 2)), Some(&DataType::Bool(true))); + /// assert_eq!(c.get_value((0, 0)), Some(&Data::Empty)); + /// assert_eq!(c.get_value((1, 1)), Some(&Data::Bool(true))); + /// assert_eq!(c.get_value((2, 2)), Some(&Data::Bool(true))); /// ``` pub fn range(&self, start: (u32, u32), end: (u32, u32)) -> Range { let mut other = Range::new(start, end); diff --git a/src/ods.rs b/src/ods.rs index efedc4ae..f342f479 100644 --- a/src/ods.rs +++ b/src/ods.rs @@ -16,7 +16,7 @@ use zip::read::{ZipArchive, ZipFile}; use zip::result::ZipError; use crate::vba::VbaProject; -use crate::{DataType, DataTypeTrait, Metadata, Range, Reader, Sheet, SheetType, SheetVisible}; +use crate::{Data, DataType, Metadata, Range, Reader, Sheet, SheetType, SheetVisible}; use std::marker::PhantomData; const MIMETYPE: &[u8] = b"application/vnd.oasis.opendocument.spreadsheet"; @@ -111,7 +111,7 @@ impl std::error::Error for OdsError { /// OASIS Open Document Format for Office Application 1.2 (ODF 1.2) /// http://docs.oasis-open.org/office/v1.2/OpenDocument-v1.2.pdf pub struct Ods { - sheets: BTreeMap, Range)>, + sheets: BTreeMap, Range)>, metadata: Metadata, marker: PhantomData, #[cfg(feature = "picture")] @@ -175,14 +175,14 @@ where } /// Read worksheet data in corresponding worksheet path - fn worksheet_range(&mut self, name: &str) -> Result, OdsError> { + fn worksheet_range(&mut self, name: &str) -> Result, OdsError> { self.sheets .get(name) .ok_or_else(|| OdsError::WorksheetNotFound(name.into())) .map(|r| r.0.to_owned()) } - fn worksheets(&mut self) -> Vec<(String, Range)> { + fn worksheets(&mut self) -> Vec<(String, Range)> { self.sheets .iter() .map(|(name, (range, _formula))| (name.to_owned(), range.clone())) @@ -204,7 +204,7 @@ where } struct Content { - sheets: BTreeMap, Range)>, + sheets: BTreeMap, Range)>, sheets_metadata: Vec, defined_names: Vec<(String, String)>, } @@ -345,7 +345,7 @@ fn parse_content(mut zip: ZipArchive) -> Result) -> Result<(Range, Range), OdsError> { +fn read_table(reader: &mut OdsReader<'_>) -> Result<(Range, Range), OdsError> { let mut cells = Vec::new(); let mut rows_repeats = Vec::new(); let mut formulas = Vec::new(); @@ -490,7 +490,7 @@ fn read_row( reader: &mut OdsReader<'_>, row_buf: &mut Vec, cell_buf: &mut Vec, - cells: &mut Vec, + cells: &mut Vec, formulas: &mut Vec, ) -> Result<(), OdsError> { let mut empty_col_repeats = 0; @@ -517,7 +517,7 @@ fn read_row( let (value, formula, is_closed) = get_datatype(reader, e.attributes(), cell_buf)?; for _ in 0..empty_col_repeats { - cells.push(DataType::Empty); + cells.push(Data::Empty); formulas.push("".to_string()); } empty_col_repeats = 0; @@ -547,24 +547,24 @@ fn read_row( Ok(()) } -/// Converts table-cell element into a `DataType` +/// Converts table-cell element into a `Data` /// /// ODF 1.2-19.385 fn get_datatype( reader: &mut OdsReader<'_>, atts: Attributes<'_>, buf: &mut Vec, -) -> Result<(DataType, String, bool), OdsError> { +) -> Result<(Data, String, bool), OdsError> { let mut is_string = false; let mut is_value_set = false; - let mut val = DataType::Empty; + let mut val = Data::Empty; let mut formula = String::new(); for a in atts { let a = a.map_err(OdsError::XmlAttr)?; match a.key { QName(b"office:value") if !is_value_set => { let v = reader.decoder().decode(&a.value)?; - val = DataType::Float(v.parse().map_err(OdsError::ParseFloat)?); + val = Data::Float(v.parse().map_err(OdsError::ParseFloat)?); is_value_set = true; } QName(b"office:string-value" | b"office:date-value" | b"office:time-value") @@ -575,15 +575,15 @@ fn get_datatype( .map_err(OdsError::Xml)? .to_string(); val = match a.key { - QName(b"office:date-value") => DataType::DateTimeIso(attr), - QName(b"office:time-value") => DataType::DurationIso(attr), - _ => DataType::String(attr), + QName(b"office:date-value") => Data::DateTimeIso(attr), + QName(b"office:time-value") => Data::DurationIso(attr), + _ => Data::String(attr), }; is_value_set = true; } QName(b"office:boolean-value") if !is_value_set => { let b = &*a.value == b"TRUE" || &*a.value == b"true"; - val = DataType::Bool(b); + val = Data::Bool(b); is_value_set = true; } QName(b"office:value-type") if !is_value_set => is_string = &*a.value == b"string", @@ -611,7 +611,7 @@ fn get_datatype( if e.name() == QName(b"table:table-cell") || e.name() == QName(b"table:covered-table-cell") => { - return Ok((DataType::String(s), formula, true)); + return Ok((Data::String(s), formula, true)); } Ok(Event::Start(ref e)) if e.name() == QName(b"text:p") => { if first_paragraph { diff --git a/src/xls.rs b/src/xls.rs index 7c40ef00..921f1720 100644 --- a/src/xls.rs +++ b/src/xls.rs @@ -18,7 +18,7 @@ use crate::utils::read_usize; use crate::utils::{push_column, read_f64, read_i16, read_i32, read_u16, read_u32}; use crate::vba::VbaProject; use crate::{ - Cell, CellErrorType, DataType, Metadata, Range, Reader, Sheet, SheetType, SheetVisible, + Cell, CellErrorType, Data, Metadata, Range, Reader, Sheet, SheetType, SheetVisible, }; #[derive(Debug)] @@ -141,7 +141,7 @@ pub struct XlsOptions { /// A struct representing an old xls format file (CFB) pub struct Xls { - sheets: BTreeMap, Range)>, + sheets: BTreeMap, Range)>, vba: Option, metadata: Metadata, marker: PhantomData, @@ -222,14 +222,14 @@ impl Reader for Xls { &self.metadata } - fn worksheet_range(&mut self, name: &str) -> Result, XlsError> { + fn worksheet_range(&mut self, name: &str) -> Result, XlsError> { self.sheets .get(name) .map(|r| r.0.clone()) .ok_or_else(|| XlsError::WorksheetNotFound(name.into())) } - fn worksheets(&mut self) -> Vec<(String, Range)> { + fn worksheets(&mut self) -> Vec<(String, Range)> { self.sheets .iter() .map(|(name, (data, _))| (name.to_owned(), data.clone())) @@ -406,7 +406,7 @@ impl Xls { 0x0205 => cells.push(parse_bool_err(r.data)?), // 517: BoolErr 0x0207 => { // 519 String (formula value) - let val = DataType::String(parse_string(r.data, &encoding, biff)?); + let val = Data::String(parse_string(r.data, &encoding, biff)?); cells.push(Cell::new(fmla_pos, val)) } 0x027E => cells.push(parse_rk(r.data, &self.formats, self.is_1904)?), // 638: Rk @@ -562,7 +562,7 @@ fn parse_number( r: &[u8], formats: &[CellFormat], is_1904: bool, -) -> Result, XlsError> { +) -> Result, XlsError> { if r.len() < 14 { return Err(XlsError::Len { typ: "number", @@ -578,7 +578,7 @@ fn parse_number( Ok(Cell::new((row, col), format_excel_f64(v, format, is_1904))) } -fn parse_bool_err(r: &[u8]) -> Result, XlsError> { +fn parse_bool_err(r: &[u8]) -> Result, XlsError> { if r.len() < 8 { return Err(XlsError::Len { typ: "BoolErr", @@ -590,7 +590,7 @@ fn parse_bool_err(r: &[u8]) -> Result, XlsError> { let col = read_u16(&r[2..]); let pos = (row as u32, col as u32); match r[7] { - 0x00 => Ok(Cell::new(pos, DataType::Bool(r[6] != 0))), + 0x00 => Ok(Cell::new(pos, Data::Bool(r[6] != 0))), 0x01 => Ok(Cell::new(pos, parse_err(r[6])?)), e => Err(XlsError::Unrecognized { typ: "fError", @@ -599,16 +599,16 @@ fn parse_bool_err(r: &[u8]) -> Result, XlsError> { } } -fn parse_err(e: u8) -> Result { +fn parse_err(e: u8) -> Result { match e { - 0x00 => Ok(DataType::Error(CellErrorType::Null)), - 0x07 => Ok(DataType::Error(CellErrorType::Div0)), - 0x0F => Ok(DataType::Error(CellErrorType::Value)), - 0x17 => Ok(DataType::Error(CellErrorType::Ref)), - 0x1D => Ok(DataType::Error(CellErrorType::Name)), - 0x24 => Ok(DataType::Error(CellErrorType::Num)), - 0x2A => Ok(DataType::Error(CellErrorType::NA)), - 0x2B => Ok(DataType::Error(CellErrorType::GettingData)), + 0x00 => Ok(Data::Error(CellErrorType::Null)), + 0x07 => Ok(Data::Error(CellErrorType::Div0)), + 0x0F => Ok(Data::Error(CellErrorType::Value)), + 0x17 => Ok(Data::Error(CellErrorType::Ref)), + 0x1D => Ok(Data::Error(CellErrorType::Name)), + 0x24 => Ok(Data::Error(CellErrorType::Num)), + 0x2A => Ok(Data::Error(CellErrorType::NA)), + 0x2B => Ok(Data::Error(CellErrorType::GettingData)), e => Err(XlsError::Unrecognized { typ: "error", val: e, @@ -616,7 +616,7 @@ fn parse_err(e: u8) -> Result { } } -fn parse_rk(r: &[u8], formats: &[CellFormat], is_1904: bool) -> Result, XlsError> { +fn parse_rk(r: &[u8], formats: &[CellFormat], is_1904: bool) -> Result, XlsError> { if r.len() < 10 { return Err(XlsError::Len { typ: "rk", @@ -635,7 +635,7 @@ fn parse_rk(r: &[u8], formats: &[CellFormat], is_1904: bool) -> Result>, + cells: &mut Vec>, formats: &[CellFormat], is_1904: bool, ) -> Result<(), XlsError> { @@ -668,7 +668,7 @@ fn parse_mul_rk( Ok(()) } -fn rk_num(rk: &[u8], formats: &[CellFormat], is_1904: bool) -> DataType { +fn rk_num(rk: &[u8], formats: &[CellFormat], is_1904: bool) -> Data { let d100 = (rk[2] & 1) != 0; let is_int = (rk[2] & 2) != 0; let format = formats.get(read_u16(rk) as usize); @@ -742,7 +742,7 @@ fn parse_label( r: &[u8], encoding: &XlsEncoding, biff: Biff, -) -> Result>, XlsError> { +) -> Result>, XlsError> { if r.len() < 6 { return Err(XlsError::Len { typ: "label", @@ -755,11 +755,11 @@ fn parse_label( let _ixfe = read_u16(&r[4..]); return Ok(Some(Cell::new( (row as u32, col as u32), - DataType::String(parse_string(&r[6..], encoding, biff)?), + Data::String(parse_string(&r[6..], encoding, biff)?), ))); } -fn parse_label_sst(r: &[u8], strings: &[String]) -> Result>, XlsError> { +fn parse_label_sst(r: &[u8], strings: &[String]) -> Result>, XlsError> { if r.len() < 10 { return Err(XlsError::Len { typ: "label sst", @@ -774,7 +774,7 @@ fn parse_label_sst(r: &[u8], strings: &[String]) -> Result if !s.is_empty() { return Ok(Some(Cell::new( (row as u32, col as u32), - DataType::String(s.clone()), + Data::String(s.clone()), ))); } } @@ -1412,19 +1412,19 @@ fn parse_formula( } /// FormulaValue [MS-XLS 2.5.133] -fn parse_formula_value(r: &[u8]) -> Result, XlsError> { +fn parse_formula_value(r: &[u8]) -> Result, XlsError> { match *r { // String, value should be in next record [0x00, .., 0xFF, 0xFF] => Ok(None), - [0x01, _, b, .., 0xFF, 0xFF] => Ok(Some(DataType::Bool(b != 0))), + [0x01, _, b, .., 0xFF, 0xFF] => Ok(Some(Data::Bool(b != 0))), [0x02, _, e, .., 0xFF, 0xFF] => parse_err(e).map(Some), // ignore, return blank string value - [0x03, _, .., 0xFF, 0xFF] => Ok(Some(DataType::String("".to_string()))), + [0x03, _, .., 0xFF, 0xFF] => Ok(Some(Data::String("".to_string()))), [e, .., 0xFF, 0xFF] => Err(XlsError::Unrecognized { typ: "error", val: e, }), - _ => Ok(Some(DataType::Float(read_f64(r)))), + _ => Ok(Some(Data::Float(read_f64(r)))), } } diff --git a/src/xlsb/cells_reader.rs b/src/xlsb/cells_reader.rs index 474a0738..79dbc4cb 100644 --- a/src/xlsb/cells_reader.rs +++ b/src/xlsb/cells_reader.rs @@ -1,5 +1,5 @@ use crate::{ - datatype::DataTypeRef, + datatype::DataRef, formats::{format_excel_f64_ref, CellFormat}, utils::{read_f64, read_i32, read_u32, read_usize}, Cell, CellErrorType, Dimensions, XlsbError, @@ -72,14 +72,14 @@ impl<'a> XlsbCellsReader<'a> { self.dimensions } - pub fn next_cell(&mut self) -> Result>>, XlsbError> { + pub fn next_cell(&mut self) -> Result>>, XlsbError> { // loop until end of sheet let value = loop { self.buf.clear(); self.typ = self.iter.read_type()?; let _ = self.iter.fill_buffer(&mut self.buf)?; let value = match self.typ { - // 0x0001 => continue, // DataType::Empty, // BrtCellBlank + // 0x0001 => continue, // Data::Empty, // BrtCellBlank 0x0002 => { // BrtCellRk MS-XLSB 2.5.122 let d100 = (self.buf[8] & 1) != 0; @@ -96,7 +96,7 @@ impl<'a> XlsbCellsReader<'a> { self.is_1904, ) } else { - DataTypeRef::Int(v) + DataRef::Int(v) } } else { let mut v = [0u8; 8]; @@ -119,20 +119,20 @@ impl<'a> XlsbCellsReader<'a> { c => return Err(XlsbError::CellError(c)), }; // BrtCellError - DataTypeRef::Error(error) + DataRef::Error(error) } - 0x0004 | 0x000A => DataTypeRef::Bool(self.buf[8] != 0), // BrtCellBool or BrtFmlaBool + 0x0004 | 0x000A => DataRef::Bool(self.buf[8] != 0), // BrtCellBool or BrtFmlaBool 0x0005 | 0x0009 => { let v = read_f64(&self.buf[8..16]); format_excel_f64_ref(v, cell_format(&self.formats, &self.buf), self.is_1904) } // BrtCellReal or BrtFmlaNum 0x0006 | 0x0008 => { - DataTypeRef::String(wide_str(&self.buf[8..], &mut 0)?.into_owned()) + DataRef::String(wide_str(&self.buf[8..], &mut 0)?.into_owned()) } // BrtCellSt or BrtFmlaString 0x0007 => { // BrtCellIsst let isst = read_usize(&self.buf[8..12]); - DataTypeRef::SharedString(&self.strings[isst]) + DataRef::SharedString(&self.strings[isst]) } 0x0000 => { // BrtRowHdr @@ -157,7 +157,7 @@ impl<'a> XlsbCellsReader<'a> { let _ = self.iter.fill_buffer(&mut self.buf)?; let value = match self.typ { - // 0x0001 => continue, // DataType::Empty, // BrtCellBlank + // 0x0001 => continue, // Data::Empty, // BrtCellBlank 0x0008 => { // BrtFmlaString let cch = read_u32(&self.buf[8..]) as usize; diff --git a/src/xlsb/mod.rs b/src/xlsb/mod.rs index c94a1079..c36bcb26 100644 --- a/src/xlsb/mod.rs +++ b/src/xlsb/mod.rs @@ -17,11 +17,11 @@ use quick_xml::Reader as XmlReader; use zip::read::{ZipArchive, ZipFile}; use zip::result::ZipError; -use crate::datatype::DataTypeRef; +use crate::datatype::DataRef; use crate::formats::{builtin_format_by_code, detect_custom_number_format, CellFormat}; use crate::utils::{push_column, read_f64, read_i32, read_u16, read_u32, read_usize}; use crate::vba::VbaProject; -use crate::{Cell, DataType, Metadata, Range, Reader, Sheet, SheetType, SheetVisible}; +use crate::{Cell, Data, Metadata, Range, Reader, Sheet, SheetType, SheetVisible}; /// A Xlsb specific error #[derive(Debug)] @@ -470,12 +470,12 @@ impl Reader for Xlsb { } /// MS-XLSB 2.1.7.62 - fn worksheet_range(&mut self, name: &str) -> Result, XlsbError> { + fn worksheet_range(&mut self, name: &str) -> Result, XlsbError> { let mut cells_reader = self.worksheet_cells_reader(name)?; let mut cells = Vec::with_capacity(cells_reader.dimensions().len().min(1_000_000) as _); while let Some(cell) = cells_reader.next_cell()? { - if cell.val != DataTypeRef::Empty { - cells.push(Cell::new(cell.pos, DataType::from(cell.val))); + if cell.val != DataRef::Empty { + cells.push(Cell::new(cell.pos, Data::from(cell.val))); } } Ok(Range::from_sparse(cells)) @@ -494,7 +494,7 @@ impl Reader for Xlsb { } /// MS-XLSB 2.1.7.62 - fn worksheets(&mut self) -> Vec<(String, Range)> { + fn worksheets(&mut self) -> Vec<(String, Range)> { let sheets = self .sheets .iter() diff --git a/src/xlsx/cells_reader.rs b/src/xlsx/cells_reader.rs index 16a32a23..9a14a9b4 100644 --- a/src/xlsx/cells_reader.rs +++ b/src/xlsx/cells_reader.rs @@ -7,7 +7,7 @@ use super::{ get_attribute, get_dimension, get_row, get_row_column, read_string, Dimensions, XlReader, }; use crate::{ - datatype::DataTypeRef, + datatype::DataRef, formats::{format_excel_f64_ref, CellFormat}, Cell, XlsxError, }; @@ -75,7 +75,7 @@ impl<'a> XlsxCellReader<'a> { self.dimensions } - pub fn next_cell(&mut self) -> Result>>, XlsxError> { + pub fn next_cell(&mut self) -> Result>>, XlsxError> { loop { self.buf.clear(); match self.xml.read_event_into(&mut self.buf) { @@ -101,7 +101,7 @@ impl<'a> XlsxCellReader<'a> { } else { (self.row_index, self.col_index) }; - let mut value = DataTypeRef::Empty; + let mut value = DataRef::Empty; loop { self.cell_buf.clear(); match self.xml.read_event_into(&mut self.cell_buf) { @@ -196,11 +196,11 @@ fn read_value<'s>( xml: &mut XlReader<'_>, e: &BytesStart<'_>, c_element: &BytesStart<'_>, -) -> Result, XlsxError> { +) -> Result, XlsxError> { Ok(match e.local_name().as_ref() { b"is" => { // inlineStr - read_string(xml, e.name())?.map_or(DataTypeRef::Empty, DataTypeRef::String) + read_string(xml, e.name())?.map_or(DataRef::Empty, DataRef::String) } b"v" => { // value @@ -219,7 +219,7 @@ fn read_value<'s>( } b"f" => { xml.read_to_end_into(e.name(), &mut Vec::new())?; - DataTypeRef::Empty + DataRef::Empty } _n => return Err(XlsxError::UnexpectedNode("v, f, or is")), }) @@ -232,7 +232,7 @@ fn read_v<'s>( formats: &[CellFormat], c_element: &BytesStart<'_>, is_1904: bool, -) -> Result, XlsxError> { +) -> Result, XlsxError> { let cell_format = match get_attribute(c_element.attributes(), QName(b"s")) { Ok(Some(style)) => { let id: usize = std::str::from_utf8(style).unwrap_or("0").parse()?; @@ -244,39 +244,39 @@ fn read_v<'s>( Some(b"s") => { // shared string let idx: usize = v.parse()?; - Ok(DataTypeRef::SharedString(&strings[idx])) + Ok(DataRef::SharedString(&strings[idx])) } Some(b"b") => { // boolean - Ok(DataTypeRef::Bool(v != "0")) + Ok(DataRef::Bool(v != "0")) } Some(b"e") => { // error - Ok(DataTypeRef::Error(v.parse()?)) + Ok(DataRef::Error(v.parse()?)) } Some(b"d") => { // date - Ok(DataTypeRef::DateTimeIso(v)) + Ok(DataRef::DateTimeIso(v)) } Some(b"str") => { // see http://officeopenxml.com/SScontentOverview.php // str - refers to formula cells // * indicates calculated value (this case) // * to the formula string (ignored case - // TODO: Fully support a DataType::Formula representing both Formula string & + // TODO: Fully support a Data::Formula representing both Formula string & // last calculated value? // // NB: the result of a formula may not be a numeric value (=A3&" "&A4). // We do try an initial parse as Float for utility, but fall back to a string // representation if that fails v.parse() - .map(DataTypeRef::Float) - .or(Ok(DataTypeRef::String(v))) + .map(DataRef::Float) + .or(Ok(DataRef::String(v))) } Some(b"n") => { // n - number if v.is_empty() { - Ok(DataTypeRef::Empty) + Ok(DataRef::Empty) } else { v.parse() .map(|n| format_excel_f64_ref(n, cell_format, is_1904)) @@ -288,7 +288,7 @@ fn read_v<'s>( // String if this fails. v.parse() .map(|n| format_excel_f64_ref(n, cell_format, is_1904)) - .or(Ok(DataTypeRef::String(v))) + .or(Ok(DataRef::String(v))) } Some(b"is") => { // this case should be handled in outer loop over cell elements, in which diff --git a/src/xlsx/mod.rs b/src/xlsx/mod.rs index d927049b..f018110a 100644 --- a/src/xlsx/mod.rs +++ b/src/xlsx/mod.rs @@ -14,11 +14,11 @@ use quick_xml::Reader as XmlReader; use zip::read::{ZipArchive, ZipFile}; use zip::result::ZipError; -use crate::datatype::DataTypeRef; +use crate::datatype::DataRef; use crate::formats::{builtin_format_by_id, detect_custom_number_format, CellFormat}; use crate::vba::VbaProject; use crate::{ - Cell, CellErrorType, DataType, Dimensions, Metadata, Range, Reader, Sheet, SheetType, + Cell, CellErrorType, Data, Dimensions, Metadata, Range, Reader, Sheet, SheetType, SheetVisible, Table, }; pub use cells_reader::XlsxCellReader; @@ -675,7 +675,7 @@ impl Xlsx { /// Get the table by name // TODO: If retrieving multiple tables from a single sheet, get tables by sheet will be more efficient - pub fn table_by_name(&mut self, table_name: &str) -> Result, XlsxError> { + pub fn table_by_name(&mut self, table_name: &str) -> Result, XlsxError> { let match_table_meta = self .tables .as_ref() @@ -742,7 +742,7 @@ impl Xlsx { pub fn worksheet_range_ref<'a>( &'a mut self, name: &str, - ) -> Result>, XlsxError> { + ) -> Result>, XlsxError> { let mut cell_reader = self.worksheet_cells_reader(name)?; let len = cell_reader.dimensions().len(); let mut cells = Vec::new(); @@ -752,7 +752,7 @@ impl Xlsx { loop { match cell_reader.next_cell() { Ok(Some(Cell { - val: DataTypeRef::Empty, + val: DataRef::Empty, .. })) => (), Ok(Some(cell)) => cells.push(cell), @@ -805,7 +805,7 @@ impl Reader for Xlsx { &self.metadata } - fn worksheet_range(&mut self, name: &str) -> Result, XlsxError> { + fn worksheet_range(&mut self, name: &str) -> Result, XlsxError> { let rge = self.worksheet_range_ref(name)?; let inner = rge.inner.into_iter().map(|v| v.into()).collect(); Ok(Range { @@ -830,7 +830,7 @@ impl Reader for Xlsx { Ok(Range::from_sparse(cells)) } - fn worksheets(&mut self) -> Vec<(String, Range)> { + fn worksheets(&mut self) -> Vec<(String, Range)> { let names = self .sheets .iter() diff --git a/tests/test.rs b/tests/test.rs index 9cf150d5..f8677cd6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,11 +1,11 @@ -use calamine::DataType::{ +use calamine::Data::{ Bool, DateTime, DateTimeIso, Duration, DurationIso, Empty, Error, Float, String, }; use calamine::{ - open_workbook, open_workbook_auto, DataTypeTrait, Ods, Reader, Sheet, SheetType, SheetVisible, - Xls, Xlsb, Xlsx, + open_workbook, open_workbook_auto, DataType, Ods, Reader, Sheet, SheetType, SheetVisible, Xls, + Xlsb, Xlsx, }; -use calamine::{CellErrorType::*, DataType}; +use calamine::{CellErrorType::*, Data}; use std::io::Cursor; use std::sync::Once; @@ -1301,10 +1301,10 @@ fn issue304_xls_values() { let mut wb: Xls<_> = open_workbook(&path).unwrap(); let rge = wb.worksheet_range("Sheet1").unwrap(); let mut rows = rge.rows(); - assert_eq!(rows.next(), Some(&[DataType::Float(10.)][..])); - assert_eq!(rows.next(), Some(&[DataType::Float(20.)][..])); - assert_eq!(rows.next(), Some(&[DataType::Float(110.)][..])); - assert_eq!(rows.next(), Some(&[DataType::Float(65.)][..])); + assert_eq!(rows.next(), Some(&[Data::Float(10.)][..])); + assert_eq!(rows.next(), Some(&[Data::Float(20.)][..])); + assert_eq!(rows.next(), Some(&[Data::Float(110.)][..])); + assert_eq!(rows.next(), Some(&[Data::Float(65.)][..])); assert_eq!(rows.next(), None); } @@ -1315,10 +1315,10 @@ fn issue334_xls_values_string() { let mut wb: Xls<_> = open_workbook(&path).unwrap(); let rge = wb.worksheet_range("Sheet1").unwrap(); let mut rows = rge.rows(); - assert_eq!(rows.next(), Some(&[DataType::String("aa".into())][..])); - assert_eq!(rows.next(), Some(&[DataType::String("bb".into())][..])); - assert_eq!(rows.next(), Some(&[DataType::String("aa".into())][..])); - assert_eq!(rows.next(), Some(&[DataType::String("bb".into())][..])); + assert_eq!(rows.next(), Some(&[Data::String("aa".into())][..])); + assert_eq!(rows.next(), Some(&[Data::String("bb".into())][..])); + assert_eq!(rows.next(), Some(&[Data::String("aa".into())][..])); + assert_eq!(rows.next(), Some(&[Data::String("bb".into())][..])); assert_eq!(rows.next(), None); } @@ -1550,10 +1550,10 @@ fn issue_384_multiple_formula() { // first check values let range = workbook.worksheet_range("Sheet1").unwrap(); let expected = [ - (0, 0, DataType::Float(23.)), - (0, 2, DataType::Float(23.)), - (12, 6, DataType::Float(2.)), - (13, 9, DataType::String("US".into())), + (0, 0, Data::Float(23.)), + (0, 2, Data::Float(23.)), + (12, 6, Data::Float(2.)), + (13, 9, Data::String("US".into())), ]; let expected = expected .iter() @@ -1569,7 +1569,7 @@ fn issue_384_multiple_formula() { .collect::>(); let expected = [ (0, 0, "C1+E5"), - // (0, 2, DataType::Float(23.)), + // (0, 2, Data::Float(23.)), (12, 6, "SUM(1+1)"), ( 13, From e2fe7f926f8406aba06ce119a8b79ec3f72b9b25 Mon Sep 17 00:00:00 2001 From: Luka Peschke Date: Mon, 15 Jan 2024 10:18:29 +0100 Subject: [PATCH 5/6] docs: update changelog Signed-off-by: Luka Peschke --- Changelog.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 13765ffa..7e42b5ef 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,9 @@ ## Unreleased +- refactor: rename `DataType` enum to `Data` and `DataTypeRef` to `DataRef` +- feat: introduce a `DataType` trait implemented by both `Data` and `DataRef`. + ## 0.23.1 - fix: `worksheet_formula` not returning all formula @@ -146,7 +149,7 @@ - fix: xls - allow sectors ending after eof (truncate them!) ## 0.15.0 -- feat: codepage/encoding_rs for codpage mapping +- feat: codepage/encoding_rs for codpage mapping ## 0.14.10 - fix: serde map do not stop at first empty value From 04c1e3e9c5976b7e47800cb99c21300471459ad0 Mon Sep 17 00:00:00 2001 From: Luka Peschke Date: Mon, 15 Jan 2024 10:20:58 +0100 Subject: [PATCH 6/6] chore: cargo fmt Signed-off-by: Luka Peschke --- src/datatype.rs | 4 +--- src/xls.rs | 10 ++-------- src/xlsb/cells_reader.rs | 4 +--- src/xlsx/cells_reader.rs | 4 +--- src/xlsx/mod.rs | 4 ++-- 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/datatype.rs b/src/datatype.rs index a2cc842a..6d268f24 100644 --- a/src/datatype.rs +++ b/src/datatype.rs @@ -520,9 +520,7 @@ impl DataType for DataRef<'_> { .as_datetime() .map(|dt| dt.time()) .or_else(|| chrono::NaiveTime::from_str(s).ok()), - DataRef::DurationIso(s) => { - chrono::NaiveTime::parse_from_str(s, "PT%HH%MM%S%.fS").ok() - } + DataRef::DurationIso(s) => chrono::NaiveTime::parse_from_str(s, "PT%HH%MM%S%.fS").ok(), _ => self.as_datetime().map(|dt| dt.time()), } } diff --git a/src/xls.rs b/src/xls.rs index 921f1720..4fb62a57 100644 --- a/src/xls.rs +++ b/src/xls.rs @@ -17,9 +17,7 @@ use crate::formats::{ use crate::utils::read_usize; use crate::utils::{push_column, read_f64, read_i16, read_i32, read_u16, read_u32}; use crate::vba::VbaProject; -use crate::{ - Cell, CellErrorType, Data, Metadata, Range, Reader, Sheet, SheetType, SheetVisible, -}; +use crate::{Cell, CellErrorType, Data, Metadata, Range, Reader, Sheet, SheetType, SheetVisible}; #[derive(Debug)] /// An enum to handle Xls specific errors @@ -558,11 +556,7 @@ fn parse_sheet_metadata( Ok((pos, Sheet { name, visible, typ })) } -fn parse_number( - r: &[u8], - formats: &[CellFormat], - is_1904: bool, -) -> Result, XlsError> { +fn parse_number(r: &[u8], formats: &[CellFormat], is_1904: bool) -> Result, XlsError> { if r.len() < 14 { return Err(XlsError::Len { typ: "number", diff --git a/src/xlsb/cells_reader.rs b/src/xlsb/cells_reader.rs index 79dbc4cb..ab522e9a 100644 --- a/src/xlsb/cells_reader.rs +++ b/src/xlsb/cells_reader.rs @@ -126,9 +126,7 @@ impl<'a> XlsbCellsReader<'a> { let v = read_f64(&self.buf[8..16]); format_excel_f64_ref(v, cell_format(&self.formats, &self.buf), self.is_1904) } // BrtCellReal or BrtFmlaNum - 0x0006 | 0x0008 => { - DataRef::String(wide_str(&self.buf[8..], &mut 0)?.into_owned()) - } // BrtCellSt or BrtFmlaString + 0x0006 | 0x0008 => DataRef::String(wide_str(&self.buf[8..], &mut 0)?.into_owned()), // BrtCellSt or BrtFmlaString 0x0007 => { // BrtCellIsst let isst = read_usize(&self.buf[8..12]); diff --git a/src/xlsx/cells_reader.rs b/src/xlsx/cells_reader.rs index 9a14a9b4..b6435d20 100644 --- a/src/xlsx/cells_reader.rs +++ b/src/xlsx/cells_reader.rs @@ -269,9 +269,7 @@ fn read_v<'s>( // NB: the result of a formula may not be a numeric value (=A3&" "&A4). // We do try an initial parse as Float for utility, but fall back to a string // representation if that fails - v.parse() - .map(DataRef::Float) - .or(Ok(DataRef::String(v))) + v.parse().map(DataRef::Float).or(Ok(DataRef::String(v))) } Some(b"n") => { // n - number diff --git a/src/xlsx/mod.rs b/src/xlsx/mod.rs index f018110a..a1e23cdb 100644 --- a/src/xlsx/mod.rs +++ b/src/xlsx/mod.rs @@ -18,8 +18,8 @@ use crate::datatype::DataRef; use crate::formats::{builtin_format_by_id, detect_custom_number_format, CellFormat}; use crate::vba::VbaProject; use crate::{ - Cell, CellErrorType, Data, Dimensions, Metadata, Range, Reader, Sheet, SheetType, - SheetVisible, Table, + Cell, CellErrorType, Data, Dimensions, Metadata, Range, Reader, Sheet, SheetType, SheetVisible, + Table, }; pub use cells_reader::XlsxCellReader;