blockworx/store.rs
1//! Id newtypes for the legacy document model.
2//!
3//! These belong to the legacy document model (`crate::document`), its
4//! KDL/JSON schema, and the waist that still reads them: the editor's own
5//! ids are `blockworx_doc::id::Id<K>`, so nothing outside those places
6//! names a newtype from here, and phase 7 demolishes them with the model.
7//! [`IdMap`](crate::presentation::store::IdMap), its `IdMapExt`, `IdSet`,
8//! and [`EdgeId`](crate::presentation::store::EdgeId) — the one id the
9//! presentation layer mints for itself and keeps — moved to
10//! `crate::presentation::store`.
11//!
12//! Legacy ids are opaque, code-assigned counters (a newtype-wrapped `usize`)
13//! unique within one map. They are never user-editable; the visible label is a
14//! separate `tag` string. An id renders (via `Display`/`FromStr`) as its type
15//! prefix followed by the number (e.g. `b1`, `r3`, `p0`), which is the form the
16//! `schema` layer reads and writes on disk.
17
18// The legacy half of this module is unplugged with the model it belongs to
19// (F7), so its unused members are allowed rather than deleted — they go when
20// phase 7 deletes `crate::document`.
21#![allow(dead_code)]
22
23macro_rules! define_id {
24 ($name:ident, $prefix:literal) => {
25 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26 pub struct $name(usize);
27
28 impl $name {
29 const PREFIX: &'static str = $prefix;
30
31 /// Wrap a raw counter value. `const` so it can seed sentinel
32 /// constants (e.g. the port's own pin id `0`, which the
33 /// `max + 1` counter never auto-assigns). Not every id type uses
34 /// this, so allow it to go unused per type.
35 #[allow(dead_code)]
36 pub const fn new(n: usize) -> Self {
37 Self(n)
38 }
39
40 /// The `n`-th default id (the newtype wrapping `n`).
41 pub fn nth_default(n: usize) -> Self {
42 Self(n)
43 }
44
45 /// The wrapped counter value.
46 pub fn counter_hint(self) -> Option<usize> {
47 Some(self.0)
48 }
49 }
50
51 impl crate::presentation::store::KeyType for $name {
52 fn nth_default(n: usize) -> Self {
53 Self::nth_default(n)
54 }
55 fn counter_hint(self) -> Option<usize> {
56 Self::counter_hint(self)
57 }
58 }
59
60 impl std::fmt::Display for $name {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 write!(f, "{}{}", Self::PREFIX, self.0)
63 }
64 }
65
66 impl std::str::FromStr for $name {
67 type Err = String;
68 /// Parse the prefixed-number form (e.g. `b13`) emitted by `Display`.
69 /// Used by the hand-edited KDL document format.
70 fn from_str(s: &str) -> Result<Self, String> {
71 let digits = s.strip_prefix(Self::PREFIX).ok_or_else(|| {
72 format!(
73 "{} id {s:?} is missing the {:?} prefix",
74 stringify!($name),
75 Self::PREFIX
76 )
77 })?;
78 let n = digits
79 .parse()
80 .map_err(|_| format!("{} id {s:?} is not numeric", stringify!($name)))?;
81 Ok(Self(n))
82 }
83 }
84
85 impl std::fmt::Debug for $name {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 write!(f, "{}{}", Self::PREFIX, self.0)
88 }
89 }
90 };
91}
92pub(crate) use define_id;
93
94define_id!(WaypointId, "w");
95define_id!(WireLabelId, "l");
96define_id!(PinId, "p");
97define_id!(RectId, "b");
98define_id!(RouteId, "r");
99define_id!(TextId, "t");
100define_id!(CommentId, "c");
101define_id!(ImageId, "i");