safecoin_measure/
macros.rs

1/// Measure this expression
2///
3/// Use `measure!()` when you have an expression that you want to measure.  `measure!()` will start
4/// a new [`Measure`], evaluate your expression, stop the [`Measure`], and then return the
5/// [`Measure`] object along with your expression's return value.
6///
7/// [`Measure`]: crate::measure::Measure
8///
9/// # Examples
10///
11/// ```
12/// // Measure functions
13/// # use safecoin_measure::measure;
14/// # fn foo() {}
15/// # fn bar(x: i32) {}
16/// # fn add(x: i32, y: i32) -> i32 {x + y}
17/// let (result, measure) = measure!(foo(), "foo takes no parameters");
18/// let (result, measure) = measure!(bar(42), "bar takes one parameter");
19/// let (result, measure) = measure!(add(1, 2), "add takes two parameters and returns a value");
20/// # assert_eq!(result, 1 + 2);
21/// ```
22///
23/// ```
24/// // Measure methods
25/// # use safecoin_measure::measure;
26/// # struct Foo {
27/// #     f: i32,
28/// # }
29/// # impl Foo {
30/// #     fn frobnicate(&self, bar: i32) -> i32 {
31/// #         self.f * bar
32/// #     }
33/// # }
34/// let foo = Foo { f: 42 };
35/// let (result, measure) = measure!(foo.frobnicate(2), "measure methods");
36/// # assert_eq!(result, 42 * 2);
37/// ```
38///
39/// ```
40/// // Measure expression blocks
41/// # use safecoin_measure::measure;
42/// # fn complex_calculation() -> i32 { 42 }
43/// # fn complex_transform(x: i32) -> i32 { x + 3 }
44/// # fn record_result(y: i32) {}
45/// let (result, measure) = measure!(
46///     {
47///         let x = complex_calculation();
48///         # assert_eq!(x, 42);
49///         let y = complex_transform(x);
50///         # assert_eq!(y, 42 + 3);
51///         record_result(y);
52///         y
53///     },
54///     "measure a block of many operations",
55/// );
56/// # assert_eq!(result, 42 + 3);
57/// ```
58///
59/// ```
60/// // The `name` parameter is optional
61/// # use safecoin_measure::measure;
62/// # fn meow() {};
63/// let (result, measure) = measure!(meow());
64/// ```
65#[macro_export]
66macro_rules! measure {
67    ($val:expr, $name:tt $(,)?) => {{
68        let mut measure = $crate::measure::Measure::start($name);
69        let result = $val;
70        measure.stop();
71        (result, measure)
72    }};
73    ($val:expr) => {
74        measure!($val, "")
75    };
76}
77
78#[cfg(test)]
79mod tests {
80    use std::{thread::sleep, time::Duration};
81
82    fn my_multiply(x: i32, y: i32) -> i32 {
83        x * y
84    }
85
86    fn square(x: i32) -> i32 {
87        my_multiply(x, x)
88    }
89
90    struct SomeStruct {
91        x: i32,
92    }
93    impl SomeStruct {
94        fn add_to(&self, x: i32) -> i32 {
95            x + self.x
96        }
97    }
98
99    #[test]
100    fn test_measure_macro() {
101        // Ensure that the measurement side actually works
102        {
103            let (_result, measure) = measure!(sleep(Duration::from_secs(1)), "test");
104            assert!(measure.as_s() >= 0.99f32 && measure.as_s() <= 1.01f32);
105            assert!(measure.as_ms() >= 990 && measure.as_ms() <= 1_010);
106            assert!(measure.as_us() >= 999_000 && measure.as_us() <= 1_010_000);
107        }
108
109        // Ensure that the macro can be called with functions
110        {
111            let (result, _measure) = measure!(my_multiply(3, 4), "test");
112            assert_eq!(result, 3 * 4);
113
114            let (result, _measure) = measure!(square(5), "test");
115            assert_eq!(result, 5 * 5)
116        }
117
118        // Ensure that the macro can be called with methods
119        {
120            let some_struct = SomeStruct { x: 42 };
121            let (result, _measure) = measure!(some_struct.add_to(4), "test");
122            assert_eq!(result, 42 + 4);
123        }
124
125        // Ensure that the macro can be called with blocks
126        {
127            let (result, _measure) = measure!({ 1 + 2 }, "test");
128            assert_eq!(result, 3);
129        }
130
131        // Ensure that the macro can be called with a trailing comma
132        {
133            let (result, _measure) = measure!(square(5), "test",);
134            assert_eq!(result, 5 * 5)
135        }
136
137        // Ensure that the macro can be called without a name
138        {
139            let (result, _measure) = measure!(square(5));
140            assert_eq!(result, 5 * 5)
141        }
142    }
143}