static-generics 0.1.3

Zero-cost generic statics for Rust.
Documentation
# static-generics
[![docs.rs](https://img.shields.io/docsrs/static-generics)](https://docs.rs/static-generics)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](LICENSE-MIT)


Zero-cost generic statics for Rust.

Based on the ideas of [cynecx/generic-statics](https://github.com/cynecx/generic-statics),
and implemented to be zero-cost*: one–two instructions to access a generic
(`lea`, `adrp`+`add`, `auipc`+`addi`, `larl`, …) instead of a `call` to the
accessor function.

*Zero cost applies only to supported platforms, unsupported platforms go through fallback of HashMap + Mutex and require `std` feature to be enabled.


```rust
use static_generics::{define_namespace, namespace::NamespaceExt};
use core::sync::atomic::{AtomicU64, Ordering};

define_namespace!(Counters);

let hits = Counters::get::<AtomicU64>();
hits.fetch_add(1, Ordering::Relaxed);
```

## Why

Rust has no generic statics unlike C++, and default solution to that is using `typemap`/`HashMap<TypeId, ...>` which
require locking, allocation, hashing on each access which is expensive and slow. `static-generics` implements zero-cost
solution which allows to implement generic statics in ~1-2 instructions on supported platforms (and falls back to hashmap on unsupported). 

## Requirements and limits

* Only `bytemuck::Zeroable` types can be stored in the static generic (use OnceSlot to lazily initialize any other types in static generic).
* No `Drop` support, all static generics are essentially leaked. If you need to clean-up memory after them, it has to be done manually. 
* Within a single crate the same `(Namespace, T)` is always the same address. Across crates or dynamic libraries sharing is not guaranteed: depending on optimization and linking, another crate may alias your slot or keep its own copy. Dynamic library loading in particular is not guaranteed to return the same address for `generic_static::<i32>()` done in `libA.so` and `libB.so`.

## Implementation

We use inline assembly + monomorphization of rustc to emit "unique" function body per each T. In the assembly
code block we define storage with weak + COMDAT linkage in a per-symbol `.bss` section with the name of unique function 
+ `gen_static_` prefix, and after that we compute the PC-relative address using `lea` on x86, `adrp` on arm, and so on.

Since the storage symbol is linkonce, the linker keeps a single copy per binary, so inlined `generic_static`
calls stay at 1 or 2 instructions with no runtime overhead.


## Platform support

- x86_64
- aarch64
- x86_32
- arm (Thumb as well)
- riscv32/riscv64
- loongarc32/loongarch64
- powerpc/powerpc64
- s390x
- wasm32: ONLY with `nightly` feature enabled, stable Rust does not support `asm!()` on WASM.

On other platforms (or with Miri/Cranelift detected) the crate will fallback to slow implementation via 
HashMap and Mutex.