Thanks to visit codestin.com
Credit goes to lib.rs

#singleton #static #generic #global

generic_singleton

A library crate allowing for generic singleton patterns

8 releases

0.5.1 May 20, 2025
0.5.0 Jun 8, 2023
0.4.1 Jan 12, 2023
0.3.2 Nov 23, 2022
0.1.3 Sep 8, 2022

#405 in Data structures

Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App Codestin Search App

2,659 downloads per month
Used in 5 crates (2 directly)

MIT/Apache

22KB
184 lines

generic_singleton

crates.io Documentation

Rust does NOT monomorphize it's static generic items. This means you cannot use a generic static item in a generic function. 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. This crate allows for this pattern with minimal runtime overhead.

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

Example

use std::{ops::AddAssign, sync::RwLock};

use num_traits::{One, Zero};

fn generic_call_counter<T: Zero + One + Copy + AddAssign + Send + Sync + 'static>() -> T {
    let mut count = generic_singleton::get_or_init!(|| RwLock::new(T::zero())).write().unwrap();
    *count += T::one();
    *count
}

fn main() {
    // Works with usize
    assert_eq!(generic_call_counter::<usize>(), 1);
    assert_eq!(generic_call_counter::<usize>(), 2);
    assert_eq!(generic_call_counter::<usize>(), 3);

    // Works with i32
    assert_eq!(generic_call_counter::<i32>(), 1);
    assert_eq!(generic_call_counter::<i32>(), 2);
    assert_eq!(generic_call_counter::<i32>(), 3);

    // Works with f32
    assert_eq!(generic_call_counter::<f32>(), 1.0);
    assert_eq!(generic_call_counter::<f32>(), 2.0);
    assert_eq!(generic_call_counter::<f32>(), 3.0);
}

Thread Local variant

The example shown above has a drawback of requiring an RwLock to ensure synchronisation around the inner AnyMap. In single-threaded situations we can remove this lock and provide mutable references directly using the get_or_init_thread_local! macro. This comes at the cost of ergonomics, requiring you to express your logic in a closure rather than simply returning a reference.

Dependencies

~0.4–6MB
~11K SLoC