papergrid/config/
entity_map.rs

1use fnv::FnvHashMap;
2
3use super::{Entity, Position};
4
5#[derive(Debug, Clone, Default)]
6pub(crate) struct EntityMap<T> {
7    // we have a global type to allocate in on stack.
8    // because most of the time no changes are made to the [EntityMap].
9    pub(crate) global: T,
10    pub(crate) columns: FnvHashMap<usize, T>,
11    pub(crate) rows: FnvHashMap<usize, T>,
12    pub(crate) cells: FnvHashMap<Position, T>,
13}
14
15impl<T> EntityMap<T> {
16    pub(crate) fn new(global: T) -> Self {
17        Self {
18            global,
19            rows: FnvHashMap::default(),
20            columns: FnvHashMap::default(),
21            cells: FnvHashMap::default(),
22        }
23    }
24
25    pub(crate) fn lookup(&self, entity: Entity) -> &T {
26        if self.rows.is_empty() && self.columns.is_empty() && self.cells.is_empty() {
27            return &self.global;
28        }
29
30        match entity {
31            Entity::Column(col) => self.columns.get(&col).unwrap_or(&self.global),
32            Entity::Row(row) => self.rows.get(&row).unwrap_or(&self.global),
33            Entity::Cell(row, col) => self
34                .cells
35                .get(&(row, col))
36                .or_else(|| self.columns.get(&col))
37                .or_else(|| self.rows.get(&row))
38                .unwrap_or(&self.global),
39            Entity::Global => &self.global,
40        }
41    }
42
43    pub(crate) fn invalidate(&mut self, entity: Entity) {
44        match entity {
45            Entity::Global => {
46                self.cells.clear();
47                self.rows.clear();
48                self.columns.clear();
49            }
50            Entity::Column(col) => self.cells.retain(|&(_, c), _| c != col),
51            Entity::Row(row) => self.cells.retain(|&(r, _), _| r != row),
52            Entity::Cell(_, _) => (),
53        }
54    }
55}
56
57impl<T: Clone> EntityMap<T> {
58    pub(crate) fn set(&mut self, entity: Entity, value: T) {
59        self.invalidate(entity);
60
61        match entity {
62            Entity::Column(col) => {
63                for &row in self.rows.keys() {
64                    self.cells.insert((row, col), value.clone());
65                }
66
67                self.columns.insert(col, value);
68            }
69            Entity::Row(row) => {
70                for &col in self.columns.keys() {
71                    self.cells.insert((row, col), value.clone());
72                }
73
74                self.rows.insert(row, value);
75            }
76            Entity::Cell(row, col) => {
77                self.cells.insert((row, col), value);
78            }
79            Entity::Global => self.global = value,
80        }
81    }
82}