Skip to main content

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");