ixa/
macros.rs

1/// Defines a global property with the following parameters:
2/// * `$global_property`: Name for the identifier type of the global property
3/// * `$value`: The type of the property's value
4/// * `$validate`: A function (or closure) that checks the validity of the property (optional)
5#[macro_export]
6macro_rules! define_global_property {
7    ($global_property:ident, $value:ty, $validate: expr) => {
8        #[derive(Copy, Clone)]
9        pub struct $global_property;
10
11        impl $crate::global_properties::GlobalProperty for $global_property {
12            type Value = $value;
13
14            fn new() -> Self {
15                $global_property
16            }
17
18            fn validate(val: &$value) -> Result<(), $crate::error::IxaError> {
19                $validate(val)
20            }
21        }
22
23        $crate::paste::paste! {
24            $crate::ctor::declarative::ctor!{
25                #[ctor]
26                fn [<$global_property:snake _register>]() {
27                    let module = module_path!();
28                    let mut name = module.split("::").next().unwrap().to_string();
29                    name += ".";
30                    name += stringify!($global_property);
31                    $crate::global_properties::add_global_property::<$global_property>(&name);
32                }
33            }
34        }
35    };
36
37    ($global_property: ident, $value: ty) => {
38        define_global_property!($global_property, $value, |_| { Ok(()) });
39    };
40}
41pub use define_global_property;
42
43/// Define a new edge type for use with `network`.
44///
45/// Defines a new edge type of type `$edge_type`, with inner type `$value`.
46/// Use `()` for `$value` to have no inner type.
47#[allow(unused_macros)]
48#[macro_export]
49macro_rules! define_edge_type {
50    ($edge_type:ident, $value:ty) => {
51        #[derive(Debug, Copy, Clone)]
52        pub struct $edge_type;
53
54        impl $crate::network::EdgeType for $edge_type {
55            type Value = $value;
56        }
57    };
58}
59pub use define_edge_type;
60
61/// Use this macro to define a unique report type
62#[macro_export]
63macro_rules! define_report {
64    ($name:ident) => {
65        impl $crate::Report for $name {
66            fn type_id(&self) -> std::any::TypeId {
67                std::any::TypeId::of::<$name>()
68            }
69
70            fn serialize(&self, writer: &mut $crate::csv::Writer<std::fs::File>) {
71                writer.serialize(self).unwrap();
72            }
73        }
74    };
75}
76pub use define_report;
77
78/// Helper for `define_data_plugin`
79#[macro_export]
80macro_rules! __define_data_plugin {
81    ($data_plugin:ident, $data_container:ty, |$ctx:ident| $body:expr) => {
82        struct $data_plugin;
83
84        impl $crate::DataPlugin for $data_plugin {
85            type DataContainer = $data_container;
86
87            fn init<C: $crate::PluginContext>($ctx: &C) -> Self::DataContainer {
88                $body
89            }
90
91            fn index_within_context() -> usize {
92                // This static must be initialized with a compile-time constant expression.
93                // We use `usize::MAX` as a sentinel to mean "uninitialized". This
94                // static variable is shared among all instances of this data plugin type.
95                static INDEX: std::sync::atomic::AtomicUsize =
96                    std::sync::atomic::AtomicUsize::new(usize::MAX);
97
98                // Fast path: already initialized.
99                let index = INDEX.load(std::sync::atomic::Ordering::Relaxed);
100                if index != usize::MAX {
101                    return index;
102                }
103
104                // Slow path: initialize it.
105                $crate::initialize_data_plugin_index(&INDEX)
106            }
107        }
108
109        $crate::paste::paste! {
110            $crate::ctor::declarative::ctor!{
111                #[ctor]
112                fn [<_register_plugin_$data_plugin:snake>]() {
113                    $crate::add_data_plugin_to_registry::<$data_plugin>()
114                }
115            }
116        }
117    };
118}
119
120/// Defines a new type for storing data in Context.
121#[macro_export]
122macro_rules! define_data_plugin {
123    ($data_plugin:ident, $data_container:ty, |$ctx:ident| $body:expr) => {
124        $crate::__define_data_plugin!($data_plugin, $data_container, |$ctx| $body);
125    };
126
127    ($data_plugin:ident, $data_container:ty, $default: expr) => {
128        $crate::__define_data_plugin!($data_plugin, $data_container, |_context| $default);
129    };
130}
131pub use define_data_plugin;
132
133#[macro_export]
134macro_rules! assert_almost_eq {
135    ($a:expr, $b:expr, $prec:expr $(,)?) => {
136        if !$crate::numeric::almost_eq($a, $b, $prec) {
137            panic!(
138                "assertion failed: `abs(left - right) < {:e}`, (left: `{}`, right: `{}`)",
139                $prec, $a, $b
140            );
141        }
142    };
143}
144pub use assert_almost_eq;