Skip to main content

tree_table/types/
header.rs

1use crate::CellProps;
2use crate::HeaderCell;
3use crate::str_err;
4use crate::types::CyclingCounter;
5use crate::utils::utils_fns::n_to_base62;
6use crate::utils::utils_fns::pull_n;
7use crate::utils::utils_fns::push_n_add;
8use alloc::rc::Rc;
9use alloc::string::String;
10use alloc::vec::Vec;
11use hashbrown::HashMap;
12
13#[derive(Clone, Debug)]
14pub struct Header {
15    pub iid_to_col: HashMap<Rc<str>, usize>,
16    pub cells: Vec<HeaderCell>,
17    pub iid_ctr: CyclingCounter,
18}
19
20impl Header {
21    pub fn new() -> Self {
22        Header {
23            iid_to_col: HashMap::new(),
24            cells: Vec::new(),
25            iid_ctr: CyclingCounter::new(),
26        }
27    }
28
29    /// Clears all mappings and cells from the header and resets the iid counter.
30    pub fn reset(&mut self) {
31        self.iid_to_col.clear();
32        self.cells.clear();
33        self.iid_ctr = CyclingCounter::new();
34    }
35
36    /// Clone header cell properties at col.
37    pub fn clone_props(&self, col: &usize) -> Option<CellProps> {
38        self.cells.get(*col).and_then(|cell| cell.props.clone())
39    }
40
41    /// Get header cell properties reference at col.
42    pub fn get_props(&self, col: &usize) -> Option<&CellProps> {
43        self.cells.get(*col).and_then(|cell| cell.props.as_ref())
44    }
45
46    /// Insert multiple items, add cols
47    pub fn add_cols(&mut self, to_add: Vec<(usize, HeaderCell)>) {
48        // Adjust existing HashMap indices
49        for (_, col) in self.iid_to_col.iter_mut() {
50            *col = push_n_add(*col, &to_add);
51        }
52        // Add items
53        for (pos, val) in to_add.into_iter() {
54            self.iid_to_col.insert(val.iid.clone(), pos.clone());
55            self.cells.insert(pos, val);
56        }
57    }
58
59    /// Remove and return multiple items, delete cols
60    pub fn del_cols(&mut self, sorted_seq: &[usize]) -> Result<Vec<(usize, HeaderCell)>, String> {
61        let largest_pos = *sorted_seq
62            .last()
63            .ok_or_else(|| str_err!("To delete is empty."))?;
64        if largest_pos >= self.cells.len() {
65            return Err(str_err!(
66                "Deletion pos: {} out of bounds of header len: {}",
67                largest_pos,
68                self.cells.len()
69            ));
70        }
71        let mut removed = Vec::with_capacity(sorted_seq.len());
72        for (i, &pos) in sorted_seq.iter().enumerate() {
73            let cell = self.cells.remove(pos - i);
74            self.iid_to_col.remove(&cell.iid);
75            removed.push((pos, cell));
76        }
77        // Adjust indices post removal
78        for (_, pos) in self.iid_to_col.iter_mut() {
79            *pos = pull_n(*pos, sorted_seq);
80        }
81        Ok(removed)
82    }
83
84    pub fn move_cols(&mut self, full_new_to_old: &[usize]) -> Result<(), String> {
85        let n = self.cells.len();
86        if n == 0 {
87            return Ok(());
88        }
89        if full_new_to_old.len() != n {
90            return Err(str_err!(
91                "move_cols: length mismatch (got {}, expected {})",
92                full_new_to_old.len(),
93                n
94            ));
95        }
96
97        #[cfg(any(debug_assertions, feature = "safety"))]
98        {
99            use alloc::vec;
100
101            let mut seen = vec![false; n];
102            for &old_idx in full_new_to_old {
103                if old_idx >= n || seen[old_idx] {
104                    return Err(str_err!("Mapping error: invalid old index {}", old_idx));
105                }
106                seen[old_idx] = true;
107            }
108        }
109
110        let mut old_cells = core::mem::take(&mut self.cells)
111            .into_iter()
112            .map(Some)
113            .collect::<Vec<_>>();
114
115        self.cells = Vec::with_capacity(n);
116
117        for (new_idx, &old_idx) in full_new_to_old.iter().enumerate() {
118            let cell = old_cells
119                .get_mut(old_idx)
120                .and_then(Option::take)
121                .ok_or_else(|| str_err!("Mapping error: invalid or duplicate index {}", old_idx))?;
122
123            if let Some(col) = self.iid_to_col.get_mut(&cell.iid) {
124                *col = new_idx; // new column index
125            }
126            self.cells.push(cell);
127        }
128
129        Ok(())
130    }
131
132    #[inline]
133    pub fn new_iid(&mut self) -> Result<String, String> {
134        let mut iid = n_to_base62(
135            self.iid_ctr
136                .next()
137                .ok_or_else(|| str_err!("Cycling counter should never end"))?,
138        );
139        if self.iid_to_col.contains_key(iid.as_str()) {
140            let mut cycles: usize = 0;
141            while self.iid_to_col.contains_key(iid.as_str()) {
142                if cycles == usize::MAX {
143                    return Err(str_err!("Column limit reached."));
144                }
145                iid = n_to_base62(
146                    self.iid_ctr
147                        .next()
148                        .ok_or_else(|| str_err!("Cycling counter should never end"))?,
149                );
150                cycles = cycles.saturating_add(1);
151            }
152        }
153        Ok(iid)
154    }
155}