use crate::pointer_trait::{AsPtr, CanTransmuteElement, GetPointerKind, PK_Reference};
use std::{
fmt::{self, Display},
ops::Deref,
ptr::NonNull,
};
#[repr(transparent)]
#[derive(StableAbi)]
pub struct StaticRef<T> {
ref_: NonNull<T>,
}
impl<T> Display for StaticRef<T>
where
T: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&**self, f)
}
}
impl<T> Clone for StaticRef<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for StaticRef<T> {}
unsafe impl<'a, T: 'a> Sync for StaticRef<T> where &'a T: Sync {}
unsafe impl<'a, T: 'a> Send for StaticRef<T> where &'a T: Send {}
shared_impls! {
mod=static_ref_impls
new_type=StaticRef[][T],
original_type=AAAA,
}
impl<T> StaticRef<T> {
pub const unsafe fn from_raw(ref_: *const T) -> Self {
Self {
ref_: unsafe { NonNull::new_unchecked(ref_ as *mut T) },
}
}
pub const fn new(ref_: &'static T) -> Self {
Self {
ref_: unsafe { NonNull::new_unchecked(ref_ as *const T as *mut T) },
}
}
pub fn leak_value(val: T) -> Self {
unsafe { Self::from_raw(crate::utils::leak_value(val)) }
}
pub const fn get<'a>(self) -> &'a T {
unsafe { crate::utils::deref!(self.ref_.as_ptr() as *const T) }
}
pub const fn as_ptr(self) -> *const T {
self.ref_.as_ptr() as *const T
}
pub const unsafe fn transmute<U>(self) -> StaticRef<U> {
unsafe { StaticRef::from_raw(self.ref_.as_ptr() as *const T as *const U) }
}
}
impl<T> Deref for StaticRef<T> {
type Target = T;
fn deref(&self) -> &T {
self.get()
}
}
unsafe impl<T> AsPtr for StaticRef<T> {
fn as_ptr(&self) -> *const T {
self.ref_.as_ptr() as *const T
}
}
unsafe impl<T> GetPointerKind for StaticRef<T> {
type Kind = PK_Reference;
type PtrTarget = T;
}
unsafe impl<T, U> CanTransmuteElement<U> for StaticRef<T> {
type TransmutedPtr = StaticRef<U>;
#[inline(always)]
unsafe fn transmute_element_(self) -> StaticRef<U> {
unsafe { self.transmute() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn construction_test() {
unsafe {
let three: *const i32 = &3;
assert_eq!(*StaticRef::from_raw(three), 3);
}
assert_eq!(*StaticRef::new(&5), 5);
assert_eq!(*StaticRef::leak_value(8), 8);
}
#[test]
fn access() {
let reference = StaticRef::new(&8);
const SREF: StaticRef<u8> = StaticRef::new(&8);
const REF: &u8 = SREF.get();
assert_eq!(*reference.get(), 8);
assert_eq!(*REF, 8);
unsafe {
assert_eq!(*reference.as_ptr(), 8);
}
}
#[test]
fn transmutes() {
let reference = StaticRef::new(&(!0u32));
unsafe {
assert_eq!(*reference.transmute::<i32>(), -1);
}
}
}