Skip to main content

static_generics/
lib.rs

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