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}