excel2df 0.1.5

A library for converting Excel files to Polars DataFrame.It supports multiple threads to improve performance.
Documentation
use polars::prelude::{AnyValue,Column,DataFrame};
use std::{fmt, ops::Index};


#[derive(Debug, Clone)]
pub struct Cell<'a> {
    pub value: AnyValue<'a>,
    pub pos: (usize, usize), // (row, col)
}



impl fmt::Display for Cell<'_> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.value)
    }
}

impl <'a>Cell<'a> {
    pub fn new() -> Self {
        Cell {
            value: AnyValue::Null,
            pos: (0, 0),
        }
    }

    pub fn set_value(&mut self, value: AnyValue<'a>) ->&mut Self{
        self.value = value;
        self
    }

    pub fn set_pos(&mut self, pos: (usize, usize))->&mut Self {
        self.pos = pos;
        self
    }

    pub fn get_pos(&self) -> (usize, usize) {
        self.pos
    }

    // Option 1: Return a reference to the value
    pub fn get_value(&self) -> &AnyValue<'_> {
        &self.value
    }

    pub fn as_string(&self) -> String {
        self.value.to_string()
    }
}

#[derive(Debug, Clone, Default)]
pub struct Row<'a> {
    pub cells: Vec<Cell<'a>>,
}
impl <'a>Row<'a> {
    pub fn new()-> Self {
        Row {
            cells: vec![],
        }
    }
}

impl fmt::Display for Row<'_> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        let first_cell = self.cells.first().unwrap();
        let (row, _) = first_cell.pos;
        write!(f, "Row#{} [", row);
        for cell in self.cells.iter()  {
            write!(f, "{},", cell.as_string());
        }
        write!(f, "]")
    }
    
}

impl<'a> Index<usize> for Row<'a> {
    type Output = Cell<'a>;

    fn index(&self, index: usize) -> &Self::Output {
        &self.cells[index]
    }
}

#[derive(Debug, Clone, Default)]
pub struct Range<'a> {
    pub cells: Vec<Cell<'a>>,
    pub max_col: usize,
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CellFormat {
    Number,
    DateTime,
    TimeDelta,
}

impl <'a> Range<'a> {
    pub fn rows(&self) ->Option<Vec<Row<'a>>>{
        if self.cells.is_empty(){
            return None;
        }
        Some(
            self.cells
                .chunks(self.max_col)
                .map(|chunk| {
                    Row{cells:chunk.to_vec()}
                })
                .collect::<Vec<_>>()
        )
    }
    pub fn to_dataframe(&self,skip_rows:usize)->Option<DataFrame>{
        let rows = self.rows()?;
        let header_row = rows.get(skip_rows).unwrap();
        let mut header = vec![];
        let mut i = 1;
        for cell in header_row.cells.iter(){
            match cell.value{
                AnyValue::Null =>{
                    header.push(format!("BlankCol_{i}"));
                    i+=1;
                }
                _ =>{
                    header.push(cell.as_string().trim_matches('"').to_owned());
                }
            }
        }

        let rows = rows[skip_rows+1..].to_vec();

        let columns = (0..self.max_col)
                                    .map(|i| 
                                        Column::new(
                                            header[i].clone().into(),
                                            rows.iter()
                                            .map(|row| row[i].value.clone())
                                            .collect::<Vec<_>>()
                                        )

                                    ).collect::<Vec<_>>();
        // println!("columns:{:?}",&columns);
        Some(DataFrame::new(columns).unwrap())
    }
    
}

pub fn get_cell_format(format: &str) -> CellFormat {
    match format {
        // mm-dd-yy
        "14" |
        // d-mmm-yy
        "15" |
        // d-mmm
        "16" |
        // mmm-yy
        "17" => CellFormat::DateTime,
        // h:mm AM/PM
        "18" |
        // h:mm:ss AM/PM
        "19" |
        // h:mm
        "20" |
        // h:mm:ss
        "21" |
        // m/d/yy h:mm
        "22" |
        // mm:ss
        "45" |
        // mmss.0
        "47" |
        // [h]:mm:ss
        "46" => CellFormat::TimeDelta,
        _ => CellFormat::Number
}
}