#![doc = include_str!("../doc/ptr.md")]
use core::{
any,
cmp,
fmt,
hash::{
Hash,
Hasher,
},
marker::PhantomData,
mem,
ptr::{
self,
NonNull,
},
};
#[doc = include_str!("../doc/permission.md")]
pub trait Permission {
type Ptr<T: ?Sized>: RawPtr<T>;
type Ref<'a, T: 'a + ?Sized>: RawRef<'a, T>;
const DEBUG_PREFIX: &'static str;
#[doc(hidden)]
fn cast<T: ?Sized, U>(ptr: Self::Ptr<T>) -> Self::Ptr<U>;
#[doc(hidden)]
fn into_const<T: ?Sized>(ptr: Self::Ptr<T>) -> *const T;
#[doc(hidden)]
fn try_into_mut<T: ?Sized>(ptr: Self::Ptr<T>) -> Option<*mut T>;
#[doc(hidden)]
fn from_const<T: ?Sized>(ptr: *const T) -> Self::Ptr<T>;
#[doc(hidden)]
unsafe fn ptr_to_ref<'a, T: 'a + ?Sized>(
ptr: Self::Ptr<T>,
) -> Self::Ref<'a, T>;
#[doc(hidden)]
unsafe fn ptr_to_slice<T: Sized>(
ptr: Self::Ptr<T>,
len: usize,
) -> Self::Ptr<[T]>;
#[doc(hidden)]
fn addr<T: ?Sized>(ptr: Self::Ptr<T>) -> usize;
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Shared;
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Unique;
impl Permission for Shared {
type Ptr<T: ?Sized> = *const T;
type Ref<'a, T: 'a + ?Sized> = &'a T;
const DEBUG_PREFIX: &'static str = "*const";
fn cast<T: ?Sized, U>(ptr: *const T) -> *const U {
ptr.cast::<U>()
}
fn into_const<T: ?Sized>(ptr: *const T) -> *const T {
ptr
}
fn try_into_mut<T: ?Sized>(_: *const T) -> Option<*mut T> {
None
}
fn from_const<T: ?Sized>(ptr: *const T) -> *const T {
ptr
}
unsafe fn ptr_to_ref<'a, T: 'a + ?Sized>(ptr: *const T) -> &'a T {
&*ptr
}
unsafe fn ptr_to_slice<T: Sized>(ptr: *const T, len: usize) -> *const [T] {
ptr::slice_from_raw_parts(ptr, len)
}
fn addr<T: ?Sized>(ptr: *const T) -> usize {
ptr.cast::<()>() as usize
}
}
impl Permission for Unique {
type Ptr<T: ?Sized> = *mut T;
type Ref<'a, T: 'a + ?Sized> = &'a mut T;
const DEBUG_PREFIX: &'static str = "*mut";
fn cast<T: ?Sized, U>(ptr: *mut T) -> *mut U {
ptr.cast::<U>()
}
fn into_const<T: ?Sized>(ptr: *mut T) -> *const T {
ptr.cast_const()
}
fn try_into_mut<T: ?Sized>(ptr: *mut T) -> Option<*mut T> {
Some(ptr)
}
fn from_const<T: ?Sized>(ptr: *const T) -> *mut T {
ptr.cast_mut()
}
unsafe fn ptr_to_ref<'a, T: 'a + ?Sized>(ptr: *mut T) -> &'a mut T {
&mut *ptr
}
unsafe fn ptr_to_slice<T: Sized>(ptr: *mut T, len: usize) -> *mut [T] {
ptr::slice_from_raw_parts_mut(ptr, len)
}
fn addr<T: ?Sized>(ptr: *mut T) -> usize {
ptr.cast::<()>() as usize
}
}
impl<P> Permission for (Shared, P)
where P: Permission
{
type Ptr<T: ?Sized> = *const T;
type Ref<'a, T: 'a + ?Sized> = &'a T;
const DEBUG_PREFIX: &'static str = Shared::DEBUG_PREFIX;
fn cast<T: ?Sized, U>(ptr: *const T) -> *const U {
ptr.cast::<U>()
}
fn into_const<T: ?Sized>(ptr: *const T) -> *const T {
ptr
}
fn try_into_mut<T: ?Sized>(_: *const T) -> Option<*mut T> {
None
}
fn from_const<T: ?Sized>(ptr: *const T) -> *const T {
ptr
}
unsafe fn ptr_to_ref<'a, T: 'a + ?Sized>(ptr: *const T) -> &'a T {
&*ptr
}
unsafe fn ptr_to_slice<T: Sized>(ptr: *const T, len: usize) -> *const [T] {
ptr::slice_from_raw_parts(ptr, len)
}
fn addr<T: ?Sized>(ptr: *const T) -> usize {
ptr.cast::<()>() as usize
}
}
#[repr(transparent)]
#[doc = include_str!("../doc/pointers.md")]
pub struct Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
ptr: P::Ptr<T>,
}
impl<T> Pointer<T, Shared>
where T: ?Sized
{
pub const fn new(ptr: *const T) -> Self {
Self { ptr }
}
pub const fn into_inner(self) -> *const T {
self.ptr
}
}
impl<T> Pointer<T, Unique>
where T: ?Sized
{
pub const fn new(ptr: *mut T) -> Self {
Self { ptr }
}
pub const fn into_inner(self) -> *mut T {
self.ptr
}
pub unsafe fn as_mut<'a>(self) -> Option<&'a mut T> {
if self.is_null() {
return None;
}
Some(&mut *self.ptr)
}
pub unsafe fn drop_in_place(self) {
self.ptr.drop_in_place();
}
}
impl<T> Pointer<T, Unique>
where T: Sized
{
pub unsafe fn copy_from<P: Permission>(
self,
src: Pointer<T, P>,
count: usize,
) {
self.ptr.copy_from(
<(Shared, P)>::into_const::<T>(src.cast_const().ptr),
count,
);
}
pub unsafe fn copy_from_nonoverlapping<P: Permission>(
self,
src: Pointer<T, P>,
count: usize,
) {
self.ptr.copy_from_nonoverlapping(
<(Shared, P)>::into_const::<T>(src.cast_const().ptr),
count,
);
}
pub unsafe fn write(self, value: T) {
self.ptr.write(value);
}
pub unsafe fn write_bytes(self, byte: u8, count: usize) {
self.ptr.write_bytes(byte, count);
}
pub unsafe fn write_volatile(self, value: T) {
self.ptr.write_volatile(value);
}
pub unsafe fn write_unaligned(self, value: T) {
self.ptr.write_unaligned(value);
}
pub unsafe fn replace(self, value: T) -> T {
self.ptr.replace(value)
}
pub unsafe fn swap(self, with: Self) {
self.ptr.swap(with.ptr);
}
}
impl<T, P> Pointer<T, (Shared, P)>
where
T: ?Sized,
P: Permission,
{
pub fn cast_unshared(self) -> Pointer<T, P> {
Pointer {
ptr: <P>::from_const(self.into_const_ptr()),
}
}
}
impl<T, P> Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
pub fn from_ptr(ptr: P::Ptr<T>) -> Self {
Self { ptr }
}
pub fn as_ptr(self) -> P::Ptr<T> {
self.ptr
}
pub fn into_const_ptr(self) -> *const T {
P::into_const::<T>(self.ptr)
}
pub fn try_into_mut_ptr(self) -> Option<*mut T> {
P::try_into_mut::<T>(self.ptr)
}
pub fn is_null(self) -> bool {
self.ptr.is_null()
}
pub fn cast<U: Sized>(self) -> Pointer<U, P> {
let Self { ptr } = self;
Pointer {
ptr: <P as Permission>::cast::<T, U>(ptr),
}
}
pub unsafe fn as_ref<'a>(self) -> Option<&'a T> {
if self.is_null() {
return None;
};
Some(&*P::into_const(self.ptr))
}
pub unsafe fn as_reference<'a>(self) -> Option<Reference<'a, T, P>> {
if self.is_null() {
return None;
}
Some(P::ptr_to_ref(self.ptr))
}
pub fn cast_const(self) -> Pointer<T, Shared> {
Pointer {
ptr: self.into_const_ptr(),
}
}
pub unsafe fn cast_mut(self) -> Pointer<T, Unique> {
Pointer {
ptr: self.into_const_ptr().cast_mut(),
}
}
pub fn cast_shared(self) -> Pointer<T, (Shared, P)> {
let ptr = P::into_const(self.ptr);
let ptr = <(Shared, P)>::from_const(ptr);
Pointer { ptr }
}
pub fn addr(self) -> usize {
P::addr::<T>(self.ptr)
}
}
impl<T, P> Pointer<T, P>
where
T: Sized,
P: Permission,
{
pub fn dangling() -> Self {
Self {
ptr: P::from_const(mem::align_of::<T>() as *const T),
}
}
pub fn is_dangling(self) -> bool {
self == Self::dangling()
}
pub unsafe fn offset(self, by: isize) -> Self {
Self {
ptr: self.ptr.offset(by),
}
}
pub fn wrapping_offset(self, by: isize) -> Self {
Self {
ptr: self.ptr.wrapping_offset(by),
}
}
pub unsafe fn offset_from(self, origin: Self) -> isize {
self.ptr.offset_from(origin.ptr)
}
pub unsafe fn add(self, count: usize) -> Self {
debug_assert!(
count < (isize::MAX as usize),
"Addend ({}) exceeds maximum ({})",
count,
isize::MAX
);
self.offset(count as isize)
}
pub unsafe fn sub(self, count: usize) -> Self {
debug_assert!(
count < (isize::MAX as usize),
"Subtrahend ({}) exceeds maximum ({})",
count,
isize::MAX
);
self.offset(-(count as isize))
}
pub fn wrapping_add(self, count: usize) -> Self {
debug_assert!(
count < (isize::MAX as usize),
"Addend ({}) exceeds maximum ({})",
count,
isize::MAX
);
self.wrapping_offset(count as isize)
}
pub fn wrapping_sub(self, count: usize) -> Self {
debug_assert!(
count < (isize::MAX as usize),
"Subtrahend ({}) exceeds maximum ({})",
count,
isize::MAX
);
self.wrapping_offset(-(count as isize))
}
pub unsafe fn read(self) -> T {
self.ptr.read()
}
pub unsafe fn read_volatile(self) -> T {
self.ptr.read_volatile()
}
pub unsafe fn read_unaligned(self) -> T {
self.ptr.read_unaligned()
}
pub unsafe fn copy_to(self, dest: Pointer<T, Unique>, count: usize) {
self.ptr.copy_to(dest.ptr, count)
}
pub unsafe fn copy_to_nonoverlapping(
self,
dest: Pointer<T, Unique>,
count: usize,
) {
self.ptr.copy_to_nonoverlapping(dest.ptr, count)
}
pub fn align_offset(self, align: usize) -> usize {
self.ptr.align_offset(align)
}
pub unsafe fn make_slice(self, len: usize) -> Pointer<[T], P> {
Pointer::from_raw_parts(self, len)
}
}
impl<T, P> Pointer<[T], P>
where
T: Sized,
P: Permission,
{
pub unsafe fn from_raw_parts(ptr: Pointer<T, P>, len: usize) -> Self {
Self {
ptr: P::ptr_to_slice::<T>(ptr.ptr, len),
}
}
}
impl<T, P> fmt::Debug for Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
if fmt.alternate() {
write!(fmt, "({} {})", P::DEBUG_PREFIX, any::type_name::<T>())?;
}
fmt::Debug::fmt(&P::into_const(self.ptr), fmt)
}
}
impl<T, P> fmt::Pointer for Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&P::into_const(self.ptr), fmt)
}
}
impl<T, P> Clone for Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
fn clone(&self) -> Self {
*self
}
}
impl<T, P> Eq for Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
}
impl<T, P> Ord for Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
fn cmp(&self, other: &Self) -> cmp::Ordering {
let this = P::into_const(self.ptr);
let that = P::into_const(other.ptr);
this.cmp(&that)
}
}
impl<T, P1, P2> PartialEq<Pointer<T, P2>> for Pointer<T, P1>
where
T: ?Sized,
P1: Permission,
P2: Permission,
{
fn eq(&self, other: &Pointer<T, P2>) -> bool {
let this = P1::into_const(self.ptr);
let that = P2::into_const(other.ptr);
this == that
}
}
impl<T, P1, P2> PartialOrd<Pointer<T, P2>> for Pointer<T, P1>
where
T: ?Sized,
P1: Permission,
P2: Permission,
{
fn partial_cmp(&self, other: &Pointer<T, P2>) -> Option<cmp::Ordering> {
let this = P1::into_const(self.ptr);
let that = P2::into_const(other.ptr);
this.partial_cmp(&that)
}
}
impl<T> From<*const T> for Pointer<T, Shared>
where T: ?Sized
{
fn from(src: *const T) -> Self {
Self::new(src)
}
}
impl<T> From<&T> for Pointer<T, Shared>
where T: ?Sized
{
fn from(src: &T) -> Self {
Self::new(src)
}
}
impl<T> From<*mut T> for Pointer<T, Unique>
where T: ?Sized
{
fn from(src: *mut T) -> Self {
Self::new(src)
}
}
impl<T> From<&mut T> for Pointer<T, Unique>
where T: ?Sized
{
fn from(src: &mut T) -> Self {
Self::new(src)
}
}
impl<T, P> Hash for Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
fn hash<H: Hasher>(&self, hasher: &mut H) {
P::into_const(self.ptr).hash(hasher);
}
}
impl<T, P> Copy for Pointer<T, P>
where
T: ?Sized,
P: Permission,
{
}
#[repr(transparent)]
#[doc = include_str!("../doc/nonnull.md")]
pub struct NonNullPtr<T, P>
where
T: ?Sized,
P: Permission,
{
inner: NonNull<T>,
_perm: PhantomData<P>,
}
impl<T> NonNullPtr<T, Shared>
where T: ?Sized
{
pub fn new(ptr: *const T) -> Option<Self> {
NonNull::new(ptr.cast_mut()).map(Self::from_nonnull)
}
pub const unsafe fn new_unchecked(ptr: *const T) -> Self {
Self::from_nonnull(NonNull::new_unchecked(ptr.cast_mut()))
}
}
impl<T> NonNullPtr<T, Unique>
where T: ?Sized
{
pub fn new(ptr: *mut T) -> Option<Self> {
NonNull::new(ptr).map(Self::from_nonnull)
}
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
Self::from_nonnull(NonNull::new_unchecked(ptr))
}
}
impl<T, P> NonNullPtr<T, P>
where
T: ?Sized,
P: Permission,
{
pub const fn from_nonnull(ptr: NonNull<T>) -> Self {
Self {
inner: ptr,
_perm: PhantomData,
}
}
pub const fn cast<U: Sized>(self) -> NonNullPtr<U, P> {
let Self { inner, _perm } = self;
NonNullPtr {
inner: inner.cast::<U>(),
_perm,
}
}
pub fn as_pointer(self) -> Pointer<T, P> {
Pointer::from_ptr(P::from_const(self.inner.as_ptr().cast_const()))
}
pub unsafe fn as_reference<'a>(self) -> Reference<'a, T, P> {
P::ptr_to_ref(self.as_pointer().as_ptr())
}
}
impl<T, P> NonNullPtr<T, P>
where
T: Sized,
P: Permission,
{
pub const fn dangling() -> Self {
Self {
inner: NonNull::dangling(),
_perm: PhantomData,
}
}
}
#[doc = include_str!("../doc/references.md")]
pub type Reference<'a, T, P> = <P as Permission>::Ref<'a, T>;
#[doc(hidden)]
pub trait RawPtr<T: ?Sized>: Copy {
fn is_null(self) -> bool;
unsafe fn offset(self, by: isize) -> Self
where T: Sized;
fn wrapping_offset(self, by: isize) -> Self
where T: Sized;
unsafe fn offset_from(self, origin: Self) -> isize
where T: Sized;
unsafe fn read(self) -> T
where T: Sized;
unsafe fn read_volatile(self) -> T
where T: Sized;
unsafe fn read_unaligned(self) -> T
where T: Sized;
unsafe fn copy_to(self, dest: *mut T, count: usize)
where T: Sized;
unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
where T: Sized;
fn align_offset(self, align: usize) -> usize
where T: Sized;
}
macro_rules! impl_raw_ptr {
($($t:ty),+) => { $(
impl<T: ?Sized> RawPtr<T> for $t {
fn is_null(self) -> bool {
self.is_null()
}
unsafe fn offset(self, by: isize) -> Self
where T: Sized {
self.offset(by)
}
fn wrapping_offset(self, by: isize) -> Self
where T: Sized {
self.wrapping_offset(by)
}
unsafe fn offset_from(self, origin: Self) -> isize
where T: Sized {
self.offset_from(origin)
}
unsafe fn read(self) -> T
where T: Sized {
self.read()
}
unsafe fn read_volatile(self) -> T
where T: Sized {
self.read_volatile()
}
unsafe fn read_unaligned(self) -> T
where T: Sized {
self.read_unaligned()
}
unsafe fn copy_to(self, dest: *mut T, count: usize)
where T: Sized {
self.copy_to(dest, count);
}
unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
where T: Sized {
self.copy_to_nonoverlapping(dest, count);
}
fn align_offset(self, align: usize) -> usize
where T: Sized {
self.align_offset(align)
}
}
)+ };
}
impl_raw_ptr!(*const T, *mut T);
#[doc(hidden)]
pub trait RawRef<'a, T: ?Sized> {}
impl<'a, T: 'a + ?Sized> RawRef<'a, T> for &'a T {
}
impl<'a, T: 'a + ?Sized> RawRef<'a, T> for &'a mut T {
}
#[cfg(test)]
mod tests {
use super::*;
use static_assertions::*;
#[test]
fn permission_stack() {
assert_impl_all!(Shared: Permission);
assert_impl_all!(Unique: Permission);
assert_impl_all!((Shared, Shared): Permission);
assert_impl_all!((Shared, Unique): Permission);
assert_impl_all!((Shared, (Shared, Shared)): Permission);
assert_impl_all!((Shared, (Shared, Unique)): Permission);
}
}