1use crate::container::descriptor::ServiceId;
61use std::any::TypeId;
62use std::marker::PhantomData;
63
64pub trait ServiceToken: Send + Sync + 'static {
117 type Service: ?Sized + Send + Sync + 'static;
122
123 fn service_type_id() -> TypeId
128 where
129 Self::Service: 'static,
130 {
131 TypeId::of::<Self::Service>()
132 }
133
134 fn service_type_name() -> &'static str {
139 std::any::type_name::<Self::Service>()
140 }
141
142 fn token_type_name() -> &'static str {
147 std::any::type_name::<Self>()
148 }
149}
150
151#[derive(Debug, Clone)]
156pub struct TokenBinding {
157 pub token_type_id: TypeId,
159 pub token_type_name: &'static str,
161 pub service_type_id: TypeId,
163 pub service_type_name: &'static str,
165 pub impl_type_id: TypeId,
167 pub impl_type_name: &'static str,
169 pub name: Option<String>,
171}
172
173impl TokenBinding {
174 pub fn new<Token, Impl>() -> Self
176 where
177 Token: ServiceToken,
178 Impl: Send + Sync + 'static,
179 {
180 Self {
181 token_type_id: TypeId::of::<Token>(),
182 token_type_name: std::any::type_name::<Token>(),
183 service_type_id: Token::service_type_id(),
184 service_type_name: Token::service_type_name(),
185 impl_type_id: TypeId::of::<Impl>(),
186 impl_type_name: std::any::type_name::<Impl>(),
187 name: None,
188 }
189 }
190
191 pub fn named<Token, Impl>(name: impl Into<String>) -> Self
193 where
194 Token: ServiceToken,
195 Impl: Send + Sync + 'static,
196 {
197 let mut binding = Self::new::<Token, Impl>();
198 binding.name = Some(name.into());
199 binding
200 }
201
202 pub fn to_service_id(&self) -> ServiceId {
204 if let Some(name) = &self.name {
205 ServiceId::named_by_ids(self.service_type_id, self.service_type_name, name.clone())
206 } else {
207 ServiceId::by_ids(self.service_type_id, self.service_type_name)
208 }
209 }
210
211 pub fn matches_token<Token: ServiceToken>(&self) -> bool {
213 self.token_type_id == TypeId::of::<Token>()
214 }
215
216 pub fn validate_implementation<Token, Impl>() -> Result<(), String>
221 where
222 Token: ServiceToken,
223 Impl: Send + Sync + 'static,
224 {
225 let token_service_id = Token::service_type_id();
226 let impl_type_id = TypeId::of::<Impl>();
227
228 if token_service_id == TypeId::of::<()>() {
230 return Err(format!(
231 "Invalid service type for token {}: service type appears to be ()",
232 Token::token_type_name()
233 ));
234 }
235
236 if token_service_id == impl_type_id {
238 return Err(format!(
239 "Token {} maps to itself: implementation type {} cannot be the same as service type {}",
240 Token::token_type_name(),
241 std::any::type_name::<Impl>(),
242 Token::service_type_name()
243 ));
244 }
245
246 let token_name = Token::token_type_name();
248 let service_name = Token::service_type_name();
249 let impl_name = std::any::type_name::<Impl>();
250
251 if token_name.is_empty() {
252 return Err("Invalid token: token type name is empty".to_string());
253 }
254
255 if service_name.is_empty() {
256 return Err(format!(
257 "Invalid token {}: service type name is empty",
258 token_name
259 ));
260 }
261
262 if impl_name.is_empty() {
263 return Err(format!(
264 "Invalid implementation for token {}: implementation type name is empty",
265 token_name
266 ));
267 }
268
269 if service_name.contains("dyn ") && impl_name.contains("dyn ") {
271 return Err(format!(
272 "Invalid binding for token {}: both service ({}) and implementation ({}) appear to be trait objects. Implementation should be a concrete type.",
273 token_name,
274 service_name,
275 impl_name
276 ));
277 }
278
279 Ok(())
281 }
282}
283
284#[derive(Debug, Default)]
289pub struct TokenRegistry {
290 bindings: std::collections::HashMap<TypeId, Vec<TokenBinding>>,
292 defaults: std::collections::HashMap<TypeId, TokenBinding>,
294 named: std::collections::HashMap<(TypeId, String), TokenBinding>,
296}
297
298impl TokenRegistry {
299 pub fn new() -> Self {
301 Self::default()
302 }
303
304 pub fn register<Token, Impl>(&mut self) -> Result<(), String>
306 where
307 Token: ServiceToken,
308 Impl: Send + Sync + 'static,
309 {
310 TokenBinding::validate_implementation::<Token, Impl>()?;
312
313 let binding = TokenBinding::new::<Token, Impl>();
314 let token_type_id = TypeId::of::<Token>();
315
316 self.bindings
318 .entry(token_type_id)
319 .or_default()
320 .push(binding.clone());
321
322 self.defaults.entry(token_type_id).or_insert(binding);
324
325 Ok(())
326 }
327
328 pub fn register_named<Token, Impl>(&mut self, name: impl Into<String>) -> Result<(), String>
330 where
331 Token: ServiceToken,
332 Impl: Send + Sync + 'static,
333 {
334 TokenBinding::validate_implementation::<Token, Impl>()?;
336
337 let name = name.into();
338 let binding = TokenBinding::named::<Token, Impl>(&name);
339 let token_type_id = TypeId::of::<Token>();
340
341 self.bindings
343 .entry(token_type_id)
344 .or_default()
345 .push(binding.clone());
346
347 self.named.insert((token_type_id, name), binding);
349
350 Ok(())
351 }
352
353 pub fn get_default<Token: ServiceToken>(&self) -> Option<&TokenBinding> {
355 let token_type_id = TypeId::of::<Token>();
356 self.defaults.get(&token_type_id)
357 }
358
359 pub fn get_named<Token: ServiceToken>(&self, name: &str) -> Option<&TokenBinding> {
361 let token_type_id = TypeId::of::<Token>();
362 self.named.get(&(token_type_id, name.to_string()))
363 }
364
365 pub fn get_all<Token: ServiceToken>(&self) -> Option<&Vec<TokenBinding>> {
367 let token_type_id = TypeId::of::<Token>();
368 self.bindings.get(&token_type_id)
369 }
370
371 pub fn contains<Token: ServiceToken>(&self) -> bool {
373 let token_type_id = TypeId::of::<Token>();
374 self.defaults.contains_key(&token_type_id)
375 }
376
377 pub fn contains_named<Token: ServiceToken>(&self, name: &str) -> bool {
379 let token_type_id = TypeId::of::<Token>();
380 self.named.contains_key(&(token_type_id, name.to_string()))
381 }
382
383 pub fn token_types(&self) -> Vec<TypeId> {
385 self.defaults.keys().cloned().collect()
386 }
387
388 pub fn stats(&self) -> TokenRegistryStats {
390 TokenRegistryStats {
391 total_tokens: self.bindings.len(), total_bindings: self.bindings.values().map(|v| v.len()).sum(),
393 named_bindings: self.named.len(),
394 }
395 }
396
397 pub fn validate_all_bindings(&self) -> Vec<String> {
402 let mut errors = Vec::new();
403
404 for (token_type_id, bindings) in &self.bindings {
406 if bindings.is_empty() {
407 errors.push(format!(
408 "Token type {:?} has empty bindings list",
409 token_type_id
410 ));
411 continue;
412 }
413
414 let first_binding = &bindings[0];
416 for binding in bindings.iter().skip(1) {
417 if binding.token_type_id != first_binding.token_type_id {
418 errors.push(format!(
419 "Inconsistent token type IDs in bindings for token type {:?}",
420 token_type_id
421 ));
422 }
423
424 if binding.service_type_id != first_binding.service_type_id {
425 errors.push(format!(
426 "Inconsistent service type IDs for token {}: {} vs {}",
427 binding.token_type_name,
428 binding.service_type_name,
429 first_binding.service_type_name
430 ));
431 }
432 }
433
434 for binding in bindings {
436 if let Some(name) = &binding.name {
437 if !self
438 .named
439 .contains_key(&(binding.token_type_id, name.clone()))
440 {
441 errors.push(format!(
442 "Named binding {} for token {} exists in bindings list but not in named map",
443 name,
444 binding.token_type_name
445 ));
446 }
447 }
448 }
449 }
450
451 for ((token_type_id, name), binding) in &self.named {
453 if !self.bindings.contains_key(token_type_id) {
454 errors.push(format!(
455 "Named binding {} for token {} exists in named map but token has no bindings",
456 name, binding.token_type_name
457 ));
458 }
459 }
460
461 errors
462 }
463
464 pub fn has_binding_conflicts<Token: ServiceToken>(&self) -> Vec<String> {
466 let mut conflicts = Vec::new();
467 let token_type_id = TypeId::of::<Token>();
468
469 if let Some(bindings) = self.bindings.get(&token_type_id) {
470 let default_count = self.defaults.contains_key(&token_type_id) as usize;
472 if default_count == 0 && !bindings.is_empty() {
473 conflicts.push(format!(
474 "Token {} has bindings but no default binding",
475 Token::token_type_name()
476 ));
477 }
478
479 let mut seen_names = std::collections::HashSet::new();
481 for binding in bindings {
482 if let Some(name) = &binding.name {
483 if !seen_names.insert(name.clone()) {
484 conflicts.push(format!(
485 "Token {} has duplicate named binding: {}",
486 Token::token_type_name(),
487 name
488 ));
489 }
490 }
491 }
492 }
493
494 conflicts
495 }
496
497 pub fn get_token_info<Token: ServiceToken>(&self) -> Option<TokenInfo> {
499 let token_type_id = TypeId::of::<Token>();
500 let bindings = self.bindings.get(&token_type_id)?;
501 let default_binding = self.defaults.get(&token_type_id);
502
503 let named_bindings: Vec<String> = self
504 .named
505 .iter()
506 .filter_map(|((tid, name), _)| {
507 if *tid == token_type_id {
508 Some(name.clone())
509 } else {
510 None
511 }
512 })
513 .collect();
514
515 Some(TokenInfo {
516 token_name: Token::token_type_name().to_string(),
517 service_name: Token::service_type_name().to_string(),
518 total_bindings: bindings.len(),
519 has_default: default_binding.is_some(),
520 named_bindings,
521 implementation_types: bindings
522 .iter()
523 .map(|b| b.impl_type_name.to_string())
524 .collect(),
525 })
526 }
527
528 #[cfg(test)]
530 pub fn clear(&mut self) {
531 self.bindings.clear();
532 self.defaults.clear();
533 self.named.clear();
534 }
535}
536
537#[derive(Debug, Clone, PartialEq, Eq)]
539pub struct TokenRegistryStats {
540 pub total_tokens: usize,
542 pub total_bindings: usize,
544 pub named_bindings: usize,
546}
547
548#[derive(Debug, Clone)]
550pub struct TokenInfo {
551 pub token_name: String,
553 pub service_name: String,
555 pub total_bindings: usize,
557 pub has_default: bool,
559 pub named_bindings: Vec<String>,
561 pub implementation_types: Vec<String>,
563}
564
565pub trait TokenReference {
570 type Token: ServiceToken;
572
573 fn token_type() -> PhantomData<Self::Token> {
575 PhantomData
576 }
577}
578
579impl<T: ServiceToken> TokenReference for &T {
580 type Token = T;
581}
582
583#[cfg(test)]
584mod tests {
585 use super::*;
586
587 trait TestService: Send + Sync {
589 #[allow(dead_code)]
590 fn test(&self) -> String;
591 }
592
593 struct TestToken;
595 impl ServiceToken for TestToken {
596 type Service = dyn TestService;
597 }
598
599 struct TestImpl;
601 impl TestService for TestImpl {
602 fn test(&self) -> String {
603 "test".to_string()
604 }
605 }
606
607 #[test]
608 fn test_service_token_trait() {
609 assert_eq!(
610 TestToken::token_type_name(),
611 "elif_core::container::tokens::tests::TestToken"
612 );
613 assert_eq!(
614 TestToken::service_type_name(),
615 "dyn elif_core::container::tokens::tests::TestService"
616 );
617 }
618
619 #[test]
620 fn test_token_binding_creation() {
621 let binding = TokenBinding::new::<TestToken, TestImpl>();
622
623 assert_eq!(binding.token_type_id, TypeId::of::<TestToken>());
624 assert_eq!(binding.service_type_id, TypeId::of::<dyn TestService>());
625 assert_eq!(binding.impl_type_id, TypeId::of::<TestImpl>());
626 assert!(binding.name.is_none());
627 }
628
629 #[test]
630 fn test_named_token_binding() {
631 let binding = TokenBinding::named::<TestToken, TestImpl>("primary");
632
633 assert_eq!(binding.name, Some("primary".to_string()));
634 assert!(binding.matches_token::<TestToken>());
635 }
636
637 #[test]
638 fn test_token_registry_basic() {
639 let mut registry = TokenRegistry::new();
640
641 assert!(!registry.contains::<TestToken>());
642
643 registry.register::<TestToken, TestImpl>().unwrap();
644
645 assert!(registry.contains::<TestToken>());
646
647 let binding = registry.get_default::<TestToken>().unwrap();
648 assert!(binding.matches_token::<TestToken>());
649 }
650
651 #[test]
652 fn test_token_registry_named() {
653 let mut registry = TokenRegistry::new();
654
655 registry
656 .register_named::<TestToken, TestImpl>("primary")
657 .unwrap();
658
659 assert!(registry.contains_named::<TestToken>("primary"));
660 assert!(!registry.contains_named::<TestToken>("secondary"));
661
662 let binding = registry.get_named::<TestToken>("primary").unwrap();
663 assert_eq!(binding.name, Some("primary".to_string()));
664 }
665
666 #[test]
667 fn test_token_registry_stats() {
668 let mut registry = TokenRegistry::new();
669
670 registry.register::<TestToken, TestImpl>().unwrap();
671 registry
672 .register_named::<TestToken, TestImpl>("primary")
673 .unwrap();
674
675 let stats = registry.stats();
676 assert_eq!(stats.total_tokens, 1);
677 assert_eq!(stats.total_bindings, 2);
678 assert_eq!(stats.named_bindings, 1);
679 }
680
681 #[test]
682 fn test_token_reference() {
683 let _phantom: PhantomData<TestToken> = <&TestToken as TokenReference>::token_type();
684 }
686}