abscissa_core/
runnable.rs

1//! `Runnable` trait.
2
3#[doc(hidden)]
4pub use abscissa_derive::Runnable;
5
6/// `Runnable` is a common trait for things which can be run without any
7/// arguments.
8///
9/// Its primary intended purpose is for use in conjunction with `Command`.
10pub trait Runnable {
11    /// Run this `Runnable`
12    fn run(&self);
13}
14
15/// `RunnableMut` is a `Runnable` that takes a mutable reference to `self`.
16pub trait RunnableMut {
17    /// Run this `RunnableMut`
18    fn run(&mut self);
19}
20
21impl Runnable for Box<dyn Fn()> {
22    fn run(&self) {
23        self();
24    }
25}
26
27impl RunnableMut for Box<dyn FnMut()> {
28    fn run(&mut self) {
29        self();
30    }
31}
32
33#[cfg(test)]
34mod tests {
35    use crate::Runnable;
36    use std::sync::Mutex;
37
38    #[allow(dead_code)]
39    #[derive(Runnable)]
40    enum TestEnum {
41        A(VariantA),
42        B(VariantB),
43    }
44
45    #[allow(dead_code)]
46    struct VariantA {}
47
48    impl Runnable for VariantA {
49        fn run(&self) {
50            panic!("don't call this!")
51        }
52    }
53
54    #[derive(Default)]
55    struct VariantB {
56        called: Mutex<bool>,
57    }
58
59    impl VariantB {
60        fn was_called(&self) -> bool {
61            let called = self.called.lock().unwrap();
62            *called
63        }
64    }
65
66    impl Runnable for VariantB {
67        fn run(&self) {
68            let mut called = self.called.lock().unwrap();
69            *called = true;
70        }
71    }
72
73    #[test]
74    fn custom_derive_test() {
75        let variant_b = VariantB::default();
76        assert!(!variant_b.was_called());
77
78        let ex = TestEnum::B(variant_b);
79        ex.run();
80
81        let variant_b = match ex {
82            TestEnum::A(_) => panic!("this shouldn't be!"),
83            TestEnum::B(b) => b,
84        };
85        assert!(variant_b.was_called());
86    }
87}