umya_spreadsheet/structs/
cells.rs

1use super::Cell;
2use super::CellValue;
3use super::Style;
4use crate::helper::coordinate::*;
5use crate::helper::range::*;
6use crate::structs::Column;
7use crate::structs::Row;
8use crate::traits::AdjustmentCoordinate;
9use crate::traits::AdjustmentCoordinateWith2Sheet;
10use crate::traits::AdjustmentCoordinateWithSheet;
11use std::collections::{BTreeSet, HashMap};
12
13#[derive(Clone, Default, Debug)]
14pub struct Cells {
15    map: HashMap<(u32, u32), Box<Cell>>,
16    row_column_index: BTreeSet<(u32, u32)>,
17    column_row_index: BTreeSet<(u32, u32)>,
18    default_cell_value: CellValue,
19    default_style: Style,
20}
21impl Cells {
22    /// Iterates all [`Cell`]s in arbitrary order (not sorted).
23    #[inline]
24    pub fn iter_collection(&self) -> impl Iterator<Item = &Cell> {
25        self.map.values().map(Box::as_ref)
26    }
27
28    #[inline(always)]
29    pub fn get_collection(&self) -> Vec<&Cell> {
30        self.iter_collection().collect()
31    }
32
33    #[inline]
34    pub fn is_row_empty(&self, row_num: u32) -> bool {
35        self.row_column_index
36            .range((row_num, 0)..=(row_num, u32::MAX))
37            .next()
38            .is_none()
39    }
40
41    #[inline]
42    pub fn is_col_empty(&self, col_num: u32) -> bool {
43        self.column_row_index
44            .range((col_num, 0)..=(col_num, u32::MAX))
45            .next()
46            .is_none()
47    }
48
49    /// Iterates all cell coordinates, sorted by row then by column.
50    /// Coordinate returned is (column, row).
51    #[inline(always)]
52    pub fn iter_coordinates_sorted_by_row_column(&self) -> impl Iterator<Item = (u32, u32)> + '_ {
53        self.row_column_index
54            .iter()
55            .copied()
56            .map(|(row, col)| (col, row))
57    }
58
59    /// Iterates all [`Cell`]s, sorted by row then by column.
60    /// Coordinate returned is (column, row).
61    #[inline]
62    pub fn iter_cells_sorted_by_row_column(&self) -> impl Iterator<Item = &Cell> {
63        self.iter_coordinates_sorted_by_row_column()
64            .map(|(col, row)| self.map.get(&(row, col)).unwrap().as_ref())
65    }
66
67    /// Iterates all cell coordinates, sorted by column then by row.
68    /// Coordinate returned is (column, row).
69    #[inline(always)]
70    pub fn iter_coordinates_sorted_by_column_row(&self) -> impl Iterator<Item = (u32, u32)> + '_ {
71        self.column_row_index.iter().copied()
72    }
73
74    /// Iterates all [`Cell`]s, sorted by column then by row.
75    /// Coordinate returned is (column, row).
76    #[inline]
77    pub fn iter_cells_sorted_by_column_row(&self) -> impl Iterator<Item = &Cell> {
78        self.iter_coordinates_sorted_by_column_row()
79            .map(|(col, row)| self.map.get(&(row, col)).unwrap().as_ref())
80    }
81
82    #[inline(always)]
83    pub fn get_collection_sorted(&self) -> Vec<&Cell> {
84        self.iter_cells_sorted_by_row_column().collect()
85    }
86
87    #[inline]
88    pub(crate) fn get_collection_mut(&mut self) -> Vec<&mut Cell> {
89        self.map.values_mut().map(Box::as_mut).collect()
90    }
91
92    #[inline]
93    pub fn get_collection_to_hashmap(&self) -> &HashMap<(u32, u32), Box<Cell>> {
94        &self.map
95    }
96
97    /// Iterates all rows cells in a given column, sorted by the row index.
98    #[inline]
99    pub fn iter_rows_with_cells_by_column(
100        &self,
101        column_num: u32,
102    ) -> impl Iterator<Item = u32> + '_ {
103        self.column_row_index
104            .range((column_num, 0)..=(column_num, u32::MAX))
105            .copied()
106            .map(|(_, row)| row)
107    }
108
109    /// Iterates all [`Cell`]s in a given column, sorted by the row index.
110    #[inline]
111    pub fn iter_cells_by_column(&self, column_num: u32) -> impl Iterator<Item = &Cell> {
112        self.iter_rows_with_cells_by_column(column_num)
113            .map(move |row| self.map.get(&(row, column_num)).unwrap().as_ref())
114    }
115
116    #[inline(always)]
117    pub fn get_collection_by_column(&self, column_num: &u32) -> Vec<&Cell> {
118        self.iter_cells_by_column(*column_num).collect()
119    }
120
121    /// Iterates all column cells in a given column, sorted by the column index.
122    #[inline]
123    pub fn iter_columns_with_cells_by_row(&self, row_num: u32) -> impl Iterator<Item = u32> + '_ {
124        self.row_column_index
125            .range((row_num, 0)..=(row_num, u32::MAX))
126            .copied()
127            .map(|(_, col)| col)
128    }
129
130    /// Iterates all [`Cell`]s in a given column, sorted by the column index.
131    #[inline]
132    pub fn iter_cells_by_row(&self, row_num: u32) -> impl Iterator<Item = &Cell> {
133        self.iter_columns_with_cells_by_row(row_num)
134            .map(move |col| self.map.get(&(row_num, col)).unwrap().as_ref())
135    }
136
137    #[inline(always)]
138    pub fn get_collection_by_row(&self, row_num: &u32) -> Vec<&Cell> {
139        self.iter_cells_by_row(*row_num).collect()
140    }
141
142    /// Iterates all coordinates in a range, sorted by row then by column.
143    /// Coordinate returned is (column, row).
144    #[inline]
145    pub fn iter_coordinates_by_range_sorted_by_row(
146        &self,
147        row_start: u32,
148        row_end: u32,
149        col_start: u32,
150        col_end: u32,
151    ) -> impl Iterator<Item = (u32, u32)> + '_ {
152        self.row_column_index
153            .range((row_start, col_start)..=(row_end, col_end))
154            .copied()
155            .filter(move |(_, col)| (col_start..=col_end).contains(col))
156            .map(|(row, col)| (col, row))
157    }
158
159    /// Iterates all [`Cell`]s in a range, sorted by row then by column.
160    #[inline]
161    pub fn iter_cells_by_range_sorted_by_row(
162        &self,
163        row_start: u32,
164        row_end: u32,
165        col_start: u32,
166        col_end: u32,
167    ) -> impl Iterator<Item = &Cell> {
168        self.iter_coordinates_by_range_sorted_by_row(row_start, row_end, col_start, col_end)
169            .map(move |(col, row)| self.map.get(&(row, col)).unwrap().as_ref())
170    }
171
172    /// Iterates all coordinates in a range, sorted by column then by row.
173    /// Coordinate returned is (column, row).
174    #[inline]
175    pub fn iter_coordinates_by_range_sorted_by_column(
176        &self,
177        col_start: u32,
178        col_end: u32,
179        row_start: u32,
180        row_end: u32,
181    ) -> impl Iterator<Item = (u32, u32)> + '_ {
182        self.column_row_index
183            .range((col_start, row_start)..=(col_end, row_end))
184            .copied()
185            .filter(move |(_, row)| (row_start..=row_end).contains(row))
186    }
187
188    /// Iterates all [`Cell`]s in a range, sorted by column then by row.
189    /// Coordinate returned is (column, row).
190    #[inline]
191    pub fn iter_cells_by_range_sorted_by_column(
192        &self,
193        col_start: u32,
194        col_end: u32,
195        row_start: u32,
196        row_end: u32,
197    ) -> impl Iterator<Item = &Cell> {
198        self.iter_coordinates_by_range_sorted_by_column(col_start, col_end, row_start, row_end)
199            .map(move |(col, row)| self.map.get(&(row, col)).unwrap().as_ref())
200    }
201
202    #[inline]
203    pub fn get_collection_by_column_to_hashmap(&self, column_num: &u32) -> HashMap<u32, &Cell> {
204        self.iter_cells_by_column(*column_num)
205            .map(|cell| (*cell.get_coordinate().get_row_num(), cell))
206            .collect()
207    }
208
209    #[inline]
210    pub fn get_collection_by_row_to_hashmap(&self, row_num: &u32) -> HashMap<u32, &Cell> {
211        self.iter_cells_by_row(*row_num)
212            .map(|cell| (*cell.get_coordinate().get_col_num(), cell))
213            .collect()
214    }
215
216    #[inline]
217    pub(crate) fn get_collection_to_hashmap_mut(&mut self) -> &mut HashMap<(u32, u32), Box<Cell>> {
218        &mut self.map
219    }
220
221    #[inline(always)]
222    pub fn get_highest_column_and_row(&self) -> (u32, u32) {
223        (
224            self.column_row_index.last().copied().unwrap_or((0, 0)).0,
225            self.row_column_index.last().copied().unwrap_or((0, 0)).0,
226        )
227    }
228
229    /// Has Hyperlink
230    #[inline]
231    pub fn has_hyperlink(&self) -> bool {
232        self.map.values().find_map(|c| c.get_hyperlink()).is_some()
233    }
234
235    #[inline]
236    pub fn get<T>(&self, coordinate: T) -> Option<&Cell>
237    where
238        T: Into<CellCoordinates>,
239    {
240        let CellCoordinates { col, row } = coordinate.into();
241        self.map.get(&(row, col)).map(Box::as_ref)
242    }
243
244    pub(crate) fn get_mut<T>(
245        &mut self,
246        coordinate: T,
247        row_dimension: &Row,
248        col_dimension: &Column,
249    ) -> &mut Cell
250    where
251        T: Into<CellCoordinates>,
252    {
253        let CellCoordinates { col, row } = coordinate.into();
254        self.map.entry((row, col)).or_insert_with(|| {
255            let mut c = Cell::default();
256            c.get_coordinate_mut().set_col_num(col);
257            c.get_coordinate_mut().set_row_num(row);
258            if col_dimension.has_style() {
259                c.set_style(col_dimension.get_style().clone());
260            }
261            if row_dimension.has_style() {
262                c.set_style(row_dimension.get_style().clone());
263            }
264
265            self.row_column_index.insert((row, col));
266            self.column_row_index.insert((col, row));
267
268            Box::new(c)
269        })
270    }
271
272    #[inline]
273    pub fn get_cell_value<T>(&self, coordinate: T) -> &CellValue
274    where
275        T: Into<CellCoordinates>,
276    {
277        let CellCoordinates { col, row } = coordinate.into();
278        self.map
279            .get(&(row, col))
280            .map(|c| c.get_cell_value())
281            .unwrap_or(&self.default_cell_value)
282    }
283
284    #[inline]
285    pub fn get_style<T>(&self, coordinate: T) -> &Style
286    where
287        T: Into<CellCoordinates>,
288    {
289        let CellCoordinates { col, row } = coordinate.into();
290        self.map
291            .get(&(row, col))
292            .map(|c| c.get_style())
293            .unwrap_or(&self.default_style)
294    }
295
296    #[inline]
297    pub(crate) fn set(
298        &mut self,
299        cell: Cell,
300        row_dimension: &Row,
301        col_dimension: &Column,
302    ) -> &mut Self {
303        let col_num = cell.get_coordinate().get_col_num();
304        let row_num = cell.get_coordinate().get_row_num();
305        let target_cell = self.get_mut((col_num, row_num), row_dimension, col_dimension);
306        target_cell.set_obj(cell);
307        self
308    }
309
310    #[inline]
311    pub(crate) fn set_fast(&mut self, cell: Cell) -> &mut Self {
312        self.add(cell);
313        self
314    }
315
316    pub(crate) fn add(&mut self, cell: Cell) {
317        let col_num = *cell.get_coordinate().get_col_num();
318        let row_num = *cell.get_coordinate().get_row_num();
319        self.map.insert((row_num, col_num), Box::new(cell));
320        self.row_column_index.insert((row_num, col_num));
321        self.column_row_index.insert((col_num, row_num));
322    }
323
324    #[inline]
325    pub(crate) fn remove(&mut self, col_num: &u32, row_num: &u32) -> bool {
326        let k = (*row_num, *col_num);
327        let r = self.map.remove(&k).is_some();
328        if r {
329            self.row_column_index.remove(&k);
330            self.column_row_index.remove(&(k.1, k.0));
331        }
332        r
333    }
334
335    pub fn iter_all_coordinates_by_range_sorted_by_row(
336        &self,
337        range: &str,
338    ) -> impl Iterator<Item = Option<(u32, u32)>> + '_ {
339        let (row_start, row_end, col_start, col_end) = get_start_and_end_point(range);
340
341        let mut iter =
342            self.iter_coordinates_by_range_sorted_by_row(row_start, row_end, col_start, col_end);
343
344        let mut current = iter.next();
345
346        (row_start..=row_end)
347            .flat_map(move |row| (col_start..=col_end).map(move |col| (row, col)))
348            .map(move |x| {
349                if let Some((cur_col, cur_row)) = current {
350                    if x < (cur_row, cur_col) {
351                        None
352                    } else {
353                        current = iter.next();
354                        Some((x.1, x.0))
355                    }
356                } else {
357                    None
358                }
359            })
360    }
361
362    pub fn iter_all_cells_by_range_sorted_by_row(
363        &self,
364        range: &str,
365    ) -> impl Iterator<Item = Option<&Cell>> + '_ {
366        self.iter_all_coordinates_by_range_sorted_by_row(range)
367            .map(move |coordinate| {
368                coordinate.map(move |(col, row)| self.map.get(&(row, col)).unwrap().as_ref())
369            })
370    }
371
372    #[inline]
373    pub fn iter_all_cell_values_by_range_sorted_by_row(
374        &self,
375        range: &str,
376    ) -> impl Iterator<Item = &CellValue> + '_ {
377        self.iter_all_coordinates_by_range_sorted_by_row(range)
378            .map(|coordinate| {
379                coordinate.map_or(&self.default_cell_value, |c| self.get_cell_value(c))
380            })
381    }
382
383    pub fn iter_all_coordinates_by_range_sorted_by_column(
384        &self,
385        range: &str,
386    ) -> impl Iterator<Item = Option<(u32, u32)>> + '_ {
387        let (row_start, row_end, col_start, col_end) = get_start_and_end_point(range);
388
389        let mut iter =
390            self.iter_coordinates_by_range_sorted_by_column(col_start, col_end, row_start, row_end);
391
392        let mut current = iter.next();
393
394        (col_start..=col_end)
395            .flat_map(move |col| (row_start..=row_end).map(move |row| (col, row)))
396            .map(move |coordinate| {
397                if let Some(cur) = current {
398                    if coordinate < cur {
399                        None
400                    } else {
401                        current = iter.next();
402                        Some(coordinate)
403                    }
404                } else {
405                    None
406                }
407            })
408    }
409
410    pub fn iter_all_cells_by_range_sorted_by_column(
411        &self,
412        range: &str,
413    ) -> impl Iterator<Item = Option<&Cell>> + '_ {
414        self.iter_all_coordinates_by_range_sorted_by_column(range)
415            .map(move |coordinate| {
416                coordinate.map(move |(col, row)| self.map.get(&(row, col)).unwrap().as_ref())
417            })
418    }
419
420    #[inline]
421    pub fn iter_all_cell_values_by_range_sorted_by_column(
422        &self,
423        range: &str,
424    ) -> impl Iterator<Item = &CellValue> + '_ {
425        self.iter_all_coordinates_by_range_sorted_by_column(range)
426            .map(|coordinate| {
427                coordinate.map_or(&self.default_cell_value, |c| self.get_cell_value(c))
428            })
429    }
430
431    #[inline(always)]
432    pub fn get_cell_by_range(&self, range: &str) -> Vec<Option<&Cell>> {
433        self.iter_all_cells_by_range_sorted_by_row(range).collect()
434    }
435
436    #[inline(always)]
437    pub fn get_cell_value_by_range(&self, range: &str) -> Vec<&CellValue> {
438        self.iter_all_cell_values_by_range_sorted_by_row(range)
439            .collect::<Vec<_>>()
440    }
441
442    #[inline]
443    pub fn get_formatted_value_by_column_and_row(&self, col_num: &u32, row_num: &u32) -> String {
444        match self.get((col_num, row_num)) {
445            Some(v) => v.get_formatted_value(),
446            None => "".into(),
447        }
448    }
449
450    pub(crate) fn rebuild_map_and_indices(&mut self) {
451        self.map = self
452            .get_collection_to_hashmap_mut()
453            .iter_mut()
454            .map(|(_, cell)| {
455                (
456                    (
457                        *cell.get_coordinate().get_row_num(),
458                        *cell.get_coordinate().get_col_num(),
459                    ),
460                    std::mem::take(cell),
461                )
462            })
463            .collect();
464
465        self.row_column_index = self.map.keys().copied().collect();
466
467        self.column_row_index = self
468            .map
469            .keys()
470            .copied()
471            .map(|(col, row)| (row, col))
472            .collect();
473    }
474}
475impl AdjustmentCoordinate for Cells {
476    #[inline]
477    fn adjustment_insert_coordinate(
478        &mut self,
479        root_col_num: &u32,
480        offset_col_num: &u32,
481        root_row_num: &u32,
482        offset_row_num: &u32,
483    ) {
484        // update cell
485        for cell in self.get_collection_to_hashmap_mut().values_mut() {
486            cell.adjustment_insert_coordinate(
487                root_col_num,
488                offset_col_num,
489                root_row_num,
490                offset_row_num,
491            );
492        }
493        self.rebuild_map_and_indices();
494    }
495
496    #[inline]
497    fn adjustment_remove_coordinate(
498        &mut self,
499        root_col_num: &u32,
500        offset_col_num: &u32,
501        root_row_num: &u32,
502        offset_row_num: &u32,
503    ) {
504        // update cell
505        self.map.retain(|k, x| {
506            !(x.get_coordinate().is_remove_coordinate(
507                root_col_num,
508                offset_col_num,
509                root_row_num,
510                offset_row_num,
511            ))
512        });
513        for cell in self.get_collection_mut() {
514            cell.adjustment_remove_coordinate(
515                root_col_num,
516                offset_col_num,
517                root_row_num,
518                offset_row_num,
519            );
520        }
521        self.rebuild_map_and_indices();
522    }
523}
524impl AdjustmentCoordinateWith2Sheet for Cells {
525    #[inline]
526    fn adjustment_insert_coordinate_with_2sheet(
527        &mut self,
528        self_sheet_name: &str,
529        sheet_name: &str,
530        root_col_num: &u32,
531        offset_col_num: &u32,
532        root_row_num: &u32,
533        offset_row_num: &u32,
534    ) {
535        for cell in self.get_collection_to_hashmap_mut().values_mut() {
536            cell.adjustment_insert_coordinate_with_2sheet(
537                self_sheet_name,
538                sheet_name,
539                root_col_num,
540                offset_col_num,
541                root_row_num,
542                offset_row_num,
543            );
544        }
545    }
546
547    #[inline]
548    fn adjustment_remove_coordinate_with_2sheet(
549        &mut self,
550        self_sheet_name: &str,
551        sheet_name: &str,
552        root_col_num: &u32,
553        offset_col_num: &u32,
554        root_row_num: &u32,
555        offset_row_num: &u32,
556    ) {
557        for cell in self.get_collection_to_hashmap_mut().values_mut() {
558            cell.adjustment_remove_coordinate_with_2sheet(
559                self_sheet_name,
560                sheet_name,
561                root_col_num,
562                offset_col_num,
563                root_row_num,
564                offset_row_num,
565            );
566        }
567    }
568}