diff --git a/src/ext.rs b/src/ext.rs index c7b0aba..4373569 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -159,6 +159,49 @@ where F: FnOnce(&mut [u8]) -> T } } +/// Create an accessor method. for a field in a structure. +/// +/// The supported accessor types are: `ref`, `mut`, and `move`. +#[macro_export] macro_rules! accessor { + ($vis:vis ref $name:ident -> $ty:ty => $internal:ident $(; $comment:literal)?) => { + $(#[doc=$comment])? + #[inline] $vis fn $name(&self) -> &$ty { + &self.$internal + } + }; + ($vis:vis ref $name:ident -> $ty:ty => $internal:tt $(; $comment:literal)?) => { + $(#[doc=$comment])? + #[inline] $vis fn $name(&self) -> &$ty { + &self.$internal + } + }; + ($vis:vis mut $name:ident -> $ty:ty => $internal:ident $(; $comment:literal)?) => { + $(#[doc=$comment])? + #[inline] $vis fn $name(&self) -> &mut $ty { + &mut self.$internal + } + }; + ($vis:vis mut $name:ident -> $ty:ty => $internal:tt $(; $comment:literal)?) => { + $(#[doc=$comment])? + #[inline] $vis fn $name(&self) -> &mut $ty { + &mut self.$internal + } + }; + ($vis:vis move $name:ident -> $ty:ty => $internal:ident $(; $comment:literal)?) => { + $(#[doc=$comment])? + #[inline] $vis fn $name(&self) -> $ty { + self.$internal + } + }; + ($vis:vis move $name:ident -> $ty:ty => $internal:tt $(; $comment:literal)?) => { + $(#[doc=$comment])? + #[inline] $vis fn $name(&self) -> $ty { + self.$internal + } + }; +} + + pub mod bytes { use super::*; @@ -170,3 +213,5 @@ pub mod bytes } } } + +pub mod slice; diff --git a/src/ext/slice.rs b/src/ext/slice.rs new file mode 100644 index 0000000..6c8bb8f --- /dev/null +++ b/src/ext/slice.rs @@ -0,0 +1,182 @@ +//! Slice tools +use super::*; +use std::marker::PhantomData; +use std::{slice, ptr, mem}; + +/// For an untyped `SliceMeta`, this is the default `T`. +/// +/// `SliceMeta` is slice metadata that can **unsafely** coerce to slice metadata for any other type. +/// And any `SliceMeta` can **safely** coerce to `SliceMeta`. +#[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 +{ + /// 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 +{ + + /// Create a new `SliceMeta` representing this slice of any type. + pub fn from_slice_any(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(&self, other: &[T]) -> bool + { + *self == Self::from_slice_any(other) + } +} + +impl SliceMeta +{ + #[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 + { + 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::() * 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."); +} diff --git a/src/lib.rs b/src/lib.rs index 72b624a..f20a152 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ mod stream; pub use stream::{ AsyncStream, - EncryptedStream, +// EncryptedStream, WriteHalf, ReadHalf, };