cairo_lang_sierra/
ids.rs

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            /// Optional name for testing and debugging.
52            #[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/// The identity of a user type.
108#[derive(Clone, Debug, Derivative, Serialize, Deserialize)]
109#[derivative(Eq, Hash, PartialEq)]
110pub struct UserTypeId {
111    pub id: BigUint,
112    /// Optional name for testing and debugging.
113    #[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        // TODO(orizi): Extract Keccak into felt252 implementation and use it at the starknet
121        // crate as well.
122        let mut hasher = Keccak256::new();
123        hasher.update(s.as_bytes());
124        let mut result = hasher.finalize();
125        // Truncate result to 250 bits.
126        *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}