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(feature = "deploy_integration")]
31 #[cfg_attr(docsrs, doc(cfg(feature = "deploy_integration")))]
32 Legacy {
33 raw_id: u32,
35 },
36 #[cfg(feature = "docker_runtime")]
38 #[cfg_attr(docsrs, doc(cfg(feature = "docker_runtime")))]
39 Docker {
40 container_name: String,
42 },
43 #[cfg(feature = "maelstrom_runtime")]
45 #[cfg_attr(docsrs, doc(cfg(feature = "maelstrom_runtime")))]
46 Maelstrom {
47 node_id: String,
49 },
50}
51
52macro_rules! assert_feature {
53 (#[cfg(feature = $feat:expr)] $( $code:stmt )+) => {
54 #[cfg(not(feature = $feat))]
55 panic!("Feature {:?} is not enabled.", $feat);
56
57 #[cfg(feature = $feat)]
58 {
59 $( $code )+
60 }
61 };
62}
63
64impl TaglessMemberId {
65 pub fn from_raw_id(_raw_id: u32) -> Self {
70 assert_feature! {
71 #[cfg(feature = "deploy_integration")]
72 Self::Legacy { raw_id: _raw_id }
73 }
74 }
75
76 pub fn get_raw_id(&self) -> u32 {
82 assert_feature! {
83 #[cfg(feature = "deploy_integration")]
84 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
85 #[allow(
86 irrefutable_let_patterns,
87 reason = "Depends on features."
88 )]
89 let TaglessMemberId::Legacy { raw_id } = self else {
90 panic!("Not `Legacy` variant.");
91 }
92 *raw_id
93 }
94 }
95
96 pub fn from_container_name(_container_name: impl Into<String>) -> Self {
101 assert_feature! {
102 #[cfg(feature = "docker_runtime")]
103 Self::Docker {
104 container_name: _container_name.into(),
105 }
106 }
107 }
108
109 pub fn get_container_name(&self) -> &str {
115 assert_feature! {
116 #[cfg(feature = "docker_runtime")]
117 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
118 #[allow(
119 irrefutable_let_patterns,
120 reason = "Depends on features."
121 )]
122 let TaglessMemberId::Docker { container_name } = self else {
123 panic!("Not `Docker` variant.");
124 }
125 container_name
126 }
127 }
128
129 pub fn from_maelstrom_node_id(_node_id: impl Into<String>) -> Self {
134 assert_feature! {
135 #[cfg(feature = "maelstrom_runtime")]
136 Self::Maelstrom {
137 node_id: _node_id.into(),
138 }
139 }
140 }
141
142 pub fn get_maelstrom_node_id(&self) -> &str {
148 assert_feature! {
149 #[cfg(feature = "maelstrom_runtime")]
150 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
151 #[allow(
152 irrefutable_let_patterns,
153 reason = "Depends on features."
154 )]
155 let TaglessMemberId::Maelstrom { node_id } = self else {
156 panic!("Not `Maelstrom` variant.");
157 }
158 node_id
159 }
160 }
161}
162
163impl Display for TaglessMemberId {
164 fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 match self {
166 #[cfg(feature = "deploy_integration")]
167 TaglessMemberId::Legacy { raw_id } => write!(_f, "{:?}", raw_id),
168 #[cfg(feature = "docker_runtime")]
169 TaglessMemberId::Docker { container_name } => write!(_f, "{:?}", container_name),
170 #[cfg(feature = "maelstrom_runtime")]
171 TaglessMemberId::Maelstrom { node_id } => write!(_f, "{:?}", node_id),
172 #[expect(
173 clippy::allow_attributes,
174 reason = "Only triggers when `TaglessMemberId` is empty."
175 )]
176 #[allow(
177 unreachable_patterns,
178 reason = "Needed when `TaglessMemberId` is empty."
179 )]
180 _ => panic!(),
181 }
182 }
183}
184
185#[repr(transparent)]
191pub struct MemberId<Tag> {
192 inner: TaglessMemberId,
193 _phantom: PhantomData<Tag>,
194}
195
196impl<Tag> MemberId<Tag> {
197 pub fn into_tagless(self) -> TaglessMemberId {
200 self.inner
201 }
202
203 pub fn from_tagless(inner: TaglessMemberId) -> Self {
205 Self {
206 inner,
207 _phantom: Default::default(),
208 }
209 }
210
211 pub fn from_raw_id(raw_id: u32) -> Self {
216 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
217 #[allow(
218 unreachable_code,
219 reason = "`inner` may be uninhabited depending on features."
220 )]
221 Self {
222 inner: TaglessMemberId::from_raw_id(raw_id),
223 _phantom: Default::default(),
224 }
225 }
226
227 pub fn get_raw_id(&self) -> u32 {
233 self.inner.get_raw_id()
234 }
235}
236
237impl<Tag> Debug for MemberId<Tag> {
238 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239 Display::fmt(self, f)
240 }
241}
242
243impl<Tag> Display for MemberId<Tag> {
244 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 write!(
246 f,
247 "MemberId::<{}>({})",
248 std::any::type_name::<Tag>(),
249 self.inner
250 )
251 }
252}
253
254impl<Tag> Clone for MemberId<Tag> {
255 fn clone(&self) -> Self {
256 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
257 #[allow(
258 unreachable_code,
259 reason = "`inner` may be uninhabited depending on features."
260 )]
261 Self {
262 inner: self.inner.clone(),
263 _phantom: Default::default(),
264 }
265 }
266}
267
268impl<Tag> Serialize for MemberId<Tag> {
269 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
270 where
271 S: serde::Serializer,
272 {
273 self.inner.serialize(serializer)
274 }
275}
276
277impl<'a, Tag> Deserialize<'a> for MemberId<Tag> {
278 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
279 where
280 D: serde::Deserializer<'a>,
281 {
282 #[expect(clippy::allow_attributes, reason = "Depends on features.")]
283 #[allow(
284 unreachable_code,
285 reason = "`inner` may be uninhabited depending on features."
286 )]
287 Ok(Self::from_tagless(TaglessMemberId::deserialize(
288 deserializer,
289 )?))
290 }
291}
292
293impl<Tag> PartialOrd for MemberId<Tag> {
294 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
295 Some(self.cmp(other))
296 }
297}
298
299impl<Tag> Ord for MemberId<Tag> {
300 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
301 self.inner.cmp(&other.inner)
302 }
303}
304
305impl<Tag> PartialEq for MemberId<Tag> {
306 fn eq(&self, other: &Self) -> bool {
307 self.inner == other.inner
308 }
309}
310
311impl<Tag> Eq for MemberId<Tag> {}
312
313impl<Tag> Hash for MemberId<Tag> {
314 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
315 self.inner.hash(state);
316 std::any::type_name::<Tag>().hash(state);
319 }
320}