Skip to main content

blockworx_editor/presentation/
store.rs

1//! [`EdgeId`] and the insertion-ordered map keyed by it. `EdgeId` is
2//! presentation's own: the router never persists edge identity, so nothing
3//! outside this module allocates one.
4//!
5//! Collections are plain [`IdMap`]s (`IndexMap` with a fast hasher);
6//! iteration follows insertion order, which is semantically meaningful
7//! (render z-order, route-crossing priority, hit-test).
8
9/// Keys usable in an [`IdMap`].
10pub trait KeyType: Copy + Eq + std::hash::Hash {
11    /// The `n`-th default id for this type (the newtype wrapping `n`).
12    fn nth_default(n: usize) -> Self;
13    /// The wrapped counter value, used to pick the next default id.
14    fn counter_hint(self) -> Option<usize>;
15}
16
17/// An insertion-ordered map keyed by an id newtype, backed by `IndexMap` with a
18/// fast (non-DoS-resistant) hasher. Iteration follows insertion order, which is
19/// semantically meaningful (render z-order, route-crossing priority).
20pub type IdMap<K, V> = indexmap::IndexMap<K, V, ahash::RandomState>;
21
22/// Operations on an [`IdMap`] that `IndexMap` does not provide directly.
23pub trait IdMapExt<K: KeyType, V> {
24    /// Insert `value` under a freshly generated default id, returning that id.
25    /// The id is `max(existing ids) + 1`, so existing keys never shift and the
26    /// result never collides with a live entry.
27    fn insert_value(&mut self, value: V) -> K;
28    /// Iterate over contiguous windows of `size` consecutive entries, with keys
29    /// copied out. Mirrors `slice::windows`.
30    fn windows(&self, size: usize) -> std::vec::IntoIter<Vec<(K, &V)>>;
31}
32
33impl<K: KeyType, V> IdMapExt<K, V> for IdMap<K, V> {
34    fn insert_value(&mut self, value: V) -> K {
35        let n = self
36            .keys()
37            .filter_map(|&k| k.counter_hint())
38            .max()
39            .unwrap_or(0)
40            + 1;
41        let key = K::nth_default(n);
42        self.insert(key, value);
43        key
44    }
45
46    fn windows(&self, size: usize) -> std::vec::IntoIter<Vec<(K, &V)>> {
47        let entries: Vec<(K, &V)> = self.iter().map(|(k, v)| (*k, v)).collect();
48        entries
49            .windows(size)
50            .map(<[(K, &V)]>::to_vec)
51            .collect::<Vec<_>>()
52            .into_iter()
53    }
54}
55
56/// A router edge's id. The router never persists edge identity, so this is
57/// minted and read only within this module; it renders as `"e"` + a counter
58/// (the family every id newtype in the snapshot-era store used) purely for
59/// consistency with [`IdMapExt::insert_value`]'s counter-based minting.
60#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
61pub struct EdgeId(usize);
62
63impl EdgeId {
64    const PREFIX: &'static str = "e";
65}
66
67impl KeyType for EdgeId {
68    fn nth_default(n: usize) -> Self {
69        Self(n)
70    }
71    fn counter_hint(self) -> Option<usize> {
72        Some(self.0)
73    }
74}
75
76impl std::fmt::Display for EdgeId {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        write!(f, "{}{}", Self::PREFIX, self.0)
79    }
80}
81
82impl std::fmt::Debug for EdgeId {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        write!(f, "{}{}", Self::PREFIX, self.0)
85    }
86}