1use derivative::Derivative;
2use num_bigint::BigUint;
3use num_traits::ToPrimitive;
4use serde::{Deserialize, Serialize};
5use sha3::{Digest, Keccak256};
6use smol_str::SmolStr;
7
8macro_rules! define_generic_identity {
9 ($doc:literal, $type_name:ident) => {
10 #[doc=$doc]
11 #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
12 pub struct $type_name(pub SmolStr);
13 impl $type_name {
14 pub const fn new_inline(name: &'static str) -> Self {
15 Self(SmolStr::new_inline(name))
16 }
17
18 pub fn from_string(name: impl Into<SmolStr>) -> Self {
19 Self(name.into())
20 }
21 }
22 impl From<&str> for $type_name {
23 fn from(name: &str) -> Self {
24 Self::from_string(name.to_string())
25 }
26 }
27 impl From<String> for $type_name {
28 fn from(name: String) -> Self {
29 Self::from_string(name)
30 }
31 }
32 impl From<SmolStr> for $type_name {
33 fn from(name: SmolStr) -> Self {
34 Self::from_string(name)
35 }
36 }
37 };
38}
39
40define_generic_identity!("The identity of a generic library function", GenericLibfuncId);
41
42define_generic_identity!("The identity of a generic type.", GenericTypeId);
43
44macro_rules! define_identity {
45 ($doc:literal, $type_name:ident) => {
46 #[doc=$doc]
47 #[derive(Clone, Debug, Derivative, Serialize, Deserialize)]
48 #[derivative(Eq, Hash, PartialEq)]
49 pub struct $type_name {
50 pub id: u64,
51 #[derivative(Hash = "ignore")]
53 #[derivative(PartialEq = "ignore")]
54 pub debug_name: Option<SmolStr>,
55 }
56 impl $type_name {
57 pub fn new(id: u64) -> Self {
58 Self { id, debug_name: None }
59 }
60
61 pub fn from_string(name: impl Into<SmolStr>) -> Self {
62 let s: SmolStr = name.into();
63 Self { id: const_fnv1a_hash::fnv1a_hash_str_64(&s), debug_name: Some(s) }
64 }
65 }
66 impl From<&str> for $type_name {
67 fn from(name: &str) -> Self {
68 Self::from_string(name.to_string())
69 }
70 }
71 impl From<String> for $type_name {
72 fn from(name: String) -> Self {
73 Self::from_string(name)
74 }
75 }
76 impl From<SmolStr> for $type_name {
77 fn from(name: SmolStr) -> Self {
78 Self::from_string(name)
79 }
80 }
81 impl From<u64> for $type_name {
82 fn from(id: u64) -> Self {
83 Self::new(id)
84 }
85 }
86 impl salsa::InternKey for $type_name {
87 fn from_intern_id(salsa_id: salsa::InternId) -> Self {
88 Self::new(salsa_id.as_u32() as u64)
89 }
90
91 fn as_intern_id(&self) -> salsa::InternId {
92 let id_usize: usize = self.id.try_into().unwrap();
93 id_usize.into()
94 }
95 }
96 };
97}
98
99define_identity!("The identity of a concrete library function.", ConcreteLibfuncId);
100
101define_identity!("The identity of a user function.", FunctionId);
102
103define_identity!("The identity of a variable.", VarId);
104
105define_identity!("The identity of a concrete type.", ConcreteTypeId);
106
107#[derive(Clone, Debug, Derivative, Serialize, Deserialize)]
109#[derivative(Eq, Hash, PartialEq)]
110pub struct UserTypeId {
111 pub id: BigUint,
112 #[derivative(Hash = "ignore")]
114 #[derivative(PartialEq = "ignore")]
115 pub debug_name: Option<SmolStr>,
116}
117impl UserTypeId {
118 pub fn from_string(name: impl Into<SmolStr>) -> Self {
119 let s: SmolStr = name.into();
120 let mut hasher = Keccak256::new();
123 hasher.update(s.as_bytes());
124 let mut result = hasher.finalize();
125 *result.first_mut().unwrap() &= 3;
127 let id = BigUint::from_bytes_be(&result);
128 Self { id, debug_name: Some(s) }
129 }
130}
131impl From<&str> for UserTypeId {
132 fn from(name: &str) -> Self {
133 Self::from_string(name.to_string())
134 }
135}
136impl From<String> for UserTypeId {
137 fn from(name: String) -> Self {
138 Self::from_string(name)
139 }
140}
141impl salsa::InternKey for UserTypeId {
142 fn from_intern_id(salsa_id: salsa::InternId) -> Self {
143 Self { id: salsa_id.as_usize().into(), debug_name: None }
144 }
145
146 fn as_intern_id(&self) -> salsa::InternId {
147 self.id.to_usize().unwrap().into()
148 }
149}