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(crate) fn stable_hash(&self) -> u64 {
107 let mut hasher = DefaultHasher::new();
108 self.hash(&mut hasher);
109 hasher.finish()
110 }
111}
112
113impl From<&str> for ServiceKey {
114 fn from(value: &str) -> Self {
115 Self::new(value.to_owned())
116 }
117}
118
119impl From<String> for ServiceKey {
120 fn from(value: String) -> Self {
121 Self::new(value)
122 }
123}
124
125impl From<&String> for ServiceKey {
126 fn from(value: &String) -> Self {
127 Self::new(value.clone())
128 }
129}
130
131impl From<&ServiceKey> for ServiceKey {
132 fn from(value: &ServiceKey) -> Self {
133 value.clone()
134 }
135}
136
137impl fmt::Debug for ServiceKey {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 match &self.0 {
140 KeyRepr::Value(v) => write!(f, "{v:?}"),
141 KeyRepr::Any => f.write_str("AnyKey"),
142 }
143 }
144}
145
146impl fmt::Display for ServiceKey {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 match &self.0 {
149 KeyRepr::Value(v) => {
150 if let Some(s) = v.as_any().downcast_ref::<String>() {
153 f.write_str(s)
154 } else {
155 write!(f, "{v:?}")
156 }
157 }
158 KeyRepr::Any => f.write_str("AnyKey"),
159 }
160 }
161}
162
163impl PartialEq for ServiceKey {
164 fn eq(&self, other: &Self) -> bool {
165 match (&self.0, &other.0) {
166 (KeyRepr::Any, KeyRepr::Any) => true,
167 (KeyRepr::Value(a), KeyRepr::Value(b)) => {
168 a.as_any().type_id() == b.as_any().type_id() && a.key_eq(b.as_any())
169 }
170 _ => false,
171 }
172 }
173}
174
175impl Eq for ServiceKey {}
176
177impl Hash for ServiceKey {
178 fn hash<H: Hasher>(&self, state: &mut H) {
179 match &self.0 {
180 KeyRepr::Any => state.write_u8(0),
181 KeyRepr::Value(v) => {
182 state.write_u8(1);
183 v.as_any().type_id().hash(state);
184 v.key_hash().hash(state);
185 }
186 }
187 }
188}
189
190#[derive(Debug, Clone, Copy, Default)]
194pub struct KeyedService;
195
196impl KeyedService {
197 pub fn any_key() -> ServiceKey {
199 ServiceKey::any_key()
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use std::collections::HashSet;
207
208 #[derive(Debug, PartialEq, Eq, Hash)]
209 enum Db {
210 Read,
211 Write,
212 }
213
214 #[test]
215 fn typed_keys_compare_and_hash() {
216 let mut set = HashSet::new();
217 set.insert(ServiceKey::new(Db::Read));
218 set.insert(ServiceKey::new(Db::Write));
219 set.insert(ServiceKey::new(Db::Read));
220 assert_eq!(set.len(), 2);
221 assert_eq!(ServiceKey::new(Db::Read), ServiceKey::new(Db::Read));
222 assert_ne!(ServiceKey::new(Db::Read), ServiceKey::new(Db::Write));
223 }
224
225 #[test]
226 fn string_keys_are_typed_keys() {
227 assert_eq!(ServiceKey::from("a"), ServiceKey::from("a".to_string()));
228 assert_ne!(ServiceKey::from("a"), ServiceKey::from("b"));
229 assert_ne!(ServiceKey::new(1_u32), ServiceKey::new(1_u64));
231 }
232
233 #[test]
234 fn any_key_identity() {
235 assert!(ServiceKey::any_key().is_any());
236 assert_eq!(ServiceKey::any_key(), KeyedService::any_key());
237 assert_ne!(ServiceKey::any_key(), ServiceKey::from("AnyKey"));
238 assert_ne!(ServiceKey::any_key(), ServiceKey::new("AnyKey"));
239 }
240
241 #[test]
242 fn debug_and_display_are_stable_enough_for_errors() {
243 assert_eq!(format!("{:?}", ServiceKey::any_key()), "AnyKey");
244 assert_eq!(format!("{}", ServiceKey::from("x")), "x");
245 assert_eq!(format!("{:?}", ServiceKey::from("x")), "\"x\"");
246 }
247
248 #[test]
249 fn string_literal_typed_key_is_a_distinct_type() {
250 assert_ne!(ServiceKey::new("x"), ServiceKey::from("x"));
253 }
254}