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
/// Generates a thread-local global counter.
///
/// # Example
///
/// ```rust
/// #[macro_use]
/// extern crate simple_counter;
/// 
/// generate_counter!(Counter, usize);
/// 
/// fn main() {
/// 
///   assert_eq!(Counter::next(), 0);
///   assert_eq!(Counter::next(), 1);
///   assert_eq!(Counter::next(), 2);
/// 
///   Counter::reset();
/// 
///   assert_eq!(Counter::next(), 0);
/// }
/// ```
#[macro_export]
macro_rules! generate_counter {
    ($name:ident, $type:ident) => {

        /// Generated by the `simple-counter` crate.
        #[allow(non_snake_case)]
        pub mod $name {
            use std::cell::Cell;

            thread_local!(
                static COUNTER: Cell<$type> = Cell::new(0);
            );

            pub fn next() -> $type {
                COUNTER.with(|cell| {
                    let n = cell.get();
                    cell.set(n + 1);
                    n
                })
            }

            #[allow(dead_code)]
            pub fn set(n: $type) {
                COUNTER.with(|cell| cell.set(n));
            }

            #[allow(dead_code)]
            pub fn reset() {
                COUNTER.with(|cell| cell.set(0));
            }
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_basic() {
        generate_counter!(Counter, i8);
        assert_eq!(0, Counter::next());
        assert_eq!(1, Counter::next());
        assert_eq!(2, Counter::next());
    }

    #[test]
    fn test_reset() {
        generate_counter!(Counter, i8);
        assert_eq!(0, Counter::next());
        assert_eq!(1, Counter::next());
        Counter::reset();
        assert_eq!(0, Counter::next());
    }

    #[test]
    fn test_set() {
        generate_counter!(Counter, u32);
        Counter::set(100);
        assert_eq!(100, Counter::next());
        assert_eq!(101, Counter::next());
        assert_eq!(102, Counter::next());
    }
}