parent
c5007ad6fa
commit
fd8f767077
@ -0,0 +1,182 @@
|
|||||||
|
//! Slice tools
|
||||||
|
use super::*;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::{slice, ptr, mem};
|
||||||
|
|
||||||
|
/// For an untyped `SliceMeta<T>`, this is the default `T`.
|
||||||
|
///
|
||||||
|
/// `SliceMeta<AnySlice>` is slice metadata that can **unsafely** coerce to slice metadata for any other type.
|
||||||
|
/// And any `SliceMeta<T>` can **safely** coerce to `SliceMeta<AnySlice>`.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
|
||||||
|
pub enum AnySlice { }
|
||||||
|
|
||||||
|
/// Metadata of a slice `[T]`.
|
||||||
|
///
|
||||||
|
/// # Usage
|
||||||
|
/// This may or may not point to a valid slice. The address may or may not be null.
|
||||||
|
/// It is intended for comparing pointer-identity of slice fat pointers.
|
||||||
|
///
|
||||||
|
/// # Layout
|
||||||
|
/// This type has a `repr(C)` memory layout of 2 `size_t`s and is safe for FFI use.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SliceMeta<T = AnySlice>
|
||||||
|
{
|
||||||
|
/// The address of the first element of the slice
|
||||||
|
/// # Notes
|
||||||
|
/// This can be `0` if the `SliceMeta` is initialised to `Default`, but a null-pointing `SliceMeta` is never safe to construct a real slice out of. The address may also be dangling, if the slice is 0 sized.
|
||||||
|
pub address: usize,
|
||||||
|
/// The length of the slice.
|
||||||
|
pub length: usize,
|
||||||
|
|
||||||
|
_slice: PhantomData<[T]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SliceMeta<AnySlice>
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Create a new `SliceMeta` representing this slice of any type.
|
||||||
|
pub fn from_slice_any<T>(slice: &[T]) -> Self
|
||||||
|
{
|
||||||
|
Self::new(slice.as_ptr() as usize, slice.len())
|
||||||
|
}
|
||||||
|
/// Is this instance referring to the data and length of this slice (regardless of type)?
|
||||||
|
pub fn is_slice_any<T>(&self, other: &[T]) -> bool
|
||||||
|
{
|
||||||
|
*self == Self::from_slice_any(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> SliceMeta<T>
|
||||||
|
{
|
||||||
|
#[inline(always)] fn assert_not_null(&self)
|
||||||
|
{
|
||||||
|
#[inline(never)] fn panic_null()
|
||||||
|
{
|
||||||
|
panic!("Address cannot be null");
|
||||||
|
}
|
||||||
|
if self.address == 0 {
|
||||||
|
panic_null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the type information from this instance.
|
||||||
|
#[inline(always)] pub const fn as_any(&self) -> SliceMeta<AnySlice>
|
||||||
|
{
|
||||||
|
SliceMeta {
|
||||||
|
address: self.address,
|
||||||
|
length: self.length,
|
||||||
|
|
||||||
|
_slice: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this slice metadata instance pointing to a null address? (i.e. undefined/empty).
|
||||||
|
#[inline(always)] pub const fn is_null(self) -> bool{
|
||||||
|
self.address == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The size in bytes of the slice pointed to at `address`.
|
||||||
|
#[inline] pub const fn length_bytes(self) -> usize
|
||||||
|
{
|
||||||
|
mem::size_of::<T>() * self.length
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this instance referring to the data and length of this slice?
|
||||||
|
pub fn is_slice(&self, other: &[T]) -> bool
|
||||||
|
{
|
||||||
|
self.as_any() == Self::from_slice(other).as_any()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `SliceMeta` representing this slice.
|
||||||
|
#[inline] pub fn from_slice(slice: &[T]) -> Self
|
||||||
|
{
|
||||||
|
Self::new(slice.as_ptr() as usize, slice.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new `SliceMeta` with these parameters.
|
||||||
|
#[inline] pub const fn new(address: usize, length: usize) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
address,
|
||||||
|
length,
|
||||||
|
_slice: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `address` as a raw pointer.
|
||||||
|
///
|
||||||
|
/// The pointer will be null if `address` is 0.
|
||||||
|
#[inline(always)] pub const fn as_ptr(self) -> *const T
|
||||||
|
{
|
||||||
|
self.address as *const T
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `address` as a mutable raw pointer.
|
||||||
|
///
|
||||||
|
/// The pointer will be null if `address` is 0.
|
||||||
|
#[inline(always)] pub const fn as_mut_ptr(self) -> *mut T
|
||||||
|
{
|
||||||
|
self.address as *mut T
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a raw slice from the metadata.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If `address` is 0.
|
||||||
|
#[inline] pub fn as_raw_slice(self) -> *const [T]
|
||||||
|
{
|
||||||
|
self.assert_not_null();
|
||||||
|
|
||||||
|
ptr::slice_from_raw_parts(self.address as *const T, self.length)
|
||||||
|
}
|
||||||
|
/// Create a mutable raw slice from the metadata.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If `address` is 0.
|
||||||
|
#[inline] pub fn as_raw_slice_mut(self) -> *mut [T]
|
||||||
|
{
|
||||||
|
self.assert_not_null();
|
||||||
|
|
||||||
|
ptr::slice_from_raw_parts_mut(self.address as *mut T, self.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a slice from the metadata.
|
||||||
|
///
|
||||||
|
/// This operation is unsafe.
|
||||||
|
/// # Safety
|
||||||
|
/// * `address` must be properly aligned and point to a valid `length` number of elements of `T`. If `length` is 0, the pointer can be dangling, but it cannot be null.
|
||||||
|
/// * Rust's slice requirements must be met using this metadata as a real slice.
|
||||||
|
/// * The lifetime chosen for the returned slice must be valid for the data pointed to by `address`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If `address` is 0.
|
||||||
|
#[inline] pub unsafe fn as_slice<'a>(self) -> &'a [T]
|
||||||
|
{
|
||||||
|
self.assert_not_null();
|
||||||
|
|
||||||
|
slice::from_raw_parts(self.address as *const T, self.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a mutable slice from the metadata.
|
||||||
|
///
|
||||||
|
/// This operation is unsafe.
|
||||||
|
/// # Safety
|
||||||
|
/// * `address` must be properly aligned and point to a valid `length` number of elements of `T`. If `length` is 0, the pointer can be dangling, but it cannot be null.
|
||||||
|
/// * Rust's slice requirements must be met using this metadata as a real slice.
|
||||||
|
/// * The lifetime chosen for the returned slice must be valid for the data pointed to by `address`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// If `address` is 0.
|
||||||
|
#[inline] pub unsafe fn as_slice_mut<'a>(self) -> &'a mut [T]
|
||||||
|
{
|
||||||
|
self.assert_not_null();
|
||||||
|
|
||||||
|
slice::from_raw_parts_mut(self.address as *mut T, self.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//accessor!(pub move address -> usize => 0; "The address of the first element of the slice\n\n# Notes\nThis can be `0` if the `SliceMeta` is initialised to `Default`, but a null-pointing `SliceMeta` is never safe to construct a real slice out of. The address may also be dangling, if the slice is 0 sized.");
|
||||||
|
}
|
Loading…
Reference in new issue