calamine/
lib.rs

1//! Rust Excel/OpenDocument reader
2//!
3//! # Status
4//!
5//! **calamine** is a pure Rust library to read Excel and OpenDocument Spreadsheet files.
6//!
7//! Read both cell values and vba project.
8//!
9//! # Examples
10//! ```
11//! use calamine::{Reader, open_workbook, Xlsx, DataType};
12//!
13//! // opens a new workbook
14//! # let path = format!("{}/tests/issue3.xlsm", env!("CARGO_MANIFEST_DIR"));
15//! let mut workbook: Xlsx<_> = open_workbook(path).expect("Cannot open file");
16//!
17//! // Read whole worksheet data and provide some statistics
18//! if let Some(Ok(range)) = workbook.worksheet_range("Sheet1") {
19//!     let total_cells = range.get_size().0 * range.get_size().1;
20//!     let non_empty_cells: usize = range.used_cells().count();
21//!     println!("Found {} cells in 'Sheet1', including {} non empty cells",
22//!              total_cells, non_empty_cells);
23//!     // alternatively, we can manually filter rows
24//!     assert_eq!(non_empty_cells, range.rows()
25//!         .flat_map(|r| r.iter().filter(|&c| c != &DataType::Empty)).count());
26//! }
27//!
28//! // Check if the workbook has a vba project
29//! if let Some(Ok(mut vba)) = workbook.vba_project() {
30//!     let vba = vba.to_mut();
31//!     let module1 = vba.get_module("Module 1").unwrap();
32//!     println!("Module 1 code:");
33//!     println!("{}", module1);
34//!     for r in vba.get_references() {
35//!         if r.is_missing() {
36//!             println!("Reference {} is broken or not accessible", r.name);
37//!         }
38//!     }
39//! }
40//!
41//! // You can also get defined names definition (string representation only)
42//! for name in workbook.defined_names() {
43//!     println!("name: {}, formula: {}", name.0, name.1);
44//! }
45//!
46//! // Now get all formula!
47//! let sheets = workbook.sheet_names().to_owned();
48//! for s in sheets {
49//!     println!("found {} formula in '{}'",
50//!              workbook
51//!                 .worksheet_formula(&s)
52//!                 .expect("sheet not found")
53//!                 .expect("error while getting formula")
54//!                 .rows().flat_map(|r| r.iter().filter(|f| !f.is_empty()))
55//!                 .count(),
56//!              s);
57//! }
58//! ```
59#![deny(missing_docs)]
60
61#[macro_use]
62mod utils;
63
64mod auto;
65mod cfb;
66mod datatype;
67mod formats;
68mod ods;
69mod xls;
70mod xlsb;
71mod xlsx;
72
73mod de;
74mod errors;
75pub mod vba;
76
77use serde::de::DeserializeOwned;
78use std::borrow::Cow;
79use std::cmp::{max, min};
80use std::fmt;
81use std::fs::File;
82use std::io::{BufReader, Read, Seek};
83use std::ops::{Index, IndexMut};
84use std::path::Path;
85
86pub use crate::auto::{open_workbook_auto, open_workbook_auto_from_rs, Sheets};
87pub use crate::datatype::DataType;
88pub use crate::de::{DeError, RangeDeserializer, RangeDeserializerBuilder, ToCellDeserializer};
89pub use crate::errors::Error;
90pub use crate::ods::{Ods, OdsError};
91pub use crate::xls::{Xls, XlsError, XlsOptions};
92pub use crate::xlsb::{Xlsb, XlsbError};
93pub use crate::xlsx::{Xlsx, XlsxError};
94
95use crate::vba::VbaProject;
96
97// https://msdn.microsoft.com/en-us/library/office/ff839168.aspx
98/// An enum to represent all different errors that can appear as
99/// a value in a worksheet cell
100#[derive(Debug, Clone, PartialEq)]
101pub enum CellErrorType {
102    /// Division by 0 error
103    Div0,
104    /// Unavailable value error
105    NA,
106    /// Invalid name error
107    Name,
108    /// Null value error
109    Null,
110    /// Number error
111    Num,
112    /// Invalid cell reference error
113    Ref,
114    /// Value error
115    Value,
116    /// Getting data
117    GettingData,
118}
119
120impl fmt::Display for CellErrorType {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
122        match *self {
123            CellErrorType::Div0 => write!(f, "#DIV/0!"),
124            CellErrorType::NA => write!(f, "#N/A"),
125            CellErrorType::Name => write!(f, "#NAME?"),
126            CellErrorType::Null => write!(f, "#NULL!"),
127            CellErrorType::Num => write!(f, "#NUM!"),
128            CellErrorType::Ref => write!(f, "#REF!"),
129            CellErrorType::Value => write!(f, "#VALUE!"),
130            CellErrorType::GettingData => write!(f, "#DATA!"),
131        }
132    }
133}
134
135/// Common file metadata
136///
137/// Depending on file type, some extra information may be stored
138/// in the Reader implementations
139#[derive(Debug, Default)]
140pub struct Metadata {
141    sheets: Vec<Sheet>,
142    /// Map of sheet names/sheet path within zip archive
143    names: Vec<(String, String)>,
144}
145
146/// Type of sheet
147///
148/// Only Excel formats support this. Default value for ODS is SheetType::WorkSheet.
149/// https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/b9ec509a-235d-424e-871d-f8e721106501
150/// https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xlsb/1edadf56-b5cd-4109-abe7-76651bbe2722
151/// [ECMA-376 Part 1](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/) 12.3.2, 12.3.7 and 12.3.24
152#[derive(Debug, Clone, Copy, PartialEq)]
153pub enum SheetType {
154    /// WorkSheet
155    WorkSheet,
156    /// DialogSheet
157    DialogSheet,
158    /// MacroSheet
159    MacroSheet,
160    /// ChartSheet
161    ChartSheet,
162    /// VBA module
163    Vba,
164}
165
166/// Type of visible sheet
167///
168/// http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#__RefHeading__1417896_253892949
169/// https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xls/b9ec509a-235d-424e-871d-f8e721106501
170/// https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-xlsb/74cb1d22-b931-4bf8-997d-17517e2416e9
171/// [ECMA-376 Part 1](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/) 18.18.68
172#[derive(Debug, Clone, Copy, PartialEq)]
173pub enum SheetVisible {
174    /// Visible
175    Visible,
176    /// Hidden
177    Hidden,
178    /// The sheet is hidden and cannot be displayed using the user interface. It is supported only by Excel formats.
179    VeryHidden,
180}
181
182/// Metadata of sheet
183#[derive(Debug, Clone, PartialEq)]
184pub struct Sheet {
185    /// Name
186    pub name: String,
187    /// Type
188    /// Only Excel formats support this. Default value for ODS is SheetType::WorkSheet.
189    pub typ: SheetType,
190    /// Visible
191    pub visible: SheetVisible,
192}
193
194// FIXME `Reader` must only be seek `Seek` for `Xls::xls`. Because of the present API this limits
195// the kinds of readers (other) data in formats can be read from.
196/// A trait to share spreadsheets reader functions across different `FileType`s
197pub trait Reader<RS>: Sized
198where
199    RS: Read + Seek,
200{
201    /// Error specific to file type
202    type Error: std::fmt::Debug + From<std::io::Error>;
203
204    /// Creates a new instance.
205    fn new(reader: RS) -> Result<Self, Self::Error>;
206    /// Gets `VbaProject`
207    fn vba_project(&mut self) -> Option<Result<Cow<'_, VbaProject>, Self::Error>>;
208    /// Initialize
209    fn metadata(&self) -> &Metadata;
210    /// Read worksheet data in corresponding worksheet path
211    fn worksheet_range(&mut self, name: &str) -> Option<Result<Range<DataType>, Self::Error>>;
212
213    /// Fetch all worksheet data & paths
214    fn worksheets(&mut self) -> Vec<(String, Range<DataType>)>;
215
216    /// Read worksheet formula in corresponding worksheet path
217    fn worksheet_formula(&mut self, _: &str) -> Option<Result<Range<String>, Self::Error>>;
218
219    /// Get all sheet names of this workbook, in workbook order
220    ///
221    /// # Examples
222    /// ```
223    /// use calamine::{Xlsx, open_workbook, Reader};
224    ///
225    /// # let path = format!("{}/tests/issue3.xlsm", env!("CARGO_MANIFEST_DIR"));
226    /// let mut workbook: Xlsx<_> = open_workbook(path).unwrap();
227    /// println!("Sheets: {:#?}", workbook.sheet_names());
228    /// ```
229    fn sheet_names(&self) -> Vec<String> {
230        self.metadata()
231            .sheets
232            .iter()
233            .map(|s| s.name.to_owned())
234            .collect()
235    }
236
237    /// Fetch all sheets metadata
238    fn sheets_metadata(&self) -> &[Sheet] {
239        &self.metadata().sheets
240    }
241
242    /// Get all defined names (Ranges names etc)
243    fn defined_names(&self) -> &[(String, String)] {
244        &self.metadata().names
245    }
246
247    /// Get the nth worksheet. Shortcut for getting the nth
248    /// sheet_name, then the corresponding worksheet.
249    fn worksheet_range_at(&mut self, n: usize) -> Option<Result<Range<DataType>, Self::Error>> {
250        let name = self.sheet_names().get(n)?.to_string();
251        self.worksheet_range(&name)
252    }
253
254    /// Get all pictures, tuple as (ext: String, data: Vec<u8>)
255    #[cfg(feature = "picture")]
256    fn pictures(&self) -> Option<Vec<(String, Vec<u8>)>>;
257}
258
259/// Convenient function to open a file with a BufReader<File>
260pub fn open_workbook<R, P>(path: P) -> Result<R, R::Error>
261where
262    R: Reader<BufReader<File>>,
263    P: AsRef<Path>,
264{
265    let file = BufReader::new(File::open(path)?);
266    R::new(file)
267}
268
269/// Convenient function to open a file with a BufReader<File>
270pub fn open_workbook_from_rs<R, RS>(rs: RS) -> Result<R, R::Error>
271where
272    RS: Read + Seek,
273    R: Reader<RS>,
274{
275    R::new(rs)
276}
277
278/// A trait to constrain cells
279pub trait CellType: Default + Clone + PartialEq {}
280
281impl CellType for DataType {}
282impl CellType for String {}
283impl CellType for usize {} // for tests
284
285/// A struct to hold cell position and value
286#[derive(Debug, Clone)]
287pub struct Cell<T: CellType> {
288    /// Position for the cell (row, column)
289    pos: (u32, u32),
290    /// Value for the cell
291    val: T,
292}
293
294impl<T: CellType> Cell<T> {
295    /// Creates a new `Cell`
296    pub fn new(position: (u32, u32), value: T) -> Cell<T> {
297        Cell {
298            pos: position,
299            val: value,
300        }
301    }
302
303    /// Gets `Cell` position
304    pub fn get_position(&self) -> (u32, u32) {
305        self.pos
306    }
307
308    /// Gets `Cell` value
309    pub fn get_value(&self) -> &T {
310        &self.val
311    }
312}
313
314/// A struct which represents a squared selection of cells
315#[derive(Debug, Default, Clone)]
316pub struct Range<T> {
317    start: (u32, u32),
318    end: (u32, u32),
319    inner: Vec<T>,
320}
321
322impl<T: CellType> Range<T> {
323    /// Creates a new non-empty `Range`
324    ///
325    /// When possible, prefer the more efficient `Range::from_sparse`
326    ///
327    /// # Panics
328    ///
329    /// Panics if start.0 > end.0 or start.1 > end.1
330    #[inline]
331    pub fn new(start: (u32, u32), end: (u32, u32)) -> Range<T> {
332        assert!(start <= end, "invalid range bounds");
333        Range {
334            start,
335            end,
336            inner: vec![T::default(); ((end.0 - start.0 + 1) * (end.1 - start.1 + 1)) as usize],
337        }
338    }
339
340    /// Creates a new empty range
341    #[inline]
342    pub fn empty() -> Range<T> {
343        Range {
344            start: (0, 0),
345            end: (0, 0),
346            inner: Vec::new(),
347        }
348    }
349
350    /// Get top left cell position (row, column)
351    #[inline]
352    pub fn start(&self) -> Option<(u32, u32)> {
353        if self.is_empty() {
354            None
355        } else {
356            Some(self.start)
357        }
358    }
359
360    /// Get bottom right cell position (row, column)
361    #[inline]
362    pub fn end(&self) -> Option<(u32, u32)> {
363        if self.is_empty() {
364            None
365        } else {
366            Some(self.end)
367        }
368    }
369
370    /// Get column width
371    #[inline]
372    pub fn width(&self) -> usize {
373        if self.is_empty() {
374            0
375        } else {
376            (self.end.1 - self.start.1 + 1) as usize
377        }
378    }
379
380    /// Get column height
381    #[inline]
382    pub fn height(&self) -> usize {
383        if self.is_empty() {
384            0
385        } else {
386            (self.end.0 - self.start.0 + 1) as usize
387        }
388    }
389
390    /// Get size in (height, width) format
391    #[inline]
392    pub fn get_size(&self) -> (usize, usize) {
393        (self.height(), self.width())
394    }
395
396    /// Is range empty
397    #[inline]
398    pub fn is_empty(&self) -> bool {
399        self.inner.is_empty()
400    }
401
402    /// Creates a `Range` from a coo sparse vector of `Cell`s.
403    ///
404    /// Coordinate list (COO) is the natural way cells are stored
405    /// Inner size is defined only by non empty.
406    ///
407    /// cells: `Vec` of non empty `Cell`s, sorted by row
408    ///
409    /// # Panics
410    ///
411    /// panics when a `Cell` row is lower than the first `Cell` row or
412    /// bigger than the last `Cell` row.
413    pub fn from_sparse(cells: Vec<Cell<T>>) -> Range<T> {
414        if cells.is_empty() {
415            Range::empty()
416        } else {
417            // search bounds
418            let row_start = cells.first().unwrap().pos.0;
419            let row_end = cells.last().unwrap().pos.0;
420            let mut col_start = std::u32::MAX;
421            let mut col_end = 0;
422            for c in cells.iter().map(|c| c.pos.1) {
423                if c < col_start {
424                    col_start = c;
425                }
426                if c > col_end {
427                    col_end = c
428                }
429            }
430            let cols = (col_end - col_start + 1) as usize;
431            let rows = (row_end - row_start + 1) as usize;
432            let len = cols.saturating_mul(rows);
433            let mut v = vec![T::default(); len];
434            v.shrink_to_fit();
435            for c in cells {
436                let row = (c.pos.0 - row_start) as usize;
437                let col = (c.pos.1 - col_start) as usize;
438                let idx = row.saturating_mul(cols) + col;
439                v.get_mut(idx).map(|v| *v = c.val);
440            }
441            Range {
442                start: (row_start, col_start),
443                end: (row_end, col_end),
444                inner: v,
445            }
446        }
447    }
448
449    /// Set inner value from absolute position
450    ///
451    /// # Remarks
452    ///
453    /// Will try to resize inner structure if the value is out of bounds.
454    /// For relative positions, use Index trait
455    ///
456    /// Try to avoid this method as much as possible and prefer initializing
457    /// the `Range` with `from_sparse` constructor.
458    ///
459    /// # Panics
460    ///
461    /// If absolute_position > Cell start
462    ///
463    /// # Examples
464    /// ```
465    /// use calamine::{Range, DataType};
466    ///
467    /// let mut range = Range::new((0, 0), (5, 2));
468    /// assert_eq!(range.get_value((2, 1)), Some(&DataType::Empty));
469    /// range.set_value((2, 1), DataType::Float(1.0));
470    /// assert_eq!(range.get_value((2, 1)), Some(&DataType::Float(1.0)));
471    /// ```
472    pub fn set_value(&mut self, absolute_position: (u32, u32), value: T) {
473        assert!(
474            self.start.0 <= absolute_position.0 && self.start.1 <= absolute_position.1,
475            "absolute_position out of bounds"
476        );
477
478        // check if we need to change range dimension (strangely happens sometimes ...)
479        match (
480            self.end.0 < absolute_position.0,
481            self.end.1 < absolute_position.1,
482        ) {
483            (false, false) => (), // regular case, position within bounds
484            (true, false) => {
485                let len = (absolute_position.0 - self.end.0 + 1) as usize * self.width();
486                self.inner.extend_from_slice(&vec![T::default(); len]);
487                self.end.0 = absolute_position.0;
488            }
489            // missing some rows
490            (e, true) => {
491                let height = if e {
492                    (absolute_position.0 - self.start.0 + 1) as usize
493                } else {
494                    self.height()
495                };
496                let width = (absolute_position.1 - self.start.1 + 1) as usize;
497                let old_width = self.width();
498                let mut data = Vec::with_capacity(width * height);
499                let empty = vec![T::default(); width - old_width];
500                for sce in self.inner.chunks(old_width) {
501                    data.extend_from_slice(sce);
502                    data.extend_from_slice(&empty);
503                }
504                data.extend_from_slice(&vec![T::default(); width * (height - self.height())]);
505                if e {
506                    self.end = absolute_position
507                } else {
508                    self.end.1 = absolute_position.1
509                }
510                self.inner = data;
511            } // missing some columns
512        }
513
514        let pos = (
515            absolute_position.0 - self.start.0,
516            absolute_position.1 - self.start.1,
517        );
518        let idx = pos.0 as usize * self.width() + pos.1 as usize;
519        self.inner[idx] = value;
520    }
521
522    /// Get cell value from **absolute position**.
523    ///
524    /// If the `absolute_position` is out of range, returns `None`, else returns the cell value.
525    /// The coordinate format is (row, column).
526    ///
527    /// # Warnings
528    ///
529    /// For relative positions, use Index trait
530    ///
531    /// # Remarks
532    ///
533    /// Absolute position is in *sheet* referential while relative position is in *range* referential.
534    ///
535    /// For instance if we consider range *C2:H38*:
536    /// - `(0, 0)` absolute is "A1" and thus this function returns `None`
537    /// - `(0, 0)` relative is "C2" and is returned by the `Index` trait (i.e `my_range[(0, 0)]`)
538    ///
539    /// # Examples
540    /// ```
541    /// use calamine::{Range, DataType};
542    ///
543    /// let range: Range<usize> = Range::new((1, 0), (5, 2));
544    /// assert_eq!(range.get_value((0, 0)), None);
545    /// assert_eq!(range[(0, 0)], 0);
546    /// ```
547    pub fn get_value(&self, absolute_position: (u32, u32)) -> Option<&T> {
548        let p = absolute_position;
549        if p.0 >= self.start.0 && p.0 <= self.end.0 && p.1 >= self.start.1 && p.1 <= self.end.1 {
550            return self.get((
551                (absolute_position.0 - self.start.0) as usize,
552                (absolute_position.1 - self.start.1) as usize,
553            ));
554        }
555        None
556    }
557
558    /// Get cell value from **relative position**.
559    ///
560    /// Unlike using the Index trait, this will not panic but rather yield `None` if out of range.
561    /// Otherwise, returns the cell value. The coordinate format is (row, column).
562    ///
563    pub fn get(&self, relative_position: (usize, usize)) -> Option<&T> {
564        let (row, col) = relative_position;
565        let (height, width) = self.get_size();
566        if col >= width || row >= height {
567            None
568        } else {
569            self.inner.get(row * width + col)
570        }
571    }
572
573    /// Get an iterator over inner rows
574    ///
575    /// # Examples
576    /// ```
577    /// use calamine::{Range, DataType};
578    ///
579    /// let range: Range<DataType> = Range::new((0, 0), (5, 2));
580    /// // with rows item row: &[DataType]
581    /// assert_eq!(range.rows().map(|r| r.len()).sum::<usize>(), 18);
582    /// ```
583    pub fn rows(&self) -> Rows<'_, T> {
584        if self.inner.is_empty() {
585            Rows { inner: None }
586        } else {
587            let width = self.width();
588            Rows {
589                inner: Some(self.inner.chunks(width)),
590            }
591        }
592    }
593
594    /// Get an iterator over used cells only
595    pub fn used_cells(&self) -> UsedCells<'_, T> {
596        UsedCells {
597            width: self.width(),
598            inner: self.inner.iter().enumerate(),
599        }
600    }
601
602    /// Get an iterator over all cells in this range
603    pub fn cells(&self) -> Cells<'_, T> {
604        Cells {
605            width: self.width(),
606            inner: self.inner.iter().enumerate(),
607        }
608    }
609
610    /// Build a `RangeDeserializer` from this configuration.
611    ///
612    /// # Example
613    ///
614    /// ```
615    /// # use calamine::{Reader, Error, open_workbook, Xlsx, RangeDeserializerBuilder};
616    /// fn main() -> Result<(), Error> {
617    ///     let path = format!("{}/tests/temperature.xlsx", env!("CARGO_MANIFEST_DIR"));
618    ///     let mut workbook: Xlsx<_> = open_workbook(path)?;
619    ///     let mut sheet = workbook.worksheet_range("Sheet1")
620    ///         .ok_or(Error::Msg("Cannot find 'Sheet1'"))??;
621    ///     let mut iter = sheet.deserialize()?;
622    ///
623    ///     if let Some(result) = iter.next() {
624    ///         let (label, value): (String, f64) = result?;
625    ///         assert_eq!(label, "celsius");
626    ///         assert_eq!(value, 22.2222);
627    ///
628    ///         Ok(())
629    ///     } else {
630    ///         return Err(From::from("expected at least one record but got none"));
631    ///     }
632    /// }
633    /// ```
634    pub fn deserialize<'a, D>(&'a self) -> Result<RangeDeserializer<'a, T, D>, DeError>
635    where
636        T: ToCellDeserializer<'a>,
637        D: DeserializeOwned,
638    {
639        RangeDeserializerBuilder::new().from_range(self)
640    }
641
642    /// Build a new `Range` out of this range
643    ///
644    /// # Remarks
645    ///
646    /// Cells within this range will be cloned, cells out of it will be set to Empty
647    ///
648    /// # Example
649    ///
650    /// ```
651    /// # use calamine::{Range, DataType};
652    /// let mut a = Range::new((1, 1), (3, 3));
653    /// a.set_value((1, 1), DataType::Bool(true));
654    /// a.set_value((2, 2), DataType::Bool(true));
655    ///
656    /// let b = a.range((2, 2), (5, 5));
657    /// assert_eq!(b.get_value((2, 2)), Some(&DataType::Bool(true)));
658    /// assert_eq!(b.get_value((3, 3)), Some(&DataType::Empty));
659    ///
660    /// let c = a.range((0, 0), (2, 2));
661    /// assert_eq!(c.get_value((0, 0)), Some(&DataType::Empty));
662    /// assert_eq!(c.get_value((1, 1)), Some(&DataType::Bool(true)));
663    /// assert_eq!(c.get_value((2, 2)), Some(&DataType::Bool(true)));
664    /// ```
665    pub fn range(&self, start: (u32, u32), end: (u32, u32)) -> Range<T> {
666        let mut other = Range::new(start, end);
667        let (self_start_row, self_start_col) = self.start;
668        let (self_end_row, self_end_col) = self.end;
669        let (other_start_row, other_start_col) = other.start;
670        let (other_end_row, other_end_col) = other.end;
671
672        // copy data from self to other
673        let start_row = max(self_start_row, other_start_row);
674        let end_row = min(self_end_row, other_end_row);
675        let start_col = max(self_start_col, other_start_col);
676        let end_col = min(self_end_col, other_end_col);
677
678        if start_row > end_row || start_col > end_col {
679            return other;
680        }
681
682        let self_width = self.width();
683        let other_width = other.width();
684
685        // change referential
686        //
687        // we want to copy range: start_row..(end_row + 1)
688        // In self referential it is (start_row - self_start_row)..(end_row + 1 - self_start_row)
689        let self_row_start = (start_row - self_start_row) as usize;
690        let self_row_end = (end_row + 1 - self_start_row) as usize;
691        let self_col_start = (start_col - self_start_col) as usize;
692        let self_col_end = (end_col + 1 - self_start_col) as usize;
693
694        let other_row_start = (start_row - other_start_row) as usize;
695        let other_row_end = (end_row + 1 - other_start_row) as usize;
696        let other_col_start = (start_col - other_start_col) as usize;
697        let other_col_end = (end_col + 1 - other_start_col) as usize;
698
699        {
700            let self_rows = self
701                .inner
702                .chunks(self_width)
703                .take(self_row_end)
704                .skip(self_row_start);
705
706            let other_rows = other
707                .inner
708                .chunks_mut(other_width)
709                .take(other_row_end)
710                .skip(other_row_start);
711
712            for (self_row, other_row) in self_rows.zip(other_rows) {
713                let self_cols = &self_row[self_col_start..self_col_end];
714                let other_cols = &mut other_row[other_col_start..other_col_end];
715                other_cols.clone_from_slice(self_cols);
716            }
717        }
718
719        other
720    }
721}
722
723impl<T: CellType> Index<usize> for Range<T> {
724    type Output = [T];
725    fn index(&self, index: usize) -> &[T] {
726        let width = self.width();
727        &self.inner[index * width..(index + 1) * width]
728    }
729}
730
731impl<T: CellType> Index<(usize, usize)> for Range<T> {
732    type Output = T;
733    fn index(&self, index: (usize, usize)) -> &T {
734        let (height, width) = self.get_size();
735        assert!(index.1 < width && index.0 < height, "index out of bounds");
736        &self.inner[index.0 * width + index.1]
737    }
738}
739
740impl<T: CellType> IndexMut<usize> for Range<T> {
741    fn index_mut(&mut self, index: usize) -> &mut [T] {
742        let width = self.width();
743        &mut self.inner[index * width..(index + 1) * width]
744    }
745}
746
747impl<T: CellType> IndexMut<(usize, usize)> for Range<T> {
748    fn index_mut(&mut self, index: (usize, usize)) -> &mut T {
749        let (height, width) = self.get_size();
750        assert!(index.1 < width && index.0 < height, "index out of bounds");
751        &mut self.inner[index.0 * width + index.1]
752    }
753}
754
755/// A struct to iterate over all cells
756#[derive(Debug)]
757pub struct Cells<'a, T: CellType> {
758    width: usize,
759    inner: std::iter::Enumerate<std::slice::Iter<'a, T>>,
760}
761
762impl<'a, T: 'a + CellType> Iterator for Cells<'a, T> {
763    type Item = (usize, usize, &'a T);
764    fn next(&mut self) -> Option<Self::Item> {
765        self.inner.next().map(|(i, v)| {
766            let row = i / self.width;
767            let col = i % self.width;
768            (row, col, v)
769        })
770    }
771    fn size_hint(&self) -> (usize, Option<usize>) {
772        self.inner.size_hint()
773    }
774}
775
776impl<'a, T: 'a + CellType> DoubleEndedIterator for Cells<'a, T> {
777    fn next_back(&mut self) -> Option<Self::Item> {
778        self.inner.next_back().map(|(i, v)| {
779            let row = i / self.width;
780            let col = i % self.width;
781            (row, col, v)
782        })
783    }
784}
785
786impl<'a, T: 'a + CellType> ExactSizeIterator for Cells<'a, T> {}
787
788/// A struct to iterate over used cells
789#[derive(Debug)]
790pub struct UsedCells<'a, T: CellType> {
791    width: usize,
792    inner: std::iter::Enumerate<std::slice::Iter<'a, T>>,
793}
794
795impl<'a, T: 'a + CellType> Iterator for UsedCells<'a, T> {
796    type Item = (usize, usize, &'a T);
797    fn next(&mut self) -> Option<Self::Item> {
798        self.inner
799            .by_ref()
800            .find(|&(_, v)| v != &T::default())
801            .map(|(i, v)| {
802                let row = i / self.width;
803                let col = i % self.width;
804                (row, col, v)
805            })
806    }
807    fn size_hint(&self) -> (usize, Option<usize>) {
808        let (_, up) = self.inner.size_hint();
809        (0, up)
810    }
811}
812
813impl<'a, T: 'a + CellType> DoubleEndedIterator for UsedCells<'a, T> {
814    fn next_back(&mut self) -> Option<Self::Item> {
815        self.inner
816            .by_ref()
817            .rfind(|&(_, v)| v != &T::default())
818            .map(|(i, v)| {
819                let row = i / self.width;
820                let col = i % self.width;
821                (row, col, v)
822            })
823    }
824}
825
826/// An iterator to read `Range` struct row by row
827#[derive(Debug)]
828pub struct Rows<'a, T: CellType> {
829    inner: Option<std::slice::Chunks<'a, T>>,
830}
831
832impl<'a, T: 'a + CellType> Iterator for Rows<'a, T> {
833    type Item = &'a [T];
834    fn next(&mut self) -> Option<Self::Item> {
835        self.inner.as_mut().and_then(std::iter::Iterator::next)
836    }
837    fn size_hint(&self) -> (usize, Option<usize>) {
838        self.inner
839            .as_ref()
840            .map_or((0, Some(0)), std::iter::Iterator::size_hint)
841    }
842}
843
844impl<'a, T: 'a + CellType> DoubleEndedIterator for Rows<'a, T> {
845    fn next_back(&mut self) -> Option<Self::Item> {
846        self.inner
847            .as_mut()
848            .and_then(std::iter::DoubleEndedIterator::next_back)
849    }
850}
851
852impl<'a, T: 'a + CellType> ExactSizeIterator for Rows<'a, T> {}
853
854/// Struct with the key elements of a table
855pub struct Table<T> {
856    pub(crate) name: String,
857    pub(crate) sheet_name: String,
858    pub(crate) columns: Vec<String>,
859    pub(crate) data: Range<T>,
860}
861impl<T> Table<T> {
862    /// Get the name of the table
863    pub fn name(&self) -> &str {
864        &self.name
865    }
866    /// Get the name of the sheet that table exists within
867    pub fn sheet_name(&self) -> &str {
868        &self.sheet_name
869    }
870    /// Get the names of the columns in the order they occur
871    pub fn columns(&self) -> &[String] {
872        &self.columns
873    }
874    /// Get a range representing the data from the table (excludes column headers)
875    pub fn data(&self) -> &Range<T> {
876        &self.data
877    }
878}