pbrt/shared/src/utils/ptr.rs

151 lines
3.3 KiB
Rust

use core::marker::PhantomData;
use core::ops::Index;
#[repr(transparent)]
#[derive(Debug)]
pub struct Ptr<T: ?Sized> {
ptr: *const T,
}
impl<T: ?Sized> Clone for Ptr<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for Ptr<T> {}
impl<T: ?Sized> PartialEq for Ptr<T> {
fn eq(&self, other: &Self) -> bool {
core::ptr::addr_eq(self.ptr, other.ptr)
}
}
impl<T: ?Sized> Eq for Ptr<T> {}
unsafe impl<T: ?Sized + Send> Send for Ptr<T> {}
unsafe impl<T: ?Sized + Sync> Sync for Ptr<T> {}
impl<T> Ptr<T> {
pub const fn null() -> Self {
Self {
ptr: core::ptr::null(),
}
}
pub const fn is_null(self) -> bool {
self.ptr.is_null()
}
pub fn from_raw(ptr: *const T) -> Self {
Self { ptr }
}
pub fn as_raw(self) -> *const T {
self.ptr
}
#[inline(always)]
pub unsafe fn as_ref<'a>(self) -> &'a T {
debug_assert!(!self.is_null(), "null Ptr dereference");
unsafe { &*self.ptr }
}
#[inline(always)]
pub fn get<'a>(self) -> Option<&'a T> {
if self.is_null() {
None
} else {
Some(unsafe { &*self.ptr })
}
}
#[inline(always)]
pub unsafe fn at<'a>(self, index: usize) -> &'a T {
debug_assert!(!self.is_null(), "null Ptr array access");
unsafe { &*self.ptr.add(index) }
}
/// Get element at index, returns None if ptr is null
#[inline(always)]
pub fn get_at<'a>(self, index: usize) -> Option<&'a T> {
if self.is_null() {
None
} else {
Some(unsafe { &*self.ptr.add(index) })
}
}
/// Offset the pointer, returning a new Ptr
#[inline(always)]
pub unsafe fn add(self, count: usize) -> Self {
Self {
ptr: unsafe { self.ptr.add(count) },
}
}
/// Convert to slice (requires knowing the length)
#[inline(always)]
pub unsafe fn as_slice<'a>(self, len: usize) -> &'a [T] {
debug_assert!(!self.is_null() || len == 0, "null Ptr to non-empty slice");
if len == 0 {
&[]
} else {
unsafe { core::slice::from_raw_parts(self.ptr, len) }
}
}
/// Convert to slice, returns None if null
#[inline(always)]
pub fn get_slice<'a>(self, len: usize) -> Option<&'a [T]> {
if self.is_null() {
if len == 0 { Some(&[]) } else { None }
} else {
Some(unsafe { core::slice::from_raw_parts(self.ptr, len) })
}
}
}
impl<T> core::ops::Deref for Ptr<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
debug_assert!(!self.is_null(), "Null Ptr dereference");
unsafe { &*self.ptr }
}
}
impl<T> Default for Ptr<T> {
fn default() -> Self {
Self::null()
}
}
impl<T> From<&T> for Ptr<T> {
fn from(r: &T) -> Self {
Self { ptr: r as *const T }
}
}
impl<T> From<&[T]> for Ptr<T> {
fn from(slice: &[T]) -> Self {
Self {
ptr: slice.as_ptr(),
}
}
}
impl<T> From<*const T> for Ptr<T> {
fn from(ptr: *const T) -> Self {
Self { ptr }
}
}
impl<T> From<Option<&T>> for Ptr<T> {
fn from(opt: Option<&T>) -> Self {
match opt {
Some(r) => Ptr::from(r),
None => Ptr::null(),
}
}
}