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