hydro_lang/location/
member_id.rs1use std::fmt::{Debug, Display};
13use std::hash::Hash;
14use std::marker::PhantomData;
15
16use serde::{Deserialize, Serialize};
17
18#[derive(Clone, Deserialize, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
27#[non_exhaustive] pub enum TaglessMemberId {
29 #[cfg(any(
31 feature = "deploy",
32 feature = "deploy_integration",
33 feature = "embedded_runtime"
34 ))]
35 #[cfg_attr(
36 docsrs,
37 doc(cfg(any(
38 feature = "deploy",
39 feature = "deploy_integration",
40 feature = "embedded_runtime"
41 )))
42 )]
43 Legacy {
44 raw_id: u32,
46 },
47 #[cfg(feature = "docker_runtime")]
49 #[cfg_attr(docsrs, doc(cfg(feature = "docker_runtime")))]
50 Docker {
51 container_name: String,
53 },
54 #[cfg(feature = "maelstrom_runtime")]
56 #[cfg_attr(docsrs, doc(cfg(feature = "maelstrom_runtime")))]
57 Maelstrom {
58 node_id: String,
60 },
61}
62
63macro_rules! assert_feature {
64 (#[cfg($meta:meta)] $( $code:stmt )+) => {
65 #[cfg(not($meta))]
66 panic!("Feature {:?} is not enabled.", stringify!($meta));
67
68 #[cfg($meta)]
69 {
70 $( $code )+
71 }
72 };
73}
74
75impl TaglessMemberId {
76 pub fn from_raw_id(_raw_id: u32) -> Self {
81 assert_feature! {
82 #[cfg(any(feature = "deploy", feature = "deploy_integration", feature = "embedded_runtime"))]
83 Self::Legacy { raw_id: _raw_id }
84 }
85 }
86
87 pub fn get_raw_id(&self) -> u32 {
93 assert_feature! {
94 #[cfg(feature = "deploy_integration")]
95 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
96 #[allow(
97 irrefutable_let_patterns,
98 reason = "Depends on features."
99 )]
100 let TaglessMemberId::Legacy { raw_id } = self else {
101 panic!("Not `Legacy` variant.");
102 }
103 *raw_id
104 }
105 }
106
107 pub fn from_container_name(_container_name: impl Into<String>) -> Self {
112 assert_feature! {
113 #[cfg(feature = "docker_runtime")]
114 Self::Docker {
115 container_name: _container_name.into(),
116 }
117 }
118 }
119
120 pub fn get_container_name(&self) -> &str {
126 assert_feature! {
127 #[cfg(feature = "docker_runtime")]
128 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
129 #[allow(
130 irrefutable_let_patterns,
131 reason = "Depends on features."
132 )]
133 let TaglessMemberId::Docker { container_name } = self else {
134 panic!("Not `Docker` variant.");
135 }
136 container_name
137 }
138 }
139
140 pub fn from_maelstrom_node_id(_node_id: impl Into<String>) -> Self {
145 assert_feature! {
146 #[cfg(feature = "maelstrom_runtime")]
147 Self::Maelstrom {
148 node_id: _node_id.into(),
149 }
150 }
151 }
152
153 pub fn get_maelstrom_node_id(&self) -> &str {
159 assert_feature! {
160 #[cfg(feature = "maelstrom_runtime")]
161 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
162 #[allow(
163 irrefutable_let_patterns,
164 reason = "Depends on features."
165 )]
166 let TaglessMemberId::Maelstrom { node_id } = self else {
167 panic!("Not `Maelstrom` variant.");
168 }
169 node_id
170 }
171 }
172}
173
174impl Display for TaglessMemberId {
175 fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
176 match self {
177 #[cfg(feature = "deploy_integration")]
178 TaglessMemberId::Legacy { raw_id } => write!(_f, "{}", raw_id),
179 #[cfg(feature = "docker_runtime")]
180 TaglessMemberId::Docker { container_name } => write!(_f, "{}", container_name),
181 #[cfg(feature = "maelstrom_runtime")]
182 TaglessMemberId::Maelstrom { node_id } => write!(_f, "{}", node_id),
183 #[expect(
184 clippy::allow_attributes,
185 reason = "Only triggers when `TaglessMemberId` is empty."
186 )]
187 #[allow(
188 unreachable_patterns,
189 reason = "Needed when `TaglessMemberId` is empty."
190 )]
191 _ => panic!(),
192 }
193 }
194}
195
196#[repr(transparent)]
202pub struct MemberId<Tag> {
203 inner: TaglessMemberId,
204 _phantom: PhantomData<Tag>,
205}
206
207impl<Tag> MemberId<Tag> {
208 pub fn into_tagless(self) -> TaglessMemberId {
211 self.inner
212 }
213
214 pub fn from_tagless(inner: TaglessMemberId) -> Self {
216 Self {
217 inner,
218 _phantom: Default::default(),
219 }
220 }
221
222 pub fn from_raw_id(raw_id: u32) -> Self {
227 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
228 #[allow(
229 unreachable_code,
230 reason = "`inner` may be uninhabited depending on features."
231 )]
232 Self {
233 inner: TaglessMemberId::from_raw_id(raw_id),
234 _phantom: Default::default(),
235 }
236 }
237
238 pub fn get_raw_id(&self) -> u32 {
244 self.inner.get_raw_id()
245 }
246}
247
248impl<Tag> Debug for MemberId<Tag> {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 Display::fmt(self, f)
251 }
252}
253
254impl<Tag> Display for MemberId<Tag> {
255 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
256 write!(
257 f,
258 "MemberId::<{}>({})",
259 std::any::type_name::<Tag>(),
260 self.inner
261 )
262 }
263}
264
265impl<Tag> Clone for MemberId<Tag> {
266 fn clone(&self) -> Self {
267 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
268 #[allow(
269 unreachable_code,
270 reason = "`inner` may be uninhabited depending on features."
271 )]
272 Self {
273 inner: self.inner.clone(),
274 _phantom: Default::default(),
275 }
276 }
277}
278
279impl<Tag> Serialize for MemberId<Tag> {
280 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
281 where
282 S: serde::Serializer,
283 {
284 self.inner.serialize(serializer)
285 }
286}
287
288impl<'a, Tag> Deserialize<'a> for MemberId<Tag> {
289 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
290 where
291 D: serde::Deserializer<'a>,
292 {
293 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
294 #[allow(
295 unreachable_code,
296 reason = "`inner` may be uninhabited depending on features."
297 )]
298 Ok(Self::from_tagless(TaglessMemberId::deserialize(
299 deserializer,
300 )?))
301 }
302}
303
304impl<Tag> PartialOrd for MemberId<Tag> {
305 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
306 Some(self.cmp(other))
307 }
308}
309
310impl<Tag> Ord for MemberId<Tag> {
311 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
312 self.inner.cmp(&other.inner)
313 }
314}
315
316impl<Tag> PartialEq for MemberId<Tag> {
317 fn eq(&self, other: &Self) -> bool {
318 self.inner == other.inner
319 }
320}
321
322impl<Tag> Eq for MemberId<Tag> {}
323
324impl<Tag> Hash for MemberId<Tag> {
325 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
326 self.inner.hash(state);
327 std::any::type_name::<Tag>().hash(state);
330 }
331}