Expand description

generic_singleton

Rust does NOT monomorphize it’s static generic items. This is dissappointing when you have a generic function that contains a static variable depending on that generic. You’ll get the following error:

error[E0401]: can't use generic parameters from outer function

That’s pretty frustrating when you want to write a singleton pattern that rely’s on a generic parameter. That’s where this crate saves the day!

generic_singleton uses anymap behind the scenes to store a map of each generic type. The first time you call get_or_init we initialize the singleton in thread local storage. Subsequent calls to get_or_init will retrieve the singleton from the map.

Example

use std::sync::Mutex;

fn generic_function<T: Copy + std::ops::Add<Output = T> + 'static>(initializer: fn() -> Mutex<T>) -> T {
    {
        let mut a = generic_singleton::get_or_init(initializer).lock().unwrap();
        let b = *a;
        *a = *a + b;
        *a
    }
}

fn main() {
    assert_eq!(generic_function(||Mutex::new(2)), 4);
    assert_eq!(generic_function(||Mutex::new(2)), 8);
    assert_eq!(generic_function(||Mutex::new(2)), 16);

    assert_eq!(generic_function(||Mutex::new(2.0)), 4.0);
    assert_eq!(generic_function(||Mutex::new(2.0)), 8.0);
    assert_eq!(generic_function(||Mutex::new(2.0)), 16.0);
}

Current limitations:

  • Each thread has a different map. I may add get_or_init_local and get_or_init_global if I can figure out how to implement concurrent access and the required trait bound to make it safe.
  • There is only one map(per thread). Mutliple uses of get_or_init on the same type will return the SAME singleton. Perhaps even accross crate boundaries. I might be able to limit it by providing a macro that salts the key in AnyMap with a context about which function it’s being called from.

Functions

Get a static reference to a generic singleton or initialize it if it doesn’t exist.