use std::{
fmt::{self, Display},
marker::PhantomData,
ptr::NonNull,
};
use crate::{
pointer_trait::{AsMutPtr, AsPtr, CanTransmuteElement, GetPointerKind, PK_MutReference},
sabi_types::RRef,
};
#[repr(transparent)]
#[derive(StableAbi)]
#[sabi(bound(T:'a))]
pub struct RMut<'a, T> {
ref_: NonNull<T>,
_marker: PhantomData<crate::utils::MutRef<'a, T>>,
}
impl<'a, T> Display for RMut<'a, T>
where
T: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(self.get(), f)
}
}
unsafe impl<'a, T> Sync for RMut<'a, T> where &'a T: Sync {}
unsafe impl<'a, T> Send for RMut<'a, T> where &'a T: Send {}
shared_impls! {
mod=static_ref_impls
new_type=RMut['a][T],
original_type=AAAA,
deref_approach=(method = get),
}
impl<'a, T> RMut<'a, T> {
#[inline(always)]
pub fn new(ref_: &'a mut T) -> Self {
unsafe {
Self {
ref_: NonNull::new_unchecked(ref_),
_marker: PhantomData,
}
}
}
#[inline(always)]
pub const unsafe fn from_raw(ref_: *mut T) -> Self
where
T: 'a,
{
Self {
ref_: unsafe { NonNull::new_unchecked(ref_) },
_marker: PhantomData,
}
}
#[inline(always)]
pub fn reborrow(&mut self) -> RMut<'_, T> {
RMut {
ref_: self.ref_,
_marker: PhantomData,
}
}
#[inline(always)]
pub const fn get(&self) -> &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 into_ref(self) -> &'a T {
unsafe { crate::utils::deref!(self.ref_.as_ptr()) }
}
#[inline(always)]
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.ref_.as_ptr() }
}
#[inline(always)]
pub fn into_mut(self) -> &'a mut T {
unsafe { &mut *self.ref_.as_ptr() }
}
#[inline]
pub const fn as_ptr(&self) -> *const T {
self.ref_.as_ptr()
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut T {
self.ref_.as_ptr()
}
#[inline]
pub const fn into_raw(self) -> *mut T {
self.ref_.as_ptr()
}
#[inline(always)]
pub const fn transmute_into_raw<U>(self) -> *mut U {
self.ref_.as_ptr() as *mut U
}
#[inline(always)]
pub unsafe fn transmute_into_mut<U>(self) -> &'a mut U
where
U: 'a,
{
unsafe { &mut *(self.ref_.as_ptr() as *mut U) }
}
#[inline(always)]
pub const unsafe fn transmute<U>(self) -> RMut<'a, U>
where
U: 'a,
{
unsafe { RMut::from_raw(self.ref_.as_ptr() as *mut U) }
}
#[inline(always)]
#[allow(clippy::needless_lifetimes)]
pub const fn as_rref<'r>(&'r self) -> RRef<'r, T> {
unsafe { RRef::from_raw(self.ref_.as_ptr()) }
}
#[inline(always)]
pub const fn into_rref(self) -> RRef<'a, T> {
unsafe { RRef::from_raw(self.ref_.as_ptr()) }
}
}
unsafe impl<'a, T> AsPtr for RMut<'a, T> {
#[inline(always)]
fn as_ptr(&self) -> *const T {
self.ref_.as_ptr() as *const T
}
#[inline(always)]
fn as_rref(&self) -> RRef<'_, T> {
unsafe { RRef::from_raw(self.ref_.as_ptr() as *const T) }
}
}
unsafe impl<'a, T> AsMutPtr for RMut<'a, T> {
#[inline(always)]
fn as_mut_ptr(&mut self) -> *mut T {
self.ref_.as_ptr()
}
#[inline(always)]
fn as_rmut(&mut self) -> RMut<'_, T> {
self.reborrow()
}
}
unsafe impl<'a, T> GetPointerKind for RMut<'a, T> {
type Kind = PK_MutReference;
type PtrTarget = T;
}
unsafe impl<'a, T, U> CanTransmuteElement<U> for RMut<'a, T>
where
U: 'a,
{
type TransmutedPtr = RMut<'a, U>;
#[inline(always)]
unsafe fn transmute_element_(self) -> Self::TransmutedPtr {
unsafe { self.transmute() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn construction_test() {
unsafe {
let val: *mut i32 = &mut 3;
let mut rmut = RMut::from_raw(val);
*rmut.get_mut() += 5;
assert_eq!(rmut.get_copy(), 8);
}
{
let val = &mut 3;
let mut rmut = RMut::new(val);
*rmut.get_mut() += 5;
assert_eq!(rmut.get_copy(), 8);
}
}
#[test]
fn access() {
let mut num = 5;
let mut mutref = RMut::new(&mut num);
assert_eq!(*mutref.get_mut(), 5);
*mutref.get_mut() = 21;
assert_eq!(*mutref.get(), 21);
assert_eq!(mutref.get_copy(), 21);
assert_eq!(*mutref.reborrow().into_ref(), 21);
*mutref.reborrow().into_mut() = 34;
unsafe {
assert_eq!(*mutref.as_ptr(), 34);
*mutref.as_mut_ptr() = 55;
assert_eq!(*mutref.reborrow().into_raw(), 55);
*mutref.reborrow().into_raw() = 89;
}
assert_eq!(num, 89);
}
#[test]
fn transmutes() {
let mut num = 0u8;
unsafe {
let ptr = RMut::new(&mut num).transmute_into_raw::<Enum>();
assert_eq!(*ptr, Enum::Foo);
ptr.write(Enum::Bar);
assert_eq!(*ptr, Enum::Bar);
assert_eq!(num, 1);
}
unsafe {
let mref = RMut::new(&mut num).transmute_into_mut::<Enum>();
assert_eq!(*mref, Enum::Bar);
*mref = Enum::Qux;
assert_eq!(*mref, Enum::Qux);
assert_eq!(num, 2);
}
unsafe {
let mut rmut = RMut::new(&mut num).transmute::<Enum>();
assert_eq!(rmut, RMut::new(&mut Enum::Qux));
*rmut.get_mut() = Enum::Foo;
assert_eq!(*rmut.get(), Enum::Foo);
assert_eq!(num, 0);
}
unsafe {
let mut rmut: RMut<'_, Enum> = RMut::new(&mut num).transmute_element_();
assert_eq!(rmut, RMut::new(&mut Enum::Foo));
*rmut.get_mut() = Enum::Bar;
assert_eq!(*rmut.get(), Enum::Bar);
assert_eq!(num, 1);
}
}
#[test]
fn as_rtype_test() {
let mut num = 0u8;
let mut rmut = RMut::new(&mut num);
assert_eq!(rmut.as_rref(), RRef::new(&0));
assert_eq!(rmut.reborrow().into_rref(), RRef::new(&0));
assert_eq!(rmut.as_rmut(), RMut::new(&mut 0));
}
#[derive(Debug, PartialEq)]
#[repr(u8)]
enum Enum {
Foo = 0,
Bar = 1,
Qux = 2,
}
}