1use std::cmp::Ordering;
26use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
27use std::hash::{Hash, Hasher};
28use std::str::FromStr;
29
30use impl_types::{GlobalIdImpl, ReactionIdImpl, ReactorIdImpl};
31use index_vec::Idx;
32
33macro_rules! simple_idx_type {
34 ($(#[$($attrs:tt)*])* $id:ident($impl_t:ty)) => {
35
36$(#[$($attrs)*])*
37#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
38#[repr(transparent)]
39pub struct $id($impl_t);
40
41impl $id {
42 pub const fn new(u: $impl_t) -> Self {
44 Self(u)
45 }
46
47 pub const fn raw(self) -> $impl_t {
48 self.0
49 }
50
51 pub(crate) fn plus(&self, u: usize) -> Self {
52 Self::from_usize(self.0 as usize + u)
53 }
54
55 pub(crate) const fn index(self) -> usize {
56 self.0 as usize
57 }
58
59 #[allow(unused)]
60 pub(crate) fn get_and_incr(&mut self) -> Self {
61 let id = *self;
62 *self = Self(self.0 + 1);
63 id
64 }
65}
66
67impl Idx for $id {
68 fn from_usize(idx: usize) -> Self {
69 debug_assert!(idx <= <$impl_t>::MAX as usize);
70 Self(idx as $impl_t)
71 }
72
73 fn index(self) -> usize {
74 self.0 as usize
75 }
76}
77
78impl Display for $id {
79 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
80 write!(f, "{}", self.0)
81 }
82}
83 };
84}
85
86simple_idx_type! {
87 LocalReactionId(ReactionIdImpl)
89}
90
91simple_idx_type! {
92 ReactorId(ReactorIdImpl)
95}
96
97macro_rules! global_id_newtype {
98 {$(#[$m:meta])* $id:ident} => {
99 $(#[$m])*
100 #[derive(Eq, Ord, PartialOrd, PartialEq, Hash, Copy, Clone)]
101 pub struct $id(pub(crate) GlobalId);
102
103 impl $id {
104 pub fn new(container: $crate::ReactorId, local: $crate::LocalReactionId) -> Self {
105 Self($crate::GlobalId::new(container, local))
106 }
107 }
108
109 impl Debug for $id {
110 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
111 write!(f, "{:?}", self.0)
112 }
113 }
114
115 impl Display for $id {
116 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
117 write!(f, "{}", self.0)
118 }
119 }
120 };
121}
122
123global_id_newtype! {
124 GlobalReactionId
126}
127
128#[derive(Eq, Copy, Clone)]
131pub(crate) struct GlobalId {
132 container: ReactorId,
133 local: LocalReactionId,
134}
135
136impl GlobalId {
137 pub fn new(container: ReactorId, local: LocalReactionId) -> Self {
138 Self { container, local }
139 }
140
141 #[allow(unused)]
142 pub(crate) fn from_raw(u: GlobalIdImpl) -> Self {
143 unsafe { std::mem::transmute(u) }
144 }
145
146 pub(crate) const fn container(&self) -> ReactorId {
147 self.container
148 }
149
150 pub(crate) const fn local(&self) -> LocalReactionId {
151 self.local
152 }
153}
154
155impl FromStr for GlobalId {
156 type Err = &'static str;
157
158 fn from_str(s: &str) -> Result<Self, Self::Err> {
159 if let Some((container, local)) = s.split_once('/') {
160 let container = container.parse::<ReactorIdImpl>().map_err(|_| "invalid reactor id")?;
161 let local = local.parse::<ReactionIdImpl>().map_err(|_| "invalid local id")?;
162 Ok(GlobalId::new(ReactorId::new(container), LocalReactionId::new(local)))
163 } else {
164 Err("Expected format {int}/{int}")
165 }
166 }
167}
168
169impl Hash for GlobalId {
174 #[inline]
175 fn hash<H: Hasher>(&self, state: &mut H) {
176 let as_impl: &GlobalIdImpl = unsafe { std::mem::transmute(self) };
177 Hash::hash(as_impl, state);
179 }
180}
181
182impl PartialEq for GlobalId {
184 fn eq(&self, other: &Self) -> bool {
185 let self_impl: &GlobalIdImpl = unsafe { std::mem::transmute(self) };
186 let other_impl: &GlobalIdImpl = unsafe { std::mem::transmute(other) };
187 self_impl == other_impl
188 }
189}
190
191impl Ord for GlobalId {
194 fn cmp(&self, other: &Self) -> Ordering {
195 let self_as_impl: &GlobalIdImpl = unsafe { std::mem::transmute(self) };
196 let other_as_impl: &GlobalIdImpl = unsafe { std::mem::transmute(other) };
197 self_as_impl.cmp(other_as_impl)
198 }
199}
200
201impl PartialOrd for GlobalId {
202 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
203 Some(self.cmp(other))
204 }
205}
206
207impl Debug for GlobalId {
208 #[inline]
209 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
210 <Self as Display>::fmt(self, f)
211 }
212}
213
214impl Display for GlobalId {
215 #[inline]
216 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
217 write!(f, "{}/{}", self.container(), self.local())
218 }
219}
220
221pub(crate) mod impl_types {
223 cfg_if! {
224 if #[cfg(all(target_pointer_width = "64", feature = "wide-ids"))] {
225 type MyUsize = usize;
226 type HalfUsize = u32;
227 } else {
228 type MyUsize = u32;
229 type HalfUsize = u16;
230 }
231 }
232
233 pub type TriggerIdImpl = MyUsize;
234 pub type ReactionIdImpl = HalfUsize;
235 pub type ReactorIdImpl = HalfUsize;
236 pub type GlobalIdImpl = MyUsize;
237 assert_eq_size!(GlobalIdImpl, (ReactorIdImpl, ReactionIdImpl));
238 assert_impl_all!(GlobalIdImpl: petgraph::graph::IndexType);
239 assert_impl_all!(ReactorIdImpl: petgraph::graph::IndexType);
240}