Skip to main content

tree_table/api/
sort_rows_by_col.rs

1use alloc::{rc::Rc, string::String, vec::Vec};
2use core::{cell::RefCell, cmp::Ordering};
3use hashbrown::{HashMap, HashSet};
4
5use crate::args::SortRowsArgs;
6use crate::{EventData, Table, Val};
7
8impl Table {
9    pub fn sort_rows_by_cols(
10        &mut self,
11        kwargs: Option<SortRowsArgs>,
12    ) -> Result<Option<Rc<RefCell<EventData>>>, String> {
13        let num_rows = Self::acr_total_rows(&self.grid.index.cells) as u64;
14        if num_rows == 0 {
15            return Ok(None);
16        }
17
18        let kwargs: SortRowsArgs = kwargs.unwrap_or_default();
19        if kwargs.keys.is_empty() {
20            return Ok(None);
21        }
22
23        let span = self.cr_key_to_span(kwargs.span)?;
24        let rows: Vec<usize> = span.rows(&self.grid).collect();
25
26        if rows.len() <= 1 {
27            return Ok(None);
28        }
29
30        let compare_fn: fn(&Val, &Val) -> Ordering = kwargs.sort_key.get_cmp();
31        let mut indices: Vec<usize> = rows.clone();
32
33        indices.sort_by(|&a, &b| {
34            for &(col_u64, ascending) in &kwargs.keys {
35                let col = col_u64 as usize;
36                let va =
37                    Self::acr_tcell_val(&self.grid.index.cells, a, col).unwrap_or(&Val::Nil(()));
38                let vb =
39                    Self::acr_tcell_val(&self.grid.index.cells, b, col).unwrap_or(&Val::Nil(()));
40
41                let mut cmp = compare_fn(va, vb);
42                if cmp != Ordering::Equal {
43                    if !ascending {
44                        cmp = cmp.reverse();
45                    }
46                    return cmp;
47                }
48            }
49            Ordering::Equal // stable tie-breaker
50        });
51
52        if indices == rows {
53            return Ok(None);
54        }
55
56        let mut old_to_new: Vec<(usize, usize)> = Vec::new();
57        let mut new_to_old: HashMap<usize, usize> = HashMap::new();
58        let mut seen_old: HashSet<usize> = HashSet::new();
59        for (new_pos, &old) in indices.iter().enumerate() {
60            let new = rows[new_pos];
61            if old == new {
62                continue;
63            }
64            seen_old.insert(old);
65            old_to_new.push((old, new));
66            new_to_old.insert(new, old);
67        }
68
69        if old_to_new.is_empty() {
70            return Ok(None);
71        }
72
73        let mut event_data = self.cr_new_event(kwargs.save_selection);
74
75        if let Err(e) = self.cr_move_rows(
76            &mut event_data,
77            seen_old,
78            old_to_new,
79            new_to_old,
80            None,
81            true,
82        ) {
83            self.cr_roll_back(Rc::new(RefCell::new(event_data)));
84            return Err(e);
85        }
86
87        if kwargs.select {
88            Self::acr_deselect_all(&mut self.sel, None);
89            let mut moved: Vec<usize> = self.extract_disp_moved_rows(&event_data);
90            if !moved.is_empty() {
91                moved.sort_unstable();
92                self.cr_select_rows_from(moved);
93            }
94        }
95
96        self.cr_finalize_event(event_data, kwargs.undo, kwargs.emit)
97    }
98}