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}