cairo_lang_sierra/
ids.rs

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