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, serdes};
90}
91
92/// Generates felt newtype-wrappers and the `macro_prelude` module.
93///
94/// Note that this is a single-use macro as it generates a module.
95///
96/// Usage:
97///     `felt_newtypes!([x1, x2, ..]; [y1, y2, ..])`
98/// where `x` is the set of `Felt` wrapper types and `y` the `Felt251` wrappers.
99macro_rules! felt_newtypes {
100    ([$($felt:ident),* $(,)?]; [$($felt251:ident),* $(,)?]) => {
101        crate::macros::felt_newtypes!(@define_felt $($felt),*);
102        crate::macros::felt_newtypes!(@define_felt251 $($felt251),*);
103
104        pub mod macro_prelude {
105            pub use super::felt;
106            pub use super::felt_bytes;
107
108            crate::macros::felt_newtypes!(@generate_felt_macro $($felt),*);
109            crate::macros::felt_newtypes!(@generate_felt251_macro $($felt251),*);
110
111            crate::macros::felt_newtypes!(@generate_use $($felt),*);
112            crate::macros::felt_newtypes!(@generate_use $($felt251),*);
113        }
114    };
115
116    (@define_felt $head:ident, $($tail:ident),+ $(,)?) => {
117        crate::macros::felt_newtypes!(@define_felt $head);
118        crate::macros::felt_newtypes!(@define_felt $($tail),+);
119    };
120
121    (@define_felt $target:ident) => {
122        paste::paste! {
123            #[derive(Copy, Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, PartialOrd, Ord, Dummy)]
124            pub struct $target(pub pathfinder_crypto::Felt);
125
126            #[allow(unused)]
127            impl $target {
128                pub const ZERO: Self = Self(pathfinder_crypto::Felt::ZERO);
129
130                pub fn as_inner(&self) -> &pathfinder_crypto::Felt {
131                    &self.0
132                }
133            }
134
135            $crate::macros::fmt::thin_debug!($target);
136            $crate::macros::fmt::thin_display!($target);
137        }
138    };
139
140    (@define_felt251 $head:ident, $($tail:ident),+ $(,)?) => {
141        crate::macros::felt_newtypes!(@define_felt251 $head);
142        crate::macros::felt_newtypes!(@define_felt251 $($tail),+);
143    };
144
145    (@define_felt251 $target:ident) => {
146        paste::paste! {
147            #[derive(Copy, Clone, Default, PartialEq, Eq, Hash, serde::Serialize, PartialOrd, Ord, Dummy)]
148            pub struct $target(pub pathfinder_crypto::Felt);
149
150            $crate::macros::fmt::thin_debug!($target);
151            $crate::macros::fmt::thin_display!($target);
152
153            impl $target {
154                pub const ZERO: Self = Self(pathfinder_crypto::Felt::ZERO);
155
156                pub fn as_inner(&self) -> &pathfinder_crypto::Felt {
157                    &self.0
158                }
159
160                pub const fn new(hash: Felt) -> Option<Self> {
161                    if hash.has_more_than_251_bits() {
162                        None
163                    } else {
164                        Some(Self(hash))
165                    }
166                }
167
168                pub const fn new_or_panic(hash: Felt) -> Self {
169                    match Self::new(hash) {
170                        Some(key) => key,
171                        None => panic!("Too many bits, need less for MPT keys"),
172                    }
173                }
174
175                pub const fn get(&self) -> &Felt {
176                    &self.0
177                }
178
179                pub fn view_bits(&self) -> &bitvec::slice::BitSlice<u8, bitvec::order::Msb0> {
180                    self.0.view_bits()
181                }
182            }
183
184            impl<'de> serde::Deserialize<'de> for $target {
185                fn deserialize<D>(de: D) -> Result<Self, D::Error>
186                where
187                    D: serde::Deserializer<'de>,
188                {
189                    let felt = Felt::deserialize(de)?;
190                    $target::new(felt).context("Felt251 overflow").map_err(serde::de::Error::custom)
191                }
192            }
193        }
194    };
195
196    (@generate_use $head:ident, $($tail:ident),+ $(,)?) => {
197        crate::macros::felt_newtypes!(@generate_use $head);
198        crate::macros::felt_newtypes!(@generate_use $($tail),+);
199    };
200
201    (@generate_use $target:ident) => {
202        paste::paste! {
203            pub use [<$target:snake>];
204            pub use [<$target:snake _bytes>];
205        }
206    };
207
208    (@generate_felt_macro $head:ident, $($tail:ident),+ $(,)?) => {
209        crate::macros::felt_newtypes!(@generate_felt_macro $head);
210        crate::macros::felt_newtypes!(@generate_felt_macro $($tail),+);
211    };
212
213    (@generate_felt_macro $target:ident) => {
214        paste::paste! {
215            #[macro_export]
216            macro_rules! [<$target:snake>] {
217                ($hex:expr) => {
218                    $crate::$target($crate::felt!($hex))
219                };
220            }
221
222            #[macro_export]
223            macro_rules! [<$target:snake _bytes>] {
224                ($bytes:expr) => {
225                    $crate::$target($crate::felt_bytes!($bytes))
226                };
227            }
228        }
229    };
230
231    (@generate_felt251_macro $head:ident, $($tail:ident),+ $(,)?) => {
232        crate::macros::felt_newtypes!(@generate_felt251_macro $head);
233        crate::macros::felt_newtypes!(@generate_felt251_macro $($tail),+);
234    };
235
236    (@generate_felt251_macro $target:ident) => {
237        paste::paste! {
238            #[macro_export]
239            macro_rules! [<$target:snake>] {
240                ($hex:expr) => {
241                    $crate::$target::new_or_panic($crate::felt!($hex))
242                };
243            }
244
245            #[macro_export]
246            macro_rules! [<$target:snake _bytes>] {
247                ($bytes:expr) => {
248                    $crate::$target::new_or_panic($crate::felt_bytes!($bytes))
249                };
250            }
251        }
252    };
253}
254pub(super) use felt_newtypes;
255
256pub(super) mod fmt {
257
258    /// Adds a thin display implementation which uses the inner fields Display.
259    macro_rules! thin_display {
260        ($target:ty) => {
261            impl std::fmt::Display for $target {
262                fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
263                    std::fmt::Display::fmt(&self.0, f)
264                }
265            }
266        };
267    }
268
269    /// Adds a thin Debug implementation, which skips `X(StarkHash(debug))` as
270    /// `X(debug)`.
271    ///
272    /// The implementation uses Display of the wrapped value to produce smallest
273    /// possible string, but still wraps it in a default Debug derive style
274    /// `TypeName(hash)`.
275    macro_rules! thin_debug {
276        ($target:ty) => {
277            impl std::fmt::Debug for $target {
278                fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279                    write!(fmt, "{}({})", stringify!($target), self.0)
280                }
281            }
282        };
283    }
284
285    pub(crate) use {thin_debug, thin_display};
286}
287
288/// Creates a [Felt](pathfinder_crypto::Felt) from a hex string literal verified
289/// at compile time.
290#[macro_export]
291macro_rules! felt {
292    ($hex:expr) => {{
293        // This forces const evaluation of the macro call. Without this the invocation
294        // will only be evaluated at runtime.
295        use ::pathfinder_crypto;
296        const CONST_FELT: pathfinder_crypto::Felt =
297            match pathfinder_crypto::Felt::from_hex_str($hex) {
298                Ok(f) => f,
299                Err(pathfinder_crypto::HexParseError::InvalidNibble(_)) => {
300                    panic!("Invalid hex digit")
301                }
302                Err(pathfinder_crypto::HexParseError::InvalidLength { .. }) => {
303                    panic!("Too many hex digits")
304                }
305                Err(pathfinder_crypto::HexParseError::Overflow) => panic!("Felt overflow"),
306            };
307        CONST_FELT
308    }};
309}
310
311/// Creates a [`pathfinder_crypto::Felt`] from a byte slice, resulting in
312/// compile-time error when invalid.
313#[macro_export]
314macro_rules! felt_bytes {
315    ($bytes:expr) => {{
316        match pathfinder_crypto::Felt::from_be_slice($bytes) {
317            Ok(sh) => sh,
318            Err(pathfinder_crypto::OverflowError) => panic!("Invalid constant: OverflowError"),
319        }
320    }};
321}