hugr_core/
macros.rs

1//! Helper macros.
2
3/// Helper macro for declaring downcast traits that can be cloned when inside a `Box<dyn $trait>`.
4/// Implements `Clone` for `Box<dyn $trait>`.
5macro_rules! impl_box_clone {
6    ($trait:ident, $clone_trait:ident) => {
7        /// Auto-implemented trait for cloning `Box<dyn $trait>`.
8        pub trait $clone_trait {
9            /// Clone the trait object into a Sized box.
10            fn clone_box(&self) -> Box<dyn $trait>;
11        }
12
13        impl<T> $clone_trait for T
14        where
15            T: $trait + Clone,
16        {
17            fn clone_box(&self) -> Box<dyn $trait> {
18                Box::new(self.clone())
19            }
20        }
21
22        impl Clone for Box<dyn $trait> {
23            fn clone(&self) -> Box<dyn $trait> {
24                self.clone_box()
25            }
26        }
27    };
28}
29pub(crate) use impl_box_clone;
30
31/// Creates a [`TypeRow`] backed by statically defined data, avoiding
32/// allocations.
33///
34/// The parameters must be constants of type [`Type`].
35///
36/// For type rows that cannot be statically defined, use a vector or slice with
37/// [`TypeRow::from`] instead.
38///
39/// [`Type`]: crate::types::Type
40/// [`TypeRow`]: crate::types::TypeRow
41/// [`TypeRow::from`]: crate::types::TypeRow::from
42///
43/// Example:
44/// ```
45/// # use hugr::type_row;
46/// # use hugr::types::{Signature, Type, TypeRow};
47/// const U: Type = Type::UNIT;
48/// let static_row: TypeRow = type_row![U, U];
49/// let dynamic_row: TypeRow = vec![U, U, U].into();
50/// let sig = Signature::new(static_row, dynamic_row);
51///
52/// let repeated_row: TypeRow = type_row![U; 3];
53/// assert_eq!(repeated_row, *sig.output());
54/// ```
55#[allow(unused_macros)]
56#[macro_export]
57macro_rules! type_row {
58    () => {
59        {
60            $crate::types::TypeRow::new()
61        }
62    };
63    ($($t:expr),+ $(,)?) => {
64        {
65            use $crate::types;
66            static ROW: &[types::Type] = &[$($t),*];
67            let row: types::TypeRow = ROW.into();
68            row
69        }
70    };
71    ($t:expr; $n:expr) => {
72        {
73            use $crate::types;
74            static ROW: &[types::Type] = &[$t; $n];
75            let row: types::TypeRow = ROW.into();
76            row
77        }
78    };
79}
80
81#[allow(unused_imports)]
82pub use type_row;
83
84/// Declare 'const' variables holding new `ExtensionIds`, validating
85/// that they are well-formed as separate tests - hence, usable at the top level
86/// of a test module only. Example:
87/// ```rust
88/// # mod test {
89/// # use hugr::const_extension_ids;
90/// const_extension_ids! {
91///   pub const EXT_A: ExtensionId = "A";
92///   /// A doc comment
93///   #[cfg(foobar)] pub (super) const EXT_A_B: ExtensionId = "A.B";
94///   const EXT_BAD: ExtensionId = "..55"; // this will generate a failing #[test] fn ....
95/// }
96/// # }
97/// ```
98#[macro_export]
99macro_rules! const_extension_ids {
100    ($($(#[$attr:meta])* $v:vis const $field_name:ident : ExtensionId = $ext_name:expr;)+) => {
101        $($(#[$attr])* $v const $field_name: $crate::extension::ExtensionId =
102            $crate::extension::ExtensionId::new_unchecked($ext_name);
103
104        paste::paste! {
105            #[test]
106            fn [<check_ $field_name:lower _wellformed>]() {
107                $crate::extension::ExtensionId::new($ext_name).unwrap();
108            }
109        })*
110    };
111}
112
113pub use const_extension_ids;
114
115#[cfg(test)]
116/// Get the full path to a test file given its path relative to the
117/// `resources/test` directory in this crate.
118#[macro_export]
119macro_rules! test_file {
120    ($fname:expr) => {
121        concat!(env!("CARGO_MANIFEST_DIR"), "/resources/test/", $fname)
122    };
123}