#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate core;
#[cfg(feature = "alloc")]
extern crate alloc;
use core::cell::{Cell, RefCell};
#[cfg(feature = "alloc")]
use core::ops::Deref;
use core::ptr::{self, NonNull};
#[cfg(feature = "std")]
use std::ffi::{CStr, CString};
#[cfg(feature = "std")]
use std::os::raw::c_char;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
#[cfg(feature = "alloc")]
use alloc::sync::Arc;
macro_rules! asptr_wrapper {
($name:ident) => {
impl<T> AsPtr for $name<T> {
type Raw = T;
#[inline]
fn as_ptr(&self) -> *const T {
$name::as_ptr(self)
}
}
};
}
#[cfg(feature = "alloc")]
macro_rules! owned_ptr_wrapper {
($name:ident) => {
impl<T: ?Sized> IntoRaw for $name<T> {
type Raw = T;
fn into_raw(self) -> *mut T {
$name::into_raw(self) as *mut T
}
}
impl<T: ?Sized> FromRaw<T> for $name<T> {
unsafe fn from_raw(raw: *mut T) -> $name<T> {
$name::from_raw(raw)
}
}
};
}
pub trait AsPtr {
type Raw: ?Sized;
fn as_ptr(&self) -> *const Self::Raw;
}
impl<T> AsPtr for [T] {
type Raw = T;
#[inline]
fn as_ptr(&self) -> *const T {
<[T]>::as_ptr(self)
}
}
impl<'a, T: ?Sized> AsPtr for &'a T {
type Raw = T;
#[inline]
fn as_ptr(&self) -> *const T {
*self as *const T
}
}
impl<T: ?Sized> AsPtr for NonNull<T> {
type Raw = T;
#[inline]
fn as_ptr(&self) -> *const T {
NonNull::as_ptr(*self)
}
}
impl<T: ?Sized> AsPtr for *const T {
type Raw = T;
#[inline]
fn as_ptr(&self) -> *const T {
*self
}
}
#[cfg(feature = "std")]
impl AsPtr for CStr {
type Raw = c_char;
#[inline]
fn as_ptr(&self) -> *const c_char {
CStr::as_ptr(self)
}
}
#[cfg(feature = "std")]
impl AsPtr for CString {
type Raw = c_char;
#[inline]
fn as_ptr(&self) -> *const c_char {
CStr::as_ptr(self)
}
}
#[cfg(feature = "alloc")]
impl<T: ?Sized> AsPtr for Box<T> {
type Raw = T;
#[inline]
fn as_ptr(&self) -> *const T {
self.deref().as_ptr()
}
}
impl<T> AsPtr for Option<T>
where
T: AsPtr,
T::Raw: Sized,
{
type Raw = T::Raw;
#[inline]
fn as_ptr(&self) -> *const T::Raw {
match self {
Some(ref v) => v.as_ptr(),
None => ptr::null(),
}
}
}
asptr_wrapper!(Cell);
asptr_wrapper!(RefCell);
#[cfg(feature = "alloc")]
asptr_wrapper!(Rc);
#[cfg(feature = "alloc")]
asptr_wrapper!(Arc);
pub trait IntoRaw {
type Raw: ?Sized;
fn into_raw(self) -> *mut Self::Raw;
}
#[cfg(feature = "std")]
impl IntoRaw for CString {
type Raw = c_char;
#[inline]
fn into_raw(self) -> *mut c_char {
CString::into_raw(self)
}
}
impl<T: ?Sized> IntoRaw for *mut T {
type Raw = T;
#[inline]
fn into_raw(self) -> *mut T {
self
}
}
impl<T: ?Sized> IntoRaw for NonNull<T> {
type Raw = T;
#[inline]
fn into_raw(self) -> *mut T {
self.as_ptr()
}
}
impl<T> IntoRaw for Option<T>
where
T: IntoRaw,
T::Raw: Sized,
{
type Raw = T::Raw;
#[inline]
fn into_raw(self) -> *mut T::Raw {
match self {
Some(v) => v.into_raw(),
None => ptr::null_mut(),
}
}
}
pub trait FromRaw<T: ?Sized> {
unsafe fn from_raw(raw: *mut T) -> Self;
}
#[cfg(feature = "std")]
impl FromRaw<c_char> for CString {
#[inline]
unsafe fn from_raw(raw: *mut c_char) -> CString {
CString::from_raw(raw)
}
}
impl<T: ?Sized> FromRaw<T> for *mut T {
#[inline]
unsafe fn from_raw(raw: *mut T) -> *mut T {
raw
}
}
impl<T: ?Sized> FromRaw<T> for *const T {
#[inline]
unsafe fn from_raw(raw: *mut T) -> *const T {
raw
}
}
impl<T: ?Sized> FromRaw<T> for NonNull<T> {
#[inline]
unsafe fn from_raw(raw: *mut T) -> NonNull<T> {
NonNull::new_unchecked(raw)
}
}
impl<T, U: ?Sized> FromRaw<U> for Option<T>
where
T: FromRaw<U>,
{
unsafe fn from_raw(raw: *mut U) -> Option<T> {
if raw.is_null() {
None
} else {
Some(T::from_raw(raw))
}
}
}
#[cfg(feature = "alloc")]
owned_ptr_wrapper!(Box);
#[cfg(feature = "alloc")]
owned_ptr_wrapper!(Rc);
#[cfg(feature = "alloc")]
owned_ptr_wrapper!(Arc);
pub trait FromRawFamily {
type Pointer<T: ?Sized>;
unsafe fn from_raw<T: ?Sized>(raw: *mut T) -> Self::Pointer<T>;
}
macro_rules! from_raw_family_impl {
($family:ident($t:ty) $v:ident => $from_raw:expr) => {
pub struct $family;
impl FromRawFamily for $family {
type Pointer<T: ?Sized> = $t;
unsafe fn from_raw<T: ?Sized>($v: *mut T) -> Self::Pointer<T> {
$from_raw
}
}
};
}
from_raw_family_impl!(MutPtrFamily(*mut T) r => r);
from_raw_family_impl!(ConstPtrFamily(*const T) r => r);
from_raw_family_impl!(NonNullFamily(NonNull<T>) r => NonNull::new_unchecked(r));
pub struct OptionFromRawFamily<P> {
_phantom: core::marker::PhantomData<P>,
}
impl<P: FromRawFamily> FromRawFamily for OptionFromRawFamily<P> {
type Pointer<T: ?Sized> = Option<P::Pointer<T>>;
unsafe fn from_raw<T: ?Sized>(raw: *mut T) -> Self::Pointer<T> {
if raw.is_null() {
None
} else {
Some(P::from_raw(raw))
}
}
}
macro_rules! owned_pointer_kind {
($name:ident, $ptr_name:ident) => {
from_raw_family_impl!($name($ptr_name<T>) r => $ptr_name::from_raw(r));
};
}
#[cfg(feature = "alloc")]
owned_pointer_kind!(BoxFamily, Box);
#[cfg(feature = "alloc")]
owned_pointer_kind!(RcFamily, Rc);
#[cfg(feature = "alloc")]
owned_pointer_kind!(ArcFamily, Arc);
#[cfg(test)]
mod tests {
use super::*;
macro_rules! as_ptr_test {
($name:ident, $t:ty, $init:expr, $compare:expr) => {
#[test]
fn $name() {
let x = $init;
let y: *const <$t as AsPtr>::Raw = <$t as AsPtr>::as_ptr(&x);
unsafe {
assert_eq!(*y, $compare);
}
}
};
}
as_ptr_test!(ref_as_ptr, &u32, &5, 5);
as_ptr_test!(nonnull_as_ptr, NonNull<u32>, NonNull::from(&5), 5);
as_ptr_test!(ptr_as_ptr, *const u32, &5u32 as *const u32, 5);
#[cfg(feature = "std")]
as_ptr_test!(
cstr_as_ptr,
CStr,
CStr::from_bytes_with_nul("abc\0".as_bytes()).unwrap(),
'a' as c_char
);
#[cfg(feature = "std")]
as_ptr_test!(
cstring_as_ptr,
CString,
CString::new("abc").unwrap(),
'a' as c_char
);
#[cfg(feature = "alloc")]
as_ptr_test!(box_as_ptr, Box<u16>, Box::new(3u16), 3);
as_ptr_test!(cell_as_ptr, Cell<u16>, Cell::new(7u16), 7);
as_ptr_test!(refcell_as_ptr, RefCell<u16>, RefCell::new(7u16), 7);
#[cfg(feature = "alloc")]
as_ptr_test!(rc_as_ptr, Rc<u16>, Rc::new(8u16), 8);
#[cfg(feature = "alloc")]
as_ptr_test!(arc_as_ptr, Arc<u16>, Arc::new(8u16), 8);
as_ptr_test!(some_as_ptr, Option<&u32>, Some(&1u32), 1);
#[test]
fn none_as_ptr() {
let x: Option<&u16> = None;
let y: *const u16 = <Option<&u16> as AsPtr>::as_ptr(&x);
assert!(y.is_null());
}
#[cfg(feature = "alloc")]
macro_rules! from_into_test {
($name:ident, $t:ty, $init: expr, $cmp:expr) => {
#[test]
fn $name() {
let orig = $init;
let p = <$t as IntoRaw>::into_raw(orig);
let back = unsafe { <$t as FromRaw<_>>::from_raw(p) };
assert_eq!(*back, $cmp);
}
};
}
#[cfg(feature = "std")]
from_into_test!(
cstring_from_into,
CString,
CString::new("abc").unwrap(),
*CStr::from_bytes_with_nul("abc\0".as_bytes()).unwrap()
);
#[cfg(feature = "alloc")]
from_into_test!(box_from_into, Box<u16>, Box::new(4u16), 4);
#[cfg(feature = "alloc")]
from_into_test!(rc_from_into, Rc<u16>, Rc::new(4u16), 4);
#[cfg(feature = "alloc")]
from_into_test!(arc_from_into, Arc<u16>, Arc::new(4u16), 4);
#[test]
fn ptr_from_into() {
let mut data: u32 = 10;
let p = <*mut u32 as IntoRaw>::into_raw(&mut data);
unsafe {
let mptr: *mut u32 = <*mut u32 as FromRaw<_>>::from_raw(p);
*mptr = 54;
}
unsafe {
let cptr = <*const u32 as FromRaw<_>>::from_raw(p);
assert_eq!(*cptr, 54);
}
}
#[test]
fn nonnull_from_into() {
let mut data: u32 = 10;
let p = <NonNull<u32> as IntoRaw>::into_raw(NonNull::from(&mut data));
unsafe {
*p = 34;
let p = <NonNull<u32> as FromRaw<_>>::from_raw(p);
assert_eq!(p, NonNull::from(&data));
}
assert_eq!(data, 34);
}
#[test]
fn some_from_into() {
let mut data: u32 = 10;
let p = <Option<*mut u32> as IntoRaw>::into_raw(Some(&mut data));
unsafe {
*p = 54;
let p = <Option<*const u32> as FromRaw<_>>::from_raw(p);
assert_eq!(p, Some(&data as *const u32));
};
assert_eq!(data, 54);
}
#[test]
fn none_into() {
assert!(<Option<*mut u16> as IntoRaw>::into_raw(None).is_null());
}
#[test]
fn none_from() {
let p = unsafe { <Option<*mut u16> as FromRaw<_>>::from_raw(core::ptr::null_mut()) };
assert_eq!(p, None);
}
fn family_round_trip<F: FromRawFamily, V>(v: F::Pointer<V>) -> F::Pointer<V>
where
F::Pointer<V>: IntoRaw<Raw = V>,
{
let p = v.into_raw();
unsafe { F::from_raw(p) }
}
fn test_from_family<F: FromRawFamily, V>(p: F::Pointer<V>, cmp: &V)
where
F::Pointer<V>: IntoRaw<Raw = V> + Deref<Target = V>,
V: std::fmt::Debug + Eq,
{
let ptr = family_round_trip::<F, _>(p);
assert_eq!(&*ptr, cmp);
}
#[test]
fn mut_ptr_family() {
let mut x = 4;
let p = family_round_trip::<MutPtrFamily, _>(&mut x as *mut _);
assert_eq!(p, &mut x as *mut _);
assert_eq!(unsafe { *p }, 4);
}
#[test]
fn const_ptr_family() {
let mut x = 23;
let p = unsafe { ConstPtrFamily::from_raw(&mut x as *mut _) };
assert_eq!(p, &x as *const _);
assert_eq!(unsafe { *p }, 23);
}
#[test]
fn nonnull_family() {
let mut x = 23;
let p = unsafe { NonNull::from_raw(&mut x as *mut _) };
assert_eq!(p, (&x).into());
assert_eq!(unsafe { *p.as_ref() }, 23);
}
#[test]
fn option_family_none() {
let n = ptr::null_mut::<u8>();
assert!(unsafe { OptionFromRawFamily::<MutPtrFamily>::from_raw(n) }.is_none());
}
#[test]
fn option_family_some() {
let mut x = 89;
let p = unsafe { OptionFromRawFamily::<MutPtrFamily>::from_raw(&mut x as *mut _) };
assert!(p.is_some());
assert_eq!(p, Some(&mut x as *mut _));
assert_eq!(unsafe { *p.unwrap() }, 89);
}
#[test]
fn box_family() {
test_from_family::<BoxFamily, _>(Box::new(16), &16);
}
#[test]
fn rc_family() {
test_from_family::<RcFamily, _>(Rc::new(16), &16);
}
#[test]
fn arc_family() {
test_from_family::<ArcFamily, _>(Arc::new(16), &16);
}
}