1use crate::{Ref, ServiceProvider};
2use std::any::type_name;
3use std::collections::hash_map::DefaultHasher;
4use std::fmt::{Display, Formatter, Result as FormatResult};
5use std::hash::{Hash, Hasher};
6
7#[derive(Clone, Debug, Eq)]
9pub struct Type {
10 id: u64,
11 name: String,
12 key: Option<String>,
13}
14
15impl Type {
16 pub fn of<T: ?Sized>() -> Self {
18 Type::new(type_name::<T>().to_string(), None)
19 }
20
21 pub fn keyed<TKey, TType: ?Sized>() -> Self {
23 Type::new(type_name::<TType>().to_string(), Some(type_name::<TKey>().to_string()))
24 }
25
26 pub fn factory_of<TSvc: ?Sized>() -> Self {
29 Type::new(type_name::<dyn Fn(&ServiceProvider) -> Ref<TSvc>>().to_string(), None)
30 }
31
32 pub fn unknown() -> Self {
34 Self::of::<()>()
35 }
36
37 pub fn with_key(&self, key: &Self) -> Self {
43 Type::new(self.name.clone(), Some(key.name.clone()))
44 }
45
46 fn new(name: String, key: Option<String>) -> Self {
47 let mut hasher = DefaultHasher::new();
48
49 name.hash(&mut hasher);
50
51 if let Some(ref val) = key {
52 val.hash(&mut hasher);
53 }
54
55 Self {
56 id: hasher.finish(),
57 name,
58 key,
59 }
60 }
61
62 #[inline]
64 pub fn id(&self) -> u64 {
65 self.id
66 }
67
68 #[inline]
70 pub fn name(&self) -> &str {
71 &self.name
72 }
73
74 #[inline]
77 pub fn deconstruct(t: &Type) -> (&str, Option<&str>) {
78 (&t.name, t.key.as_deref())
79 }
80}
81
82impl PartialEq<Type> for Type {
83 #[inline]
84 fn eq(&self, other: &Self) -> bool {
85 self.id == other.id
86 }
87}
88
89impl PartialEq<Type> for &Type {
90 #[inline]
91 fn eq(&self, other: &Type) -> bool {
92 self.id == other.id
93 }
94}
95
96impl Hash for Type {
97 fn hash<H: Hasher>(&self, state: &mut H) {
98 self.id.hash(state);
99 }
100}
101
102impl Display for Type {
103 fn fmt(&self, formatter: &mut Formatter<'_>) -> FormatResult {
104 formatter.write_str(&self.name)
105 }
106}