1use core::fmt;
4use core::sync::atomic::{AtomicU64, Ordering};
5
6static NEXT_GRAPH_ID: AtomicU64 = AtomicU64::new(1);
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub(crate) struct GraphId(u64);
10
11impl GraphId {
12 pub(crate) fn fresh() -> Self {
13 let value = NEXT_GRAPH_ID
14 .try_update(Ordering::Relaxed, Ordering::Relaxed, |current| {
15 current.checked_add(1)
16 })
17 .expect("geometry graph identity space exhausted");
18 Self(value)
19 }
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct NodeId {
31 graph: GraphId,
32 index: u32,
33}
34
35impl NodeId {
36 pub(crate) fn from_index(graph: GraphId, index: usize) -> Self {
37 Self {
38 graph,
39 index: u32::try_from(index).expect("geometry graph exceeds u32 capacity"),
40 }
41 }
42
43 pub(crate) fn belongs_to(self, graph: GraphId) -> bool {
44 self.graph == graph
45 }
46
47 pub const fn index(self) -> usize {
49 self.index as usize
50 }
51}
52
53impl fmt::Display for NodeId {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "geometry#{}", self.index)
56 }
57}
58
59#[cfg(feature = "serde")]
60std::thread_local! {
61 static WIRE_BRAND: core::cell::Cell<Option<GraphId>> = const { core::cell::Cell::new(None) };
62}
63
64#[cfg(feature = "serde")]
72pub(crate) struct WireBrand {
73 previous: Option<GraphId>,
74}
75
76#[cfg(feature = "serde")]
77impl WireBrand {
78 pub(crate) fn enter(graph: GraphId) -> Self {
81 Self {
82 previous: WIRE_BRAND.with(|brand| brand.replace(Some(graph))),
83 }
84 }
85}
86
87#[cfg(feature = "serde")]
88impl Drop for WireBrand {
89 fn drop(&mut self) {
90 WIRE_BRAND.with(|brand| brand.set(self.previous));
91 }
92}
93
94#[cfg(feature = "serde")]
96impl serde::Serialize for NodeId {
97 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
98 serializer.serialize_u32(self.index)
99 }
100}
101
102#[cfg(feature = "serde")]
107impl<'de> serde::Deserialize<'de> for NodeId {
108 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
109 let index = <u32 as serde::Deserialize>::deserialize(deserializer)?;
110 match WIRE_BRAND.with(core::cell::Cell::get) {
111 Some(graph) => Ok(Self { graph, index }),
112 None => Err(serde::de::Error::custom(
113 "a node reference is only meaningful inside a geometry graph payload",
114 )),
115 }
116 }
117}