use chrono::Local;
use anyhow::{anyhow, Result};
use lazy_static::lazy_static;
use read::FromCellValue;
pub mod read;
#[cfg(feature = "xlsxwriter")]
pub mod write;
pub use zip;
pub use chrono;
#[cfg(feature = "xlsxwriter")]
pub use rust_xlsxwriter;
pub type Date32 = i32;
#[derive(Debug)]
pub struct Timestamp(i64);
#[derive(Debug)]
pub struct Timesecond(i32);
pub type RowNum = u32;
pub type ColNum = u16;
pub type MergedRange = ((RowNum, ColNum), (RowNum, ColNum));
pub static MAX_COL_NUM: u16 = std::u16::MAX;
pub static MAX_ROW_NUM: u32 = std::u32::MAX;
impl Timestamp {
pub fn utc(&self) -> i64 {
self.0
}
pub fn local(&self) -> i64 {
self.0 - *LOCAL_OFFSET
}
}
impl Into<Timestamp> for i64 {
fn into(self) -> Timestamp {
Timestamp(self)
}
}
impl Into<Timestamp> for f64 {
fn into(self) -> Timestamp {
Timestamp(self as i64)
}
}
impl Into<Timesecond> for i32 {
fn into(self) -> Timesecond {
Timesecond(self)
}
}
impl From<Timesecond> for i32 {
fn from(ts: Timesecond) -> i32 {
ts.0
}
}
pub fn get_num_from_ord(addr: &[u8]) -> Result<ColNum>{
let mut i: usize;
let mut j: ColNum;
let mut col: ColNum;
let addr = addr.to_ascii_uppercase();
(col, i, j) = (0, addr.len(), 1);
while i > 0 {
i -= 1;
if addr[i] > b'@' {
col += ((addr[i] - b'@') as ColNum) * j;
j *= 26;
}
};
Ok(col)
}
pub fn get_ord_from_num(num: ColNum) -> Result<String> {
let mut col = num;
let mut addr = Vec::with_capacity(2);
while col > 26 {
addr.push(((col % 26) + 64) as u8 as char);
col = col / 26;
};
addr.push((col + 64) as u8 as char);
addr.reverse();
Ok(String::from_iter(addr))
}
pub fn get_tuple_from_ord(addr: &[u8]) -> Result<(RowNum, ColNum)> {
let mut i: usize;
let mut j: ColNum;
let mut col: ColNum;
let mut row: Option<RowNum> = None;
let addr = addr.to_ascii_uppercase();
(col, i, j) = (0, addr.len(), 1);
while i > 0 {
i -= 1;
if addr[i] > b'@' {
if row.is_none() {
row = Some(String::from_utf8(addr[i+1..].to_vec())?.parse::<RowNum>()?);
};
col += ((addr[i] - b'@') as ColNum) * j;
j *= 26;
}
};
if let Some(row) = row {
Ok((row, col))
} else {
return Err(anyhow!("invalid cell address: {:?}", addr))
}
}
pub fn get_ord_from_tuple(row: RowNum, col: ColNum) -> Result<String> {
match get_ord_from_num(col) {
Ok(col) => {
Ok(format!("{}{}", col, row))
},
Err(e) => Err(e)
}
}
pub fn is_merged_cell(mgs: &Vec<MergedRange>, row: RowNum, col: ColNum) -> (bool, Option<(RowNum, ColNum)>) {
for (left_top, right_end) in mgs {
if left_top.0 <= row && left_top.1 <= col && right_end.0 >= row && right_end.1 >= col {
if left_top.0 == row && left_top.1 == col {
return (true, Some((right_end.0-row+1, right_end.1-col+1)))
} else {
return (true, None);
}
};
}
return (false, None)
}
#[derive(Debug, Clone)]
pub enum CellValue<'a> {
Blank,
Bool(bool),
Number(f64),
Date(f64),
Time(f64),
Datetime(f64),
Shared(&'a String),
String(String),
Error(String)
}
impl<'a> CellValue<'a> {
pub fn get<T: FromCellValue>(&'a self) -> Result<Option<T>> {
T::try_from_cval(self)
}
}
lazy_static! {
static ref LOCAL_OFFSET: i64 = Local::now().offset().local_minus_utc() as i64;
}