1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
pub use fun_time_derive::*;

#[cfg(test)]
mod tests {
    use fun_time_derive::fun_time;
    use std::fmt::Debug;
    use std::time::Duration;

    #[fun_time(give_back)]
    fn dummy_test_function_that_sleeps<'a, T>(borrowed_thing: &'a T) -> &'a T
    where
        T: Debug + Sized,
    {
        std::thread::sleep(Duration::from_millis(42));

        println!("the borrowed_thing is = {borrowed_thing:?}");

        borrowed_thing
    }

    #[test]
    fn works_with_struct_member_that_modifies() {
        struct Thing {
            value: i32,
        }

        impl Thing {
            pub fn new(value: i32) -> Self {
                Self { value }
            }

            #[fun_time(message = "modify while mutating self", reporting = "println")]
            pub fn modify_timed(&mut self, new_value: i32) -> i32 {
                let old_value = self.value;
                self.value = new_value;
                old_value
            }
        }

        let mut thing = Thing::new(1);
        let _old_value = thing.modify_timed(1337);
    }

    #[test]
    fn works_with_traits() {
        trait MyTrait {
            fn speak(&self) -> &'static str;
        }

        struct A {}
        impl MyTrait for A {
            fn speak(&self) -> &'static str {
                "I am: A"
            }
        }

        struct B {}
        impl MyTrait for B {
            fn speak(&self) -> &'static str {
                "I am: B"
            }
        }

        #[derive(Debug)]
        enum MyEnum {
            A,
            B,
        }

        impl MyEnum {
            #[fun_time(message = "Getting trait item for: {self:?}")]
            fn get_trait_item(&self) -> Box<dyn MyTrait> {
                match self {
                    Self::A => Box::new(A {}),
                    Self::B => Box::new(B {}),
                }
            }
        }

        let enum_a = MyEnum::A;
        let _ = enum_a.get_trait_item().speak();

        let enum_b = MyEnum::B;
        let _ = enum_b.get_trait_item().speak();
    }

    #[cfg(feature = "log")]
    mod feature_log_tests {
        use super::*;
        use simple_logger::SimpleLogger;
        use std::fmt::Formatter;

        #[fun_time(when = "debug", message = "having fun with log", reporting = "log")]
        fn have_fun(_first: String, _second: String) {}

        struct Parameter {
            name: String,
            value: i32,
        }

        impl Debug for Parameter {
            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
                if f.alternate() {
                    write!(f, "name = {} and value * 2 = {}", self.name, self.value * 2)
                } else {
                    write!(f, "name = {} and value = {}", self.name, self.value)
                }
            }
        }

        #[fun_time(
            message = "having fun with parameters: {first:#?} and {second}",
            level = "debug",
            reporting = "log"
        )]
        fn have_fun_with_parameters(first: Parameter, second: i32) {
            // Let's take ownership of the first parameter
            let _first = first;
        }

        #[test]
        fn it_works() {
            let (borrowed_thing, _elapsed_time) = dummy_test_function_that_sleeps(&"Hello, there!");

            assert_eq!(&"Hello, there!", borrowed_thing);

            SimpleLogger::new().init().unwrap_or(());

            have_fun("Alice".to_string(), "Bob".to_string());
        }

        #[test]
        fn it_works_with_parameters() {
            SimpleLogger::new().init().unwrap_or(());

            have_fun_with_parameters(
                Parameter {
                    name: "Alice".to_string(),
                    value: 1234,
                },
                1234,
            );
        }
    }
}