use std::{
alloc::{self, Layout},
fmt::{self, Display},
marker::PhantomData,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
ptr::{self, NonNull},
};
use crate::{sabi_types::RMut, std_types::RBox, traits::IntoInner};
#[repr(transparent)]
#[derive(StableAbi)]
#[sabi(bound(T:'a))]
pub struct MovePtr<'a, T> {
ptr: NonNull<T>,
_marker: PhantomData<crate::utils::MutRef<'a, T>>,
}
impl<'a, T> MovePtr<'a, T> {
#[inline]
pub unsafe fn new(ptr: &'a mut T) -> Self {
Self {
ptr: unsafe { NonNull::new_unchecked(ptr) },
_marker: PhantomData,
}
}
#[inline]
pub const unsafe fn from_rmut(ptr: RMut<'a, T>) -> Self {
Self {
ptr: unsafe { NonNull::new_unchecked(ptr.into_raw()) },
_marker: PhantomData,
}
}
pub const unsafe fn from_raw(ptr: *mut T) -> Self {
Self {
ptr: unsafe { NonNull::new_unchecked(ptr) },
_marker: PhantomData,
}
}
#[inline(always)]
pub const fn as_ptr(this: &Self) -> *const T {
this.ptr.as_ptr()
}
#[inline(always)]
pub fn as_mut_ptr(this: &mut Self) -> *mut T {
this.ptr.as_ptr()
}
#[inline]
pub const fn into_raw(this: Self) -> *mut T {
let ptr = this.ptr.as_ptr();
std::mem::forget(this);
ptr
}
#[inline]
pub fn into_box(this: Self) -> Box<T> {
unsafe {
let raw = Self::into_raw(this);
if std::mem::size_of::<T>() == 0 {
Box::from_raw(raw)
} else {
let allocated = alloc::alloc(Layout::new::<T>()) as *mut T;
raw.copy_to_nonoverlapping(allocated, 1);
Box::from_raw(allocated)
}
}
}
#[inline]
pub fn into_rbox(this: Self) -> RBox<T> {
Self::into_box(this).into()
}
#[inline]
pub fn into_inner(this: Self) -> T {
let this = ManuallyDrop::new(this);
unsafe { this.ptr.as_ptr().read() }
}
#[inline]
pub const unsafe fn transmute<U>(this: Self) -> MovePtr<'a, U>
where
U: 'a,
{
unsafe { std::mem::transmute::<MovePtr<'a, T>, MovePtr<'a, U>>(this) }
}
}
shared_impls! {
mod=move_ptr_impls
new_type=MovePtr['a][T],
original_type=AAAA,
}
impl<'a, T> Display for MovePtr<'a, T>
where
T: Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(&**self, f)
}
}
impl<'a, T> Deref for MovePtr<'a, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*(self.ptr.as_ptr() as *const _) }
}
}
impl<'a, T> DerefMut for MovePtr<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr.as_ptr() }
}
}
impl<'a, T> IntoInner for MovePtr<'a, T> {
type Element = T;
fn into_inner_(self) -> T {
Self::into_inner(self)
}
}
impl<'a, T> Drop for MovePtr<'a, T> {
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(self.ptr.as_ptr());
}
}
}
unsafe impl<'a, T: Send> Send for MovePtr<'a, T> {}
unsafe impl<'a, T: Sync> Sync for MovePtr<'a, T> {}
#[cfg(all(test, not(feature = "only_new_tests")))]
mod test {
use super::*;
use std::sync::Arc;
#[test]
fn with_manuallydrop() {
let arc = Arc::new(10);
unsafe {
let mut cloned_arc = ManuallyDrop::new(arc.clone());
let move_ptr = MovePtr::new(&mut *cloned_arc);
assert_eq!(Arc::strong_count(&*move_ptr), 2);
let moved_arc = MovePtr::into_inner(move_ptr);
assert_eq!(Arc::strong_count(&moved_arc), 2);
}
assert_eq!(Arc::strong_count(&arc), 1);
unsafe {
let mut cloned_arc = ManuallyDrop::new(arc.clone());
let move_ptr = MovePtr::new(&mut *cloned_arc);
assert_eq!(Arc::strong_count(&*move_ptr), 2);
}
assert_eq!(Arc::strong_count(&arc), 1);
}
#[test]
fn take_mutable_reference() {
unsafe {
let mut val = 3u32;
let mut mutref = ManuallyDrop::new(&mut val);
let mut move_ptr = MovePtr::<&mut u32>::new(&mut *mutref);
assert_eq!(**move_ptr, 3);
**move_ptr += 2;
assert_eq!(**move_ptr, 5);
let moved_mut: &mut u32 = MovePtr::into_inner(move_ptr);
assert_eq!(*moved_mut, 5);
}
}
}