use cfg_if::cfg_if;
use core::{mem, ptr};
const fn cmp_max(a: usize, b: usize) -> usize {
if a > b { a } else { b }
}
#[allow(dead_code)]
const fn align_log2(align: usize) -> usize {
let mut log = 0;
let mut v = align;
while v > 1 {
v >>= 1;
log += 1;
}
log
}
#[repr(transparent)]
struct ConstKey<T, const N: usize>(T);
unsafe impl<T, const N: usize> bytemuck::Zeroable for ConstKey<T, N> where T: bytemuck::Zeroable {}
#[inline(never)]
fn unique_symbol<NS: Namespace, T: 'static>() -> core::any::TypeId {
core::any::TypeId::of::<(NS, T)>()
}
#[cfg_attr(all(target_family = "wasm", feature = "nightly"), inline(never))]
#[cfg_attr(not(all(target_family = "wasm", feature = "nightly")), inline(always))]
#[allow(named_asm_labels)]
fn slot_addr<NS, T>() -> *mut T
where
NS: Namespace,
T: 'static + bytemuck::Zeroable,
{
#[allow(unused_assignments)]
let mut addr: *mut () = ptr::null_mut();
cfg_if! {
if #[cfg(any(static_generics_fallback, miri))] {
} else if #[cfg(all(
target_family = "wasm",
target_arch = "wasm32",
feature = "nightly"
))] {
} else if #[cfg(target_vendor = "apple")] {
unsafe {
core::arch::asm!(
".ifnotdef gen_static_{id}",
".pushsection __DATA,__data",
".globl gen_static_{id}",
".weak_definition gen_static_{id}",
".p2align {p2align}, 0x0",
"gen_static_{id}:",
".space {size}",
".popsection",
".endif",
size = const { cmp_max(mem::size_of::<T>(), 1) },
p2align = const { align_log2(mem::align_of::<T>()) },
id = sym unique_symbol::<NS, T>,
options(nostack, nomem)
);
}
} else if #[cfg(any(
target_os = "windows",
target_os = "uefi",
target_os = "cygwin"
))] {
unsafe {
core::arch::asm!(
".ifnotdef gen_static_{id}",
".pushsection .bss,\"bw\",discard,gen_static_{id}",
".globl gen_static_{id}",
".p2align {p2align}, 0x0",
"gen_static_{id}:",
".zero {size}",
".popsection",
".endif",
size = const { cmp_max(mem::size_of::<T>(), 1) },
p2align = const { align_log2(mem::align_of::<T>()) },
id = sym unique_symbol::<NS, T>,
options(nostack, nomem)
);
}
} else if #[cfg(all(
any(
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm64ec",
target_arch = "x86",
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
target_arch = "loongarch64",
target_arch = "loongarch32",
target_arch = "powerpc64",
target_arch = "powerpc",
target_arch = "s390x"
),
not(target_os = "aix")
))] {
cfg_if! {
if #[cfg(target_arch = "arm")] {
unsafe {
core::arch::asm!(
".ifnotdef gen_static_{id}",
".pushsection .bss.gen_static_{id},\"awG\",%nobits,gen_static_{id},comdat",
".weak gen_static_{id}",
".hidden gen_static_{id}",
".type gen_static_{id},%object",
".p2align {p2align}, 0x0",
"gen_static_{id}:",
".zero {size}",
".size gen_static_{id}, {size}",
".popsection",
".endif",
size = const { cmp_max(mem::size_of::<T>(), 1) },
p2align = const { align_log2(mem::align_of::<T>()) },
id = sym unique_symbol::<NS, T>,
options(nostack, nomem)
);
}
} else {
unsafe {
core::arch::asm!(
".ifnotdef gen_static_{id}",
".pushsection .bss.gen_static_{id},\"awG\",@nobits,gen_static_{id},comdat",
".weak gen_static_{id}",
".hidden gen_static_{id}",
".type gen_static_{id},@object",
".p2align {p2align}, 0x0",
"gen_static_{id}:",
".zero {size}",
".size gen_static_{id}, {size}",
".popsection",
".endif",
size = const { cmp_max(mem::size_of::<T>(), 1) },
p2align = const { align_log2(mem::align_of::<T>()) },
id = sym unique_symbol::<NS, T>,
options(nostack, nomem)
);
}
}
}
} else {
}
}
cfg_if! {
if #[cfg(any(static_generics_fallback, miri))] {
#[cfg(feature = "std")]
{
addr = crate::fallback::generic_static_fallback_mut::<NS, T>() as *mut T
as *mut ();
}
#[cfg(not(feature = "std"))]
core::compile_error!(
"static-generics: Cranelift/Miri needs the slow fallback (enable `std` feature)"
);
} else if #[cfg(all(
target_family = "wasm",
target_arch = "wasm32",
feature = "nightly"
))] {
unsafe {
core::arch::asm!(
".ifnotdef gen_static_{id}",
".hidden gen_static_{id}",
".type gen_static_{id},@object",
".section .bss.gen_static_{id},\"G\",@,gen_static_{id},comdat",
".weak gen_static_{id}",
".p2align {align}, 0x0",
"gen_static_{id}:",
".skip {size}, 0",
".size gen_static_{id}, {size}",
".section .text.{me},\"\",@",
".endif",
"i32.const gen_static_{id}",
"local.set {x}",
size = const { cmp_max(mem::size_of::<T>(), 1) },
align = const { align_log2(mem::align_of::<T>()) },
id = sym unique_symbol::<NS, T>,
me = sym slot_addr::<NS, T>,
x = out(local) addr,
options(nostack, nomem)
);
}
} else if #[cfg(target_arch = "x86_64")] {
unsafe {
core::arch::asm!(
"lea {x}, [rip + gen_static_{id}]",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))] {
unsafe {
core::arch::asm!(
"adrp {x}, gen_static_{id}@PAGE",
"add {x}, {x}, gen_static_{id}@PAGEOFF",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(
any(target_arch = "aarch64", target_arch = "arm64ec"),
not(target_vendor = "apple")
))] {
unsafe {
core::arch::asm!(
"adrp {x}, gen_static_{id}",
"add {x}, {x}, :lo12:gen_static_{id}",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(
target_arch = "x86",
not(any(
target_vendor = "apple",
target_os = "windows",
target_os = "uefi",
target_os = "cygwin",
target_os = "none"
))
))] {
unsafe {
core::arch::asm!(
"call 2f",
"2: popl {x}",
"addl $_GLOBAL_OFFSET_TABLE_+[.-2b], {x}",
"leal gen_static_{id}@GOTOFF({x}), {x}",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(att_syntax, nomem)
);
}
} else if #[cfg(all(target_arch = "x86", target_vendor = "apple"))] {
unsafe {
core::arch::asm!(
"call 2f",
"2: popl {x}",
"leal gen_static_{id}-2b({x}), {x}",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(att_syntax, nomem)
);
}
} else if #[cfg(all(
target_arch = "x86",
any(
target_os = "windows",
target_os = "uefi",
target_os = "cygwin",
target_os = "none"
)
))] {
unsafe {
core::arch::asm!(
"lea {x}, [gen_static_{id}]",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(
target_arch = "arm",
any(target_os = "windows", target_os = "uefi", target_os = "cygwin")
))] {
unsafe {
core::arch::asm!(
"movw {x}, :lower16:gen_static_{id}",
"movt {x}, :upper16:gen_static_{id}",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(
target_arch = "arm",
not(any(target_os = "windows", target_os = "uefi", target_os = "cygwin")),
target_feature = "thumb-mode"
))] {
unsafe {
core::arch::asm!(
"ldr {x}, 2f",
"1: add {x}, pc, {x}",
"b 3f",
"2: .word gen_static_{id}-1b-4",
"3:",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(
target_arch = "arm",
not(any(target_os = "windows", target_os = "uefi", target_os = "cygwin")),
not(target_feature = "thumb-mode")
))] {
unsafe {
core::arch::asm!(
"ldr {x}, 2f",
"1: add {x}, pc, {x}",
"b 3f",
"2: .word gen_static_{id}-1b-8",
"3:",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
unsafe {
core::arch::asm!(
"1: auipc {x}, %pcrel_hi(gen_static_{id})",
"addi {x}, {x}, %pcrel_lo(1b)",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(target_arch = "loongarch64")] {
unsafe {
core::arch::asm!(
"pcalau12i {x}, %pc_hi20(gen_static_{id})",
"addi.d {x}, {x}, %pc_lo12(gen_static_{id})",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(target_arch = "loongarch32")] {
unsafe {
core::arch::asm!(
"pcalau12i {x}, %pc_hi20(gen_static_{id})",
"addi.w {x}, {x}, %pc_lo12(gen_static_{id})",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(target_arch = "powerpc64", not(target_os = "aix")))] {
unsafe {
core::arch::asm!(
"addis {x}, 2, gen_static_{id}@toc@ha",
"addi {x}, {x}, gen_static_{id}@toc@l",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else if #[cfg(all(target_arch = "powerpc", not(target_os = "aix")))] {
unsafe {
core::arch::asm!(
"bcl 20, 31, 1f",
"1: mflr {x}",
"addis {x}, {x}, (gen_static_{id}-1b)@ha",
"addi {x}, {x}, (gen_static_{id}-1b)@l",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
out("lr") _,
options(nostack, nomem)
);
}
} else if #[cfg(target_arch = "s390x")] {
unsafe {
core::arch::asm!(
"larl {x}, gen_static_{id}",
id = sym unique_symbol::<NS, T>,
x = out(reg) addr,
options(nostack, nomem)
);
}
} else {
#[cfg(feature = "std")]
{
addr = crate::fallback::generic_static_fallback_mut::<NS, T>() as *mut T
as *mut ();
}
#[cfg(not(feature = "std"))]
core::compile_error!(
"static-generics is not supported on this target without the slow fallback (enable `std` feature)"
);
}
}
debug_assert!(!addr.is_null(), "unsupported platform");
addr.cast::<T>()
}
pub unsafe trait Namespace: 'static + Send + Sync + Copy + Clone {
#[inline(always)]
#[must_use]
fn generic_static<T>() -> &'static T
where
T: 'static + bytemuck::Zeroable,
{
unsafe { &*slot_addr::<Self, T>() }
}
#[inline(always)]
#[must_use]
fn generic_static_const<T, const N: usize>() -> &'static T
where
T: 'static + bytemuck::Zeroable,
{
&Self::generic_static::<ConstKey<T, N>>().0
}
#[inline(always)]
unsafe fn generic_static_mut<T>() -> *mut T
where
T: 'static + bytemuck::Zeroable,
{
slot_addr::<Self, T>()
}
#[inline(always)]
unsafe fn generic_static_const_mut<T, const N: usize>() -> *mut T
where
T: 'static + bytemuck::Zeroable,
{
unsafe { Self::generic_static_mut::<ConstKey<T, N>>().cast::<T>() }
}
}
pub trait NamespaceExt: Namespace {
#[inline(always)]
#[must_use]
fn get<T>() -> &'static T
where
T: 'static + bytemuck::Zeroable,
{
Self::generic_static::<T>()
}
#[inline(always)]
unsafe fn get_mut<T>() -> *mut T
where
T: 'static + bytemuck::Zeroable,
{
unsafe { Self::generic_static_mut::<T>() }
}
#[must_use]
fn once<T>(init: impl FnOnce() -> T) -> &'static T
where
T: 'static + Send + Sync,
{
Self::generic_static::<crate::once::OnceSlot<T>>().get_or_init(init)
}
#[inline(always)]
#[must_use]
fn get_const<T, const N: usize>() -> &'static T
where
T: 'static + bytemuck::Zeroable,
{
Self::generic_static_const::<T, N>()
}
#[inline(always)]
unsafe fn get_const_mut<T, const N: usize>() -> *mut T
where
T: 'static + bytemuck::Zeroable,
{
unsafe { Self::generic_static_const_mut::<T, N>() }
}
#[must_use]
fn once_const<T, const N: usize>(init: impl FnOnce() -> T) -> &'static T
where
T: 'static + Send + Sync,
{
Self::generic_static_const::<crate::once::OnceSlot<T>, N>().get_or_init(init)
}
}
impl<NS: Namespace> NamespaceExt for NS {}
#[macro_export]
macro_rules! define_namespace {
($vis:vis $name:ident) => {
#[derive(Debug, Copy, Clone)]
$vis struct $name;
unsafe impl $crate::namespace::Namespace for $name {}
};
}
#[macro_export]
macro_rules! define_static {
($vis:vis fn $name:ident () -> *mut $ty:ty ; in $ns:ty) => {
$vis unsafe fn $name() -> *mut $ty
where
$ty: $crate::Zeroable,
{
unsafe { <$ns as $crate::namespace::Namespace>::generic_static_mut::<$ty>() }
}
};
($vis:vis fn $name:ident <$($gen:ident),+ $(,)?> () -> *mut $ty:ty ; in $ns:ty) => {
$vis unsafe fn $name<$($gen: 'static),+>() -> *mut $ty
where
$ty: $crate::Zeroable,
{
unsafe { <$ns as $crate::namespace::Namespace>::generic_static_mut::<$ty>() }
}
};
($vis:vis fn $name:ident <const $N:ident : usize $(,)?> () -> *mut $ty:ty ; in $ns:ty) => {
$vis unsafe fn $name<const $N: usize>() -> *mut $ty
where
$ty: $crate::Zeroable,
{
unsafe { <$ns as $crate::namespace::Namespace>::generic_static_const_mut::<$ty, $N>() }
}
};
($vis:vis fn $name:ident <$gen:ident, const $N:ident : usize $(,)?> () -> *mut $ty:ty ; in $ns:ty) => {
$vis unsafe fn $name<$gen: 'static, const $N: usize>() -> *mut $ty
where
$ty: $crate::Zeroable,
{
unsafe { <$ns as $crate::namespace::Namespace>::generic_static_const_mut::<$ty, $N>() }
}
};
($vis:vis fn $name:ident () -> $ty:ty ; in $ns:ty) => {
$vis fn $name() -> &'static $ty
where
$ty: $crate::Zeroable,
{
<$ns as $crate::namespace::Namespace>::generic_static::<$ty>()
}
};
($vis:vis fn $name:ident <$($gen:ident),+ $(,)?> () -> $ty:ty ; in $ns:ty) => {
$vis fn $name<$($gen: 'static),+>() -> &'static $ty
where
$ty: $crate::Zeroable,
{
<$ns as $crate::namespace::Namespace>::generic_static::<$ty>()
}
};
($vis:vis fn $name:ident <const $N:ident : usize $(,)?> () -> $ty:ty ; in $ns:ty) => {
$vis fn $name<const $N: usize>() -> &'static $ty
where
$ty: $crate::Zeroable,
{
<$ns as $crate::namespace::Namespace>::generic_static_const::<$ty, $N>()
}
};
($vis:vis fn $name:ident <$gen:ident, const $N:ident : usize $(,)?> () -> $ty:ty ; in $ns:ty) => {
$vis fn $name<$gen: 'static, const $N: usize>() -> &'static $ty
where
$ty: $crate::Zeroable,
{
<$ns as $crate::namespace::Namespace>::generic_static_const::<$ty, $N>()
}
};
}