Skip to main content

hydro_lang/location/
member_id.rs

1use std::fmt::{Debug, Display};
2use std::hash::Hash;
3use std::marker::PhantomData;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Deserialize, Serialize, Debug)]
8pub enum TaglessMemberId {
9    Legacy { raw_id: u32 },
10    Docker { container_name: String },
11    Maelstrom { node_id: String },
12}
13
14impl TaglessMemberId {
15    pub fn from_raw_id(raw_id: u32) -> Self {
16        Self::Legacy { raw_id }
17    }
18
19    pub fn from_container_name(container_name: impl Into<String>) -> Self {
20        Self::Docker {
21            container_name: container_name.into(),
22        }
23    }
24
25    pub fn from_maelstrom_node_id(node_id: impl ToString) -> Self {
26        Self::Maelstrom {
27            node_id: node_id.to_string(),
28        }
29    }
30
31    pub fn get_raw_id(&self) -> u32 {
32        match self {
33            TaglessMemberId::Legacy { raw_id } => *raw_id,
34            _ => panic!(),
35        }
36    }
37
38    pub fn get_container_name(&self) -> String {
39        match &self {
40            TaglessMemberId::Docker { container_name } => container_name.clone(),
41            _ => panic!(),
42        }
43    }
44
45    pub fn get_maelstrom_node_id(&self) -> String {
46        match &self {
47            TaglessMemberId::Maelstrom { node_id } => node_id.clone(),
48            _ => panic!(),
49        }
50    }
51}
52
53impl Hash for TaglessMemberId {
54    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
55        match self {
56            TaglessMemberId::Legacy { raw_id } => raw_id.hash(state),
57            TaglessMemberId::Docker { container_name } => container_name.hash(state),
58            TaglessMemberId::Maelstrom { node_id } => node_id.hash(state),
59        }
60    }
61}
62
63impl PartialEq for TaglessMemberId {
64    fn eq(&self, other: &Self) -> bool {
65        match (self, other) {
66            (
67                TaglessMemberId::Legacy { raw_id },
68                TaglessMemberId::Legacy {
69                    raw_id: other_raw_id,
70                },
71            ) => raw_id == other_raw_id,
72            (
73                TaglessMemberId::Docker { container_name },
74                TaglessMemberId::Docker {
75                    container_name: other_container_name,
76                },
77            ) => container_name == other_container_name,
78            (
79                TaglessMemberId::Maelstrom { node_id },
80                TaglessMemberId::Maelstrom {
81                    node_id: other_node_id,
82                },
83            ) => node_id == other_node_id,
84            _ => unreachable!(),
85        }
86    }
87}
88
89impl Eq for TaglessMemberId {}
90
91impl PartialOrd for TaglessMemberId {
92    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
93        Some(self.cmp(other))
94    }
95}
96
97impl Ord for TaglessMemberId {
98    // Comparing tags of different deployment origins means something has gone very wrong and the best thing to do is just crash immediately.
99    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
100        match (self, other) {
101            (
102                TaglessMemberId::Legacy { raw_id },
103                TaglessMemberId::Legacy {
104                    raw_id: other_raw_id,
105                },
106            ) => raw_id.cmp(other_raw_id),
107            (
108                TaglessMemberId::Docker { container_name },
109                TaglessMemberId::Docker {
110                    container_name: other_container_name,
111                },
112            ) => container_name.cmp(other_container_name),
113            (
114                TaglessMemberId::Maelstrom { node_id },
115                TaglessMemberId::Maelstrom {
116                    node_id: other_node_id,
117                },
118            ) => node_id.cmp(other_node_id),
119            _ => unreachable!(),
120        }
121    }
122}
123
124#[repr(transparent)]
125pub struct MemberId<Tag> {
126    inner: TaglessMemberId,
127    _phantom: PhantomData<Tag>,
128}
129
130impl<Tag> MemberId<Tag> {
131    pub fn into_tagless(self) -> TaglessMemberId {
132        self.inner
133    }
134
135    pub fn from_tagless(inner: TaglessMemberId) -> Self {
136        Self {
137            inner,
138            _phantom: Default::default(),
139        }
140    }
141
142    pub fn from_raw_id(raw_id: u32) -> Self {
143        Self {
144            inner: TaglessMemberId::from_raw_id(raw_id),
145            _phantom: Default::default(),
146        }
147    }
148
149    pub fn get_raw_id(&self) -> u32 {
150        self.inner.get_raw_id()
151    }
152}
153
154impl<Tag> Debug for MemberId<Tag> {
155    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156        Display::fmt(self, f)
157    }
158}
159
160impl<Tag> Display for MemberId<Tag> {
161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162        match &self.inner {
163            TaglessMemberId::Legacy { raw_id, .. } => {
164                write!(
165                    f,
166                    "MemberId::<{}>({})",
167                    std::any::type_name::<Tag>(),
168                    raw_id
169                )
170            }
171            TaglessMemberId::Docker { container_name, .. } => {
172                write!(
173                    f,
174                    "MemberId::<{}>(\"{}\")",
175                    std::any::type_name::<Tag>(),
176                    container_name
177                )
178            }
179            TaglessMemberId::Maelstrom { node_id, .. } => {
180                write!(
181                    f,
182                    "MemberId::<{}>(\"{}\")",
183                    std::any::type_name::<Tag>(),
184                    node_id
185                )
186            }
187        }
188    }
189}
190
191impl<Tag> Clone for MemberId<Tag> {
192    fn clone(&self) -> Self {
193        Self {
194            inner: self.inner.clone(),
195            _phantom: Default::default(),
196        }
197    }
198}
199
200impl<Tag> Serialize for MemberId<Tag> {
201    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
202    where
203        S: serde::Serializer,
204    {
205        self.inner.serialize(serializer)
206    }
207}
208
209impl<'a, Tag> Deserialize<'a> for MemberId<Tag> {
210    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
211    where
212        D: serde::Deserializer<'a>,
213    {
214        Ok(Self::from_tagless(TaglessMemberId::deserialize(
215            deserializer,
216        )?))
217    }
218}
219
220impl<Tag> PartialOrd for MemberId<Tag> {
221    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
222        Some(self.cmp(other))
223    }
224}
225
226impl<Tag> Ord for MemberId<Tag> {
227    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
228        self.inner.cmp(&other.inner)
229    }
230}
231
232impl<Tag> PartialEq for MemberId<Tag> {
233    fn eq(&self, other: &Self) -> bool {
234        self.inner == other.inner
235    }
236}
237
238impl<Tag> Eq for MemberId<Tag> {}
239
240impl<Tag> Hash for MemberId<Tag> {
241    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
242        self.inner.hash(state);
243        std::any::type_name::<Tag>().hash(state); // This seems like the a good thing to do. This will ensure that two member ids that come from different clusters but the same underlying host receive different hashes.
244    }
245}