Skip to main content

static_generics/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![cfg_attr(
4    all(feature = "nightly", target_family = "wasm", target_arch = "wasm32"),
5    feature(asm_experimental_arch)
6)]
7
8#[cfg(all(feature = "std"))]
9#[allow(dead_code)]
10pub(crate) mod fallback;
11pub mod namespace;
12pub mod once;
13
14pub use bytemuck::{Pod, Zeroable};
15pub use namespace::{Namespace, NamespaceExt};
16pub use once::OnceSlot;
17
18define_namespace!(pub DefaultNamespace);
19
20/// Generic static in the [`DefaultNamespace`].
21///
22/// ```rust
23/// use core::sync::atomic::{AtomicU32, Ordering};
24///
25/// let a = static_generics::get::<AtomicU32>();
26/// a.store(7, Ordering::Relaxed);
27/// assert_eq!(static_generics::get::<AtomicU32>().load(Ordering::Relaxed), 7);
28/// ```
29#[inline(always)]
30#[must_use]
31pub fn get<T>() -> &'static T
32where
33    T: 'static + Zeroable,
34{
35    <DefaultNamespace as Namespace>::generic_static::<T>()
36}
37
38/// Generic static in an explicit namespace.
39#[inline(always)]
40#[must_use]
41pub fn get_in<NS, T>() -> &'static T
42where
43    NS: Namespace,
44    T: 'static + Zeroable,
45{
46    <NS as Namespace>::generic_static::<T>()
47}
48
49/// Raw (`*mut T`) view of the generic static in the [`DefaultNamespace`].
50///
51/// Same slot as [`get`]; the `static mut` equivalent.
52///
53/// # Safety
54///
55/// See [`Namespace::generic_static_mut`].
56#[inline(always)]
57pub unsafe fn get_mut<T>() -> *mut T
58where
59    T: 'static + Zeroable,
60{
61    // SAFETY: forwarded from the caller upholding the `static mut` contract.
62    unsafe { <DefaultNamespace as Namespace>::generic_static_mut::<T>() }
63}
64
65/// Raw (`*mut T`) view of the generic static in an explicit namespace.
66///
67/// # Safety
68///
69/// See [`Namespace::generic_static_mut`].
70#[inline(always)]
71pub unsafe fn get_in_mut<NS, T>() -> *mut T
72where
73    NS: Namespace,
74    T: 'static + Zeroable,
75{
76    // SAFETY: forwarded from the caller upholding the `static mut` contract.
77    unsafe { <NS as Namespace>::generic_static_mut::<T>() }
78}
79
80/// Generic const-keyed static in the [`DefaultNamespace`].
81#[inline(always)]
82#[must_use]
83pub fn get_const<T, const N: usize>() -> &'static T
84where
85    T: 'static + Zeroable,
86{
87    <DefaultNamespace as Namespace>::generic_static_const::<T, N>()
88}
89
90/// Generic const-keyed static in an explicit namespace.
91#[inline(always)]
92#[must_use]
93pub fn get_in_const<NS, T, const N: usize>() -> &'static T
94where
95    NS: Namespace,
96    T: 'static + Zeroable,
97{
98    <NS as Namespace>::generic_static_const::<T, N>()
99}
100
101/// Raw (`*mut T`) const-keyed view in the [`DefaultNamespace`].
102///
103/// # Safety
104///
105/// See [`Namespace::generic_static_mut`].
106#[inline(always)]
107pub unsafe fn get_const_mut<T, const N: usize>() -> *mut T
108where
109    T: 'static + Zeroable,
110{
111    // SAFETY: forwarded from the caller upholding the `static mut` safety.
112    unsafe { <DefaultNamespace as Namespace>::generic_static_const_mut::<T, N>() }
113}
114
115/// Raw (`*mut T`) const-keyed view in an explicit namespace.
116///
117/// # Safety
118///
119/// See [`Namespace::generic_static_mut`].
120#[inline(always)]
121pub unsafe fn get_in_const_mut<NS, T, const N: usize>() -> *mut T
122where
123    NS: Namespace,
124    T: 'static + Zeroable,
125{
126    // SAFETY: forwarded from the caller upholding the `static mut` contract.
127    unsafe { <NS as Namespace>::generic_static_const_mut::<T, N>() }
128}
129
130/// Lazily-initialized generic static in the [`DefaultNamespace`].
131///
132/// Backed by [`OnceSlot`]; the first call with a given `T` runs `init`.
133/// See [`NamespaceExt::once`].
134///
135/// ## Precautions
136///
137/// This function is not marked unsafe, but it can cause some unforeseen effects:
138///
139/// If you fetch the `once::<T>(A)` with `A` being initializer in one place and then fetch `once::<T>(B)` with B being different initializer,
140/// it will initialize with whatever invocation was first.
141#[must_use]
142pub fn once<T>(init: impl FnOnce() -> T) -> &'static T
143where
144    T: 'static + Send + Sync,
145{
146    <DefaultNamespace as NamespaceExt>::once(init)
147}
148
149/// Lazily-initialized const-keyed generic static in the [`DefaultNamespace`].
150#[must_use]
151pub fn once_const<T, const N: usize>(init: impl FnOnce() -> T) -> &'static T
152where
153    T: 'static + Send + Sync,
154{
155    <DefaultNamespace as NamespaceExt>::once_const::<T, N>(init)
156}