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
#![deny(missing_docs)]
#![deny(clippy::undocumented_unsafe_blocks)]
#![doc = include_str!("../README.md")]
pub extern crate anymap;

#[doc(hidden)]
pub mod static_anymap;

/// Get a static reference to a generic singleton or initialize it if it doesn't exist.
///
/// ### Example
/// ```rust
/// use std::cell::RefCell;
/// use std::collections::HashMap;
/// use std::ops::{Deref, DerefMut, Mul};
///
/// // The expensive function we're trying to cache using a singleton map, however,
/// // we want the user of the function to determine the type of the elements being
/// // multiplied.
/// fn multiply<T: Mul<Output = T>>(a: T, b: T) -> T {
///     a * b
/// }
///
/// fn multiply_with_cache<T: Mul<Output = T>>(a: T, b: T) -> T
/// where
///     T: std::cmp::Eq,
///     T: Copy,
///     T: 'static,
///     (T, T): std::hash::Hash,
/// {
///     // This is a generic singleton map!!!
///     let map = generic_singleton::get_or_init!(|| RefCell::new(HashMap::new()));
///     let key = (a, b);
///     if map.borrow().contains_key(&key) {
///         *map.borrow().get(&key).unwrap()
///     } else {
///         let result = multiply(a, b);
///         map.borrow_mut().insert(key, result);
///         result
///     }
/// }
///
/// fn main() {
///     // This call will create the AnyMap and the HashMap<i32> and do the multiplication
///     multiply_with_cache::<u32>(10, 10);
///     // This call will only retrieve the value of the multiplication from HashMap<i32>
///     multiply_with_cache::<u32>(10, 10);
///
///     // This call will create a second HashMap< and do the multiplication
///     multiply_with_cache::<i32>(-1, -10);
///     // This call will only retrieve the value of the multiplication from HashMap
///     multiply_with_cache::<i32>(-1, -10);
/// }
/// ```
#[macro_export]
macro_rules! get_or_init {
    ($init:expr) => {{
        use $crate::static_anymap::StaticAnyMap;

        lazy_static::lazy_static! {
            static ref STATIC_ANY_MAP: StaticAnyMap = StaticAnyMap::default();
        }
        STATIC_ANY_MAP.get_or_init($init)
    }};
}

#[cfg(test)]
mod tests {
    use super::*;

    fn testing_function() -> &'static i32 {
        get_or_init!(|| 0)
    }

    #[test]
    fn works() {
        let a = testing_function();
        let b = testing_function();
        assert!(std::ptr::eq(a, b));
    }

    #[test]
    fn recursive_call_to_get_or_init_does_not_panic() {
        get_or_init!(|| get_or_init!(|| 0));
    }

    #[test]
    fn initializing_in_different_thread_works() {
        let v = std::thread::spawn(|| get_or_init!(|| String::from("foo")))
            .join()
            .unwrap();

        println!("{v}"); // Check for use-after-free, to be sure bugs are caught, run with miri
    }
}