1use std::any::Any;
12use std::fmt;
13use std::hash::{DefaultHasher, Hash, Hasher};
14use std::sync::Arc;
15
16#[doc(hidden)]
18pub trait ErasedKeyValue: Any + Send + Sync + fmt::Debug {
19 fn as_any(&self) -> &dyn Any;
20 fn key_eq(&self, other: &dyn Any) -> bool;
21 fn key_hash(&self) -> u64;
22}
23
24impl<T> ErasedKeyValue for T
25where
26 T: Any + Send + Sync + Eq + Hash + fmt::Debug,
27{
28 fn as_any(&self) -> &dyn Any {
29 self
30 }
31
32 fn key_eq(&self, other: &dyn Any) -> bool {
33 other.downcast_ref::<T>() == Some(self)
34 }
35
36 fn key_hash(&self) -> u64 {
37 let mut hasher = DefaultHasher::new();
38 self.hash(&mut hasher);
39 hasher.finish()
40 }
41}
42
43#[derive(Clone)]
44enum KeyRepr {
45 Value(Arc<dyn ErasedKeyValue>),
46 Any,
47}
48
49#[derive(Clone)]
69pub struct ServiceKey(KeyRepr);
70
71impl ServiceKey {
72 pub fn new<T>(value: T) -> Self
84 where
85 T: Any + Send + Sync + Eq + Hash + fmt::Debug + 'static,
86 {
87 Self(KeyRepr::Value(Arc::new(value)))
88 }
89
90 pub fn any_key() -> Self {
97 Self(KeyRepr::Any)
98 }
99
100 pub fn is_any(&self) -> bool {
102 matches!(self.0, KeyRepr::Any)
103 }
104
105 pub fn as_str(&self) -> Option<&str> {
115 match &self.0 {
116 KeyRepr::Value(v) => {
117 let any = v.as_any();
118 if let Some(s) = any.downcast_ref::<String>() {
119 Some(s.as_str())
120 } else if let Some(s) = any.downcast_ref::<&'static str>() {
121 Some(*s)
122 } else {
123 None
124 }
125 }
126 KeyRepr::Any => None,
127 }
128 }
129
130 pub(crate) fn stable_hash(&self) -> u64 {
132 let mut hasher = DefaultHasher::new();
133 self.hash(&mut hasher);
134 hasher.finish()
135 }
136}
137
138impl From<&str> for ServiceKey {
139 fn from(value: &str) -> Self {
140 Self::new(value.to_owned())
141 }
142}
143
144impl From<String> for ServiceKey {
145 fn from(value: String) -> Self {
146 Self::new(value)
147 }
148}
149
150impl From<&String> for ServiceKey {
151 fn from(value: &String) -> Self {
152 Self::new(value.clone())
153 }
154}
155
156impl From<&ServiceKey> for ServiceKey {
157 fn from(value: &ServiceKey) -> Self {
158 value.clone()
159 }
160}
161
162impl fmt::Debug for ServiceKey {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 match &self.0 {
165 KeyRepr::Value(v) => write!(f, "{v:?}"),
166 KeyRepr::Any => f.write_str("AnyKey"),
167 }
168 }
169}
170
171impl fmt::Display for ServiceKey {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 match &self.0 {
174 KeyRepr::Value(v) => {
175 if let Some(s) = v.as_any().downcast_ref::<String>() {
178 f.write_str(s)
179 } else {
180 write!(f, "{v:?}")
181 }
182 }
183 KeyRepr::Any => f.write_str("AnyKey"),
184 }
185 }
186}
187
188impl PartialEq for ServiceKey {
189 fn eq(&self, other: &Self) -> bool {
190 match (&self.0, &other.0) {
191 (KeyRepr::Any, KeyRepr::Any) => true,
192 (KeyRepr::Value(a), KeyRepr::Value(b)) => {
193 a.as_any().type_id() == b.as_any().type_id() && a.key_eq(b.as_any())
194 }
195 _ => false,
196 }
197 }
198}
199
200impl Eq for ServiceKey {}
201
202impl Hash for ServiceKey {
203 fn hash<H: Hasher>(&self, state: &mut H) {
204 match &self.0 {
205 KeyRepr::Any => state.write_u8(0),
206 KeyRepr::Value(v) => {
207 state.write_u8(1);
208 v.as_any().type_id().hash(state);
209 v.key_hash().hash(state);
210 }
211 }
212 }
213}
214
215#[derive(Debug, Clone, Copy, Default)]
219pub struct KeyedService;
220
221impl KeyedService {
222 pub fn any_key() -> ServiceKey {
224 ServiceKey::any_key()
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use std::collections::HashSet;
232
233 #[derive(Debug, PartialEq, Eq, Hash)]
234 enum Db {
235 Read,
236 Write,
237 }
238
239 #[test]
240 fn typed_keys_compare_and_hash() {
241 let mut set = HashSet::new();
242 set.insert(ServiceKey::new(Db::Read));
243 set.insert(ServiceKey::new(Db::Write));
244 set.insert(ServiceKey::new(Db::Read));
245 assert_eq!(set.len(), 2);
246 assert_eq!(ServiceKey::new(Db::Read), ServiceKey::new(Db::Read));
247 assert_ne!(ServiceKey::new(Db::Read), ServiceKey::new(Db::Write));
248 }
249
250 #[test]
251 fn string_keys_are_typed_keys() {
252 assert_eq!(ServiceKey::from("a"), ServiceKey::from("a".to_string()));
253 assert_ne!(ServiceKey::from("a"), ServiceKey::from("b"));
254 assert_ne!(ServiceKey::new(1_u32), ServiceKey::new(1_u64));
256 }
257
258 #[test]
259 fn any_key_identity() {
260 assert!(ServiceKey::any_key().is_any());
261 assert_eq!(ServiceKey::any_key(), KeyedService::any_key());
262 assert_ne!(ServiceKey::any_key(), ServiceKey::from("AnyKey"));
263 assert_ne!(ServiceKey::any_key(), ServiceKey::new("AnyKey"));
264 }
265
266 #[test]
267 fn as_str_only_for_string_like_keys() {
268 assert_eq!(ServiceKey::from("x").as_str(), Some("x"));
269 assert_eq!(ServiceKey::new("y").as_str(), Some("y"));
270 assert_eq!(ServiceKey::new(1_u32).as_str(), None);
271 assert_eq!(ServiceKey::any_key().as_str(), None);
272 }
273
274 #[test]
275 fn debug_and_display_are_stable_enough_for_errors() {
276 assert_eq!(format!("{:?}", ServiceKey::any_key()), "AnyKey");
277 assert_eq!(format!("{}", ServiceKey::from("x")), "x");
278 assert_eq!(format!("{:?}", ServiceKey::from("x")), "\"x\"");
279 }
280
281 #[test]
282 fn string_literal_typed_key_is_a_distinct_type() {
283 assert_ne!(ServiceKey::new("x"), ServiceKey::from("x"));
286 }
287}