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}