use std::{
fmt::{self, Display},
marker::PhantomData,
ptr::NonNull,
};
use crate::{
pointer_trait::{AsPtr, CanTransmuteElement, GetPointerKind, PK_Reference},
utils::ref_as_nonnull,
};
#[repr(transparent)]
#[derive(StableAbi)]
#[sabi(bound(T:'a))]
pub struct RRef<'a, T> {
ref_: NonNull<T>,
_marker: PhantomData<&'a T>,
}
impl<'a, T> Display for RRef<'a, T>
where
T: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(self.get(), f)
}
}
impl<'a, T> Clone for RRef<'a, T> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, T> Copy for RRef<'a, T> {}
unsafe impl<'a, T> Sync for RRef<'a, T> where &'a T: Sync {}
unsafe impl<'a, T> Send for RRef<'a, T> where &'a T: Send {}
shared_impls! {
mod=static_ref_impls
new_type=RRef['a][T],
original_type=AAAA,
deref_approach=(method = get),
}
impl<'a, T> RRef<'a, T> {
#[inline(always)]
pub const fn new(ref_: &'a T) -> Self {
Self {
ref_: ref_as_nonnull(ref_),
_marker: PhantomData,
}
}
#[inline(always)]
pub const unsafe fn from_raw(ref_: *const T) -> Self
where
T: 'a,
{
Self {
ref_: unsafe { NonNull::new_unchecked(ref_ as *mut T) },
_marker: PhantomData,
}
}
#[inline(always)]
pub const fn get(self) -> &'a T {
unsafe { crate::utils::deref!(self.ref_.as_ptr()) }
}
#[inline(always)]
pub const fn get_copy(self) -> T
where
T: Copy,
{
unsafe { *(self.ref_.as_ptr() as *const T) }
}
#[inline(always)]
pub const fn as_ptr(self) -> *const T {
self.ref_.as_ptr() as *const T
}
#[inline(always)]
pub const unsafe fn transmute<U>(self) -> RRef<'a, U>
where
U: 'a,
{
unsafe { RRef::from_raw(self.ref_.as_ptr() as *const U) }
}
#[inline(always)]
pub const fn transmute_into_raw<U>(self) -> *const U {
self.ref_.as_ptr() as *const T as *const U
}
#[inline(always)]
pub const unsafe fn transmute_into_ref<U>(self) -> &'a U
where
U: 'a,
{
unsafe { crate::utils::deref!(self.ref_.as_ptr() as *const T as *const U) }
}
}
unsafe impl<'a, T> GetPointerKind for RRef<'a, T> {
type Kind = PK_Reference;
type PtrTarget = T;
}
unsafe impl<'a, T, U> CanTransmuteElement<U> for RRef<'a, T>
where
U: 'a,
{
type TransmutedPtr = RRef<'a, U>;
#[inline(always)]
unsafe fn transmute_element_(self) -> Self::TransmutedPtr {
unsafe { self.transmute() }
}
}
unsafe impl<T> AsPtr for RRef<'_, T> {
#[inline(always)]
fn as_ptr(&self) -> *const T {
self.ref_.as_ptr() as *const T
}
#[inline(always)]
fn as_rref(&self) -> RRef<'_, T> {
*self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn construction_test() {
unsafe {
let three: *const i32 = &3;
assert_eq!(RRef::from_raw(three).get_copy(), 3);
}
assert_eq!(RRef::new(&5).get_copy(), 5);
}
#[test]
fn access() {
let reference = RRef::new(&8);
assert_eq!(*reference.get(), 8);
assert_eq!(reference.get_copy(), 8);
unsafe {
assert_eq!(*reference.as_ptr(), 8);
}
}
#[test]
fn transmutes() {
let reference = RRef::new(&(!0u32));
unsafe {
assert_eq!(reference.transmute::<i32>().get_copy(), -1);
assert_eq!(*reference.transmute_into_raw::<i32>(), -1);
assert_eq!(reference.transmute_into_ref::<i32>(), &-1);
}
}
#[test]
fn as_ptr_impl() {
let reference = RRef::new(&89u32);
unsafe {
assert_eq!(*AsPtr::as_ptr(&reference), 89);
assert_eq!(AsPtr::as_rref(&reference), reference);
}
}
}