ownref/src/ptr.rs
2026-05-07 21:50:17 +03:00

114 lines
2.3 KiB
Rust

use std::{
any::Any,
marker::PhantomData,
mem::ManuallyDrop,
ops::{Deref, DerefMut},
ptr::NonNull,
};
#[repr(transparent)]
pub struct OwnRef<'a, T: ?Sized>(Option<NonNull<T>>, PhantomData<(&'a mut [u8], T)>);
impl<T: ?Sized> Drop for OwnRef<'_, T> {
fn drop(&mut self) {
let Some(p) = self.0 else { return };
unsafe { p.drop_in_place() };
}
}
impl<T: ?Sized> Deref for OwnRef<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { self.0.unwrap().as_ref() }
}
}
impl<T: ?Sized> DerefMut for OwnRef<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.0.unwrap().as_mut() }
}
}
impl<T: ?Sized> OwnRef<'_, T> {
pub unsafe fn new_unchecked(p: NonNull<T>) -> Self {
Self(Some(p), PhantomData)
}
pub fn into_inner(mut self) -> NonNull<T> {
self.0.take().unwrap()
}
}
impl<'a, T: ?Sized> OwnRef<'a, T> {
pub unsafe fn from_manually_drop(p: &'a mut ManuallyDrop<T>) -> Self {
unsafe { Self::new_unchecked(p.deref_mut().into()) }
}
pub fn into_manually_drop(self) -> &'a mut ManuallyDrop<T> {
let p = self.into_inner().as_ptr() as *mut ManuallyDrop<T>;
unsafe { p.as_mut().unwrap() }
}
}
impl<T> OwnRef<'_, T> {
pub fn take(mut self) -> T {
let p = self.0.take().unwrap();
unsafe { p.read() }
}
}
impl OwnRef<'_, dyn Any> {
pub fn take<U: 'static>(mut self) -> Result<U, Self> {
if !self.is::<U>() {
return Err(self);
}
let p = self.0.take().unwrap();
let p = p.cast::<U>();
Ok(unsafe { p.read() })
}
}
#[macro_export]
macro_rules! _to_ptr_own_ref {
($var:ident) => { $crate::_to_ptr_own_ref!(# $var) };
(mut $var:ident) => { $crate::_to_ptr_own_ref!(mut # $var) };
($($mut:ident)? # $var:ident) => {
let mut $var = ManuallyDrop::new($var);
let $($mut)? $var = unsafe { OwnRef::from_manually_drop(&mut $var) };
};
}
pub use _to_ptr_own_ref as to_own_ref;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ref() {
let obj = "some string".to_string();
to_own_ref!(obj);
assert_eq!(*obj, "some string");
}
#[test]
fn test_mut() {
let obj = b"some string".to_vec();
to_own_ref!(mut obj);
obj[0] = b'm';
obj[1] = b'o';
obj[2] = b'r';
obj[3] = b'e';
assert_eq!(*obj, b"more string");
}
#[test]
fn test_take() {
let obj = "some string".to_string();
to_own_ref!(obj);
let s: String = obj.take();
assert_eq!(s, "some string");
}
}