excel_lib/
reference.rs

1use std::fmt; 
2use std::cmp::Ordering; 
3use std::hash::{Hasher, Hash}; 
4
5use crate::cell::Cell;
6
7#[derive(Clone, Copy, Eq)]
8pub struct Reference {
9    pub start_cell : Cell, 
10    pub end_cell : Option<Cell>
11}
12
13impl PartialOrd for Reference {
14    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
15        Some(self.cmp(other))
16    }
17}
18
19impl Hash for Reference {
20    fn hash<H: Hasher>(&self, state: &mut H) {
21        self.start_cell.hash(state); 
22        self.end_cell.hash(state); 
23    }
24}
25
26impl Ord for Reference {
27    // Top to Bottom, Left to Right
28    fn cmp(&self, other: &Self) -> Ordering {
29        self.start_cell.cmp(&other.start_cell)
30    }
31}
32
33impl PartialEq for Reference {
34    fn eq(&self, other: &Self) -> bool {
35        (self.start_cell == other.start_cell)
36        & (self.end_cell == other.end_cell) 
37    }
38}
39
40impl From<Cell> for Reference {
41    fn from(a : Cell) -> Reference {
42        Reference {
43            start_cell : a, 
44            end_cell : None
45        }
46    }
47}
48
49impl From<(Cell, Option<Cell>)> for Reference {
50    fn from((a, b) : (Cell, Option<Cell>)) -> Reference {
51        Reference {
52            start_cell : a, 
53            end_cell : b
54        }
55    }
56}
57
58impl From<(usize, usize)> for Reference {
59    fn from((a, b) : (usize, usize)) -> Reference {
60        Reference {
61            start_cell : Cell::from((a, b)), 
62            end_cell : None
63        }
64    }
65}
66
67impl From<(usize, usize, usize, usize)> for Reference {
68    fn from((a, b, c, d) : (usize, usize, usize, usize)) -> Reference {
69        Reference {
70            start_cell : Cell::from((a, b)),
71            end_cell : Some(Cell::from((c, d)))
72        }
73    }
74}
75
76impl From<String> for Reference {
77    fn from(a1 : String) -> Reference {
78        if !a1.contains(':') {
79            // Single Cell (A1)
80            let cell = Cell::from(a1); 
81            Reference::from(cell) 
82        } else {
83            // Range (A1:A1), VRange(A:A), and HRange(1:1)
84            let mut cells_split = a1.split(':').map(|x| x.to_owned()).collect::<Vec<String>>(); 
85            let c1: String = cells_split.remove(0); 
86            let c2: String = cells_split.remove(0); 
87            Reference::from((Cell::from(c1), Some(Cell::from(c2))))
88        }
89    }
90}
91
92impl From<&str> for Reference {
93    fn from(s : &str) -> Reference {
94        Reference::from(s.to_owned())
95    }
96}
97
98impl fmt::Display for Reference {
99    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100        if self.is_multi_cell() {
101            // Multiple Columns or Rows
102            write!(
103                f, 
104                "{}:{}",
105                self.start_cell,
106                self.end_cell.as_ref().unwrap()
107            )
108        } else {
109            write!(f, "{}", self.start_cell)
110        }
111    }
112}
113
114impl fmt::Debug for Reference {
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        write!(f, "{}", self)
117    }
118}
119
120impl Reference { 
121    pub fn row(&self) -> usize {
122        self.start_cell.row.index
123    }
124
125    pub fn column(&self) -> usize {
126        self.start_cell.column.index
127    }
128
129    pub fn is_single_cell(&self) -> bool {
130        self.end_cell.is_none() && !self.start_cell.is_hrange() && !self.start_cell.is_vrange()
131    }
132
133    pub fn is_multi_cell(&self) -> bool {
134        self.end_cell.is_some() || self.start_cell.is_hrange() || self.start_cell.is_vrange()
135    }
136
137    pub fn is_hrange(&self) -> bool {
138        self.start_cell.is_hrange()
139    }
140
141    pub fn is_vrange(&self) -> bool {
142        self.start_cell.is_vrange()
143    }
144
145    pub fn num_rows(&self) -> usize {
146        if self.is_multi_cell() {
147            if self.start_cell.is_vrange() {
148                usize::MAX
149            } else {
150                self.end_cell.as_ref().unwrap().row.index - self.start_cell.row.index + 1 
151            }
152        } else {
153            1
154        }
155    }
156
157    pub fn num_cols(&self) -> usize {
158        if self.is_multi_cell() {
159            if self.start_cell.is_hrange() {
160                usize::MAX
161            } else {
162                self.end_cell.as_ref().unwrap().column.index - self.start_cell.column.index + 1
163            }
164        } else {
165            1
166        }
167    }
168
169    pub fn get_dimensions(&self) -> (usize, usize, usize, usize) {
170        (
171            self.row(),
172            self.column(),
173            self.num_rows(),
174            self.num_cols(),
175        )
176    }
177
178    pub fn get_cells_from_dim(start_row: usize, start_column: usize, num_rows: usize, num_cols: usize) -> Vec<(usize, usize)> {
179        let mut output: Vec<(usize, usize)> = vec![]; 
180        for row in start_row..(start_row + num_rows) {
181            for column in start_column..(start_column + num_cols) {
182                output.push((row, column)); 
183            }
184        }
185        output
186    }
187
188    pub fn get_cells(&self) -> Vec<(usize, usize)> {
189        let (start_row, start_column, num_rows, num_cols) = self.get_dimensions();
190        Self::get_cells_from_dim(start_row, start_column, num_rows, num_cols)
191    }
192
193    pub fn offset(&mut self, offset: (i32, i32)) {
194        if !self.start_cell.row.anchor && !self.start_cell.is_vrange() {
195                self.start_cell.row.index = (self.row() as i32 + offset.0) as usize;
196        }
197
198        if !self.start_cell.column.anchor && !self.start_cell.is_hrange() {
199                self.start_cell.column.index = (self.column() as i32 + offset.1) as usize;
200        }
201
202        if self.end_cell.is_some() {
203            if !self.end_cell.as_ref().unwrap().row.anchor && !self.end_cell.as_ref().unwrap().is_vrange() {
204                    self.end_cell = Some(Cell::from(((self.end_cell.as_ref().unwrap().row.index as i32 + offset.0) as usize, self.end_cell.as_ref().unwrap().column.index)))
205            }
206
207            if !self.end_cell.as_ref().unwrap().column.anchor && !self.end_cell.as_ref().unwrap().is_hrange() {
208                self.end_cell = Some(Cell::from((self.end_cell.as_ref().unwrap().row.index, (self.end_cell.as_ref().unwrap().column.index as i32 + offset.1) as usize)))
209            }
210        }
211    }
212}
213