Skip to main content

pathfinder_common/
macros.rs

1/// Macros for newtypes stored with an sqlite INTEGER column.
2pub(super) mod i64_backed_u64 {
3
4    /// Generates `new`, `new_or_panic` and `get` methods, `PartialEq` against
5    /// `i64` and `u64`, and `fake::Dummy`.
6    macro_rules! new_get_partialeq {
7        ($target:ty) => {
8            impl $target {
9                pub const fn new(val: u64) -> Option<Self> {
10                    let max = i64::MAX as u64;
11                    // Range::contains is not const
12                    if val <= max {
13                        Some(Self(val))
14                    } else {
15                        None
16                    }
17                }
18
19                pub const fn new_or_panic(val: u64) -> Self {
20                    match Self::new(val) {
21                        Some(x) => x,
22                        None => panic!("Invalid constant"),
23                    }
24                }
25
26                pub const fn get(&self) -> u64 {
27                    self.0
28                }
29            }
30
31            impl PartialEq<u64> for $target {
32                fn eq(&self, other: &u64) -> bool {
33                    self.0 == *other
34                }
35            }
36
37            impl PartialEq<i64> for $target {
38                fn eq(&self, other: &i64) -> bool {
39                    u64::try_from(*other).map(|x| self == &x).unwrap_or(false)
40                }
41            }
42
43            impl<T> fake::Dummy<T> for $target {
44                fn dummy_with_rng<R: rand::Rng + ?Sized>(_: &T, rng: &mut R) -> Self {
45                    Self(rng.gen_range(0..i64::MAX as u64))
46                }
47            }
48        };
49    }
50
51    /// Generates a u64 alike serialization and deserialization.
52    macro_rules! serdes {
53        ($target:ty) => {
54            impl serde::Serialize for $target {
55                fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
56                where
57                    S: serde::Serializer,
58                {
59                    serializer.serialize_u64(self.0)
60                }
61            }
62
63            impl<'de> serde::Deserialize<'de> for $target {
64                fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
65                where
66                    D: serde::Deserializer<'de>,
67                {
68                    let raw = u64::deserialize(deserializer)?;
69                    <$target>::deserialize_value::<D::Error>(raw)
70                }
71            }
72
73            impl $target {
74                pub fn deserialize_value<E>(raw: u64) -> Result<Self, E>
75                where
76                    E: serde::de::Error,
77                {
78                    <$target>::new(raw).ok_or_else(|| {
79                        serde::de::Error::invalid_value(
80                            serde::de::Unexpected::Unsigned(raw),
81                            &"i64::MAX unsigned integer",
82                        )
83                    })
84                }
85            }
86        };
87    }
88
89    pub(crate) use new_get_partialeq;
90    pub(crate) use serdes;
91}
92
93/// Generates felt newtype-wrappers and the `macro_prelude` module.
94///
95/// Note that this is a single-use macro as it generates a module.
96///
97/// Usage:
98///     `felt_newtypes!([x1, x2, ..]; [y1, y2, ..])`
99/// where `x` is the set of `Felt` wrapper types and `y` the `Felt251` wrappers.
100macro_rules! felt_newtypes {
101    ([$($felt:ident),* $(,)?]; [$($felt251:ident),* $(,)?]) => {
102        crate::macros::felt_newtypes!(@define_felt $($felt),*);
103        crate::macros::felt_newtypes!(@define_felt251 $($felt251),*);
104
105        pub mod macro_prelude {
106            pub use super::felt;
107            pub use super::felt_bytes;
108
109            crate::macros::felt_newtypes!(@generate_felt_macro $($felt),*);
110            crate::macros::felt_newtypes!(@generate_felt251_macro $($felt251),*);
111
112            crate::macros::felt_newtypes!(@generate_use $($felt),*);
113            crate::macros::felt_newtypes!(@generate_use $($felt251),*);
114        }
115    };
116
117    (@define_felt $head:ident, $($tail:ident),+ $(,)?) => {
118        crate::macros::felt_newtypes!(@define_felt $head);
119        crate::macros::felt_newtypes!(@define_felt $($tail),+);
120    };
121
122    (@define_felt $target:ident) => {
123        paste::paste! {
124            #[derive(Copy, Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, PartialOrd, Ord, Dummy)]
125            pub struct $target(pub pathfinder_crypto::Felt);
126
127            #[allow(unused)]
128            impl $target {
129                pub const ZERO: Self = Self(pathfinder_crypto::Felt::ZERO);
130
131                pub fn as_inner(&self) -> &pathfinder_crypto::Felt {
132                    &self.0
133                }
134            }
135
136            $crate::macros::fmt::thin_debug!($target);
137            $crate::macros::fmt::thin_display!($target);
138        }
139    };
140
141    (@define_felt251 $head:ident, $($tail:ident),+ $(,)?) => {
142        crate::macros::felt_newtypes!(@define_felt251 $head);
143        crate::macros::felt_newtypes!(@define_felt251 $($tail),+);
144    };
145
146    (@define_felt251 $target:ident) => {
147        paste::paste! {
148            #[derive(Copy, Clone, Default, PartialEq, Eq, Hash, serde::Serialize, PartialOrd, Ord, Dummy)]
149            pub struct $target(pub pathfinder_crypto::Felt);
150
151            $crate::macros::fmt::thin_debug!($target);
152            $crate::macros::fmt::thin_display!($target);
153
154            impl $target {
155                pub const ZERO: Self = Self(pathfinder_crypto::Felt::ZERO);
156
157                pub fn as_inner(&self) -> &pathfinder_crypto::Felt {
158                    &self.0
159                }
160
161                pub const fn new(hash: Felt) -> Option<Self> {
162                    if hash.has_more_than_251_bits() {
163                        None
164                    } else {
165                        Some(Self(hash))
166                    }
167                }
168
169                pub const fn new_or_panic(hash: Felt) -> Self {
170                    match Self::new(hash) {
171                        Some(key) => key,
172                        None => panic!("Too many bits, need less for MPT keys"),
173                    }
174                }
175
176                pub const fn get(&self) -> &Felt {
177                    &self.0
178                }
179
180                pub fn view_bits(&self) -> &bitvec::slice::BitSlice<u8, bitvec::order::Msb0> {
181                    self.0.view_bits()
182                }
183            }
184
185            impl<'de> serde::Deserialize<'de> for $target {
186                fn deserialize<D>(de: D) -> Result<Self, D::Error>
187                where
188                    D: serde::Deserializer<'de>,
189                {
190                    let felt = Felt::deserialize(de)?;
191                    $target::new(felt).context("Felt251 overflow").map_err(serde::de::Error::custom)
192                }
193            }
194        }
195    };
196
197    (@generate_use $head:ident, $($tail:ident),+ $(,)?) => {
198        crate::macros::felt_newtypes!(@generate_use $head);
199        crate::macros::felt_newtypes!(@generate_use $($tail),+);
200    };
201
202    (@generate_use $target:ident) => {
203        paste::paste! {
204            pub use [<$target:snake>];
205            pub use [<$target:snake _bytes>];
206        }
207    };
208
209    (@generate_felt_macro $head:ident, $($tail:ident),+ $(,)?) => {
210        crate::macros::felt_newtypes!(@generate_felt_macro $head);
211        crate::macros::felt_newtypes!(@generate_felt_macro $($tail),+);
212    };
213
214    (@generate_felt_macro $target:ident) => {
215        paste::paste! {
216            #[macro_export]
217            macro_rules! [<$target:snake>] {
218                ($hex:expr) => {
219                    $crate::$target($crate::felt!($hex))
220                };
221            }
222
223            #[macro_export]
224            macro_rules! [<$target:snake _bytes>] {
225                ($bytes:expr) => {
226                    $crate::$target($crate::felt_bytes!($bytes))
227                };
228            }
229        }
230    };
231
232    (@generate_felt251_macro $head:ident, $($tail:ident),+ $(,)?) => {
233        crate::macros::felt_newtypes!(@generate_felt251_macro $head);
234        crate::macros::felt_newtypes!(@generate_felt251_macro $($tail),+);
235    };
236
237    (@generate_felt251_macro $target:ident) => {
238        paste::paste! {
239            #[macro_export]
240            macro_rules! [<$target:snake>] {
241                ($hex:expr) => {
242                    $crate::$target::new_or_panic($crate::felt!($hex))
243                };
244            }
245
246            #[macro_export]
247            macro_rules! [<$target:snake _bytes>] {
248                ($bytes:expr) => {
249                    $crate::$target::new_or_panic($crate::felt_bytes!($bytes))
250                };
251            }
252        }
253    };
254}
255pub(super) use felt_newtypes;
256
257pub(super) mod fmt {
258
259    /// Adds a thin display implementation which uses the inner fields Display.
260    macro_rules! thin_display {
261        ($target:ty) => {
262            impl std::fmt::Display for $target {
263                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264                    std::fmt::Display::fmt(&self.0, f)
265                }
266            }
267        };
268    }
269
270    /// Adds a thin Debug implementation, which skips `X(StarkHash(debug))` as
271    /// `X(debug)`.
272    ///
273    /// The implementation uses Display of the wrapped value to produce smallest
274    /// possible string, but still wraps it in a default Debug derive style
275    /// `TypeName(hash)`.
276    macro_rules! thin_debug {
277        ($target:ty) => {
278            impl std::fmt::Debug for $target {
279                fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280                    write!(fmt, "{}({})", stringify!($target), self.0)
281                }
282            }
283        };
284    }
285
286    pub(crate) use thin_debug;
287    pub(crate) use thin_display;
288}
289
290/// Creates a [Felt](pathfinder_crypto::Felt) from a hex string literal verified
291/// at compile time.
292#[macro_export]
293macro_rules! felt {
294    ($hex:expr) => {{
295        // This forces const evaluation of the macro call. Without this the invocation
296        // will only be evaluated at runtime.
297        use ::pathfinder_crypto;
298        const CONST_FELT: pathfinder_crypto::Felt =
299            match pathfinder_crypto::Felt::from_hex_str($hex) {
300                Ok(f) => f,
301                Err(pathfinder_crypto::HexParseError::InvalidNibble(_)) => {
302                    panic!("Invalid hex digit")
303                }
304                Err(pathfinder_crypto::HexParseError::InvalidLength { .. }) => {
305                    panic!("Too many hex digits")
306                }
307                Err(pathfinder_crypto::HexParseError::Overflow) => panic!("Felt overflow"),
308            };
309        CONST_FELT
310    }};
311}
312
313/// Creates a [`pathfinder_crypto::Felt`] from a byte slice, resulting in
314/// compile-time error when invalid.
315#[macro_export]
316macro_rules! felt_bytes {
317    ($bytes:expr) => {{
318        match pathfinder_crypto::Felt::from_be_slice($bytes) {
319            Ok(sh) => sh,
320            Err(pathfinder_crypto::OverflowError) => panic!("Invalid constant: OverflowError"),
321        }
322    }};
323}