blob: 7f723d957d50925b22922564dda9771c11f6b65e [file] [log] [blame]
use alloc::boxed::Box;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
/// This is equivalent to &[T], except it has a stable repr(C) layout
#[repr(C)]
pub struct DiplomatSlice<'a, T> {
// Invariant: ptr is a valid ptr to the beginning of an &[T] allocation. It may be null if len is null
ptr: *const T,
// Invariant: the allocation contains at least `len` elements
len: usize,
phantom: PhantomData<&'a [T]>,
}
impl<T> Clone for DiplomatSlice<'_, T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for DiplomatSlice<'_, T> {}
impl<'a, T> From<&'a [T]> for DiplomatSlice<'a, T> {
fn from(x: &'a [T]) -> Self {
// Safe to construct since we're constructing it from a slice
DiplomatSlice {
ptr: x.as_ptr(),
len: x.len(),
phantom: PhantomData,
}
}
}
impl<'a, T> From<DiplomatSlice<'a, T>> for &'a [T] {
fn from(x: DiplomatSlice<'a, T>) -> Self {
unsafe {
// It's common in C-land to represent empty slices with NULL, which is not the case in Rust
// We normalize this
if x.ptr.is_null() {
debug_assert!(x.len == 0);
return &[];
}
// Safety: carrying over safety variants from DiplomatSlice, and we null-checked
core::slice::from_raw_parts(x.ptr, x.len)
}
}
}
impl<T> Deref for DiplomatSlice<'_, T> {
type Target = [T];
fn deref(&self) -> &[T] {
(*self).into()
}
}
/// This is equivalent to &mut [T], except it has a stable repr(C) layout
#[repr(C)]
pub struct DiplomatSliceMut<'a, T> {
// Invariant: ptr is a valid ptr to the beginning of an &[T] allocation. It may be null if len is null
ptr: *mut T,
// Invariant: the allocation contains at least `len` elements
len: usize,
phantom: PhantomData<&'a mut [T]>,
}
impl<'a, T> From<&'a mut [T]> for DiplomatSliceMut<'a, T> {
fn from(x: &'a mut [T]) -> Self {
// Safe to construct since we're constructing it from a slice
DiplomatSliceMut {
ptr: x.as_mut_ptr(),
len: x.len(),
phantom: PhantomData,
}
}
}
impl<'a, T> From<DiplomatSliceMut<'a, T>> for &'a mut [T] {
fn from(x: DiplomatSliceMut<'a, T>) -> Self {
unsafe {
if x.ptr.is_null() {
debug_assert!(x.len == 0);
return &mut [];
}
// Safety: carrying over safety variants from DiplomatSliceMut
core::slice::from_raw_parts_mut(x.ptr, x.len)
}
}
}
impl<T> Deref for DiplomatSliceMut<'_, T> {
type Target = [T];
fn deref(&self) -> &[T] {
if self.ptr.is_null() {
debug_assert!(self.len == 0);
return &[];
}
unsafe {
// Safety: carrying over safety variants from DiplomatSliceMut
core::slice::from_raw_parts(self.ptr, self.len)
}
}
}
impl<T> DerefMut for DiplomatSliceMut<'_, T> {
fn deref_mut(&mut self) -> &mut [T] {
if self.ptr.is_null() {
debug_assert!(self.len == 0);
return &mut [];
}
unsafe {
// Safety: carrying over safety variants from DiplomatSliceMut
core::slice::from_raw_parts_mut(self.ptr, self.len)
}
}
}
#[repr(C)]
pub struct DiplomatOwnedSlice<T> {
// Invariant: ptr is a valid ptr to the beginning of an owned Box<[T]> allocation. It may be null if len is null
ptr: *mut T,
// Invariant: the allocation contains `len` elements
len: usize,
phantom: PhantomData<Box<[T]>>,
}
impl<T> Drop for DiplomatOwnedSlice<T> {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe {
// Safety: This is equivalent to a valid Box
drop(Box::from_raw(core::ptr::slice_from_raw_parts_mut(
self.ptr, self.len,
)));
}
}
}
}
impl<T> From<Box<[T]>> for DiplomatOwnedSlice<T> {
fn from(x: Box<[T]>) -> Self {
// Safe to construct since we're constructing it from a valid Box<[T]>
let len = x.len();
DiplomatOwnedSlice {
ptr: Box::into_raw(x) as *mut T,
len,
phantom: PhantomData,
}
}
}
impl<T> From<DiplomatOwnedSlice<T>> for Box<[T]> {
fn from(x: DiplomatOwnedSlice<T>) -> Self {
let x = ManuallyDrop::new(x);
unsafe {
if x.ptr.is_null() {
debug_assert!(x.len == 0);
let dangling = core::ptr::NonNull::dangling().as_ptr();
return Box::from_raw(core::ptr::slice_from_raw_parts_mut(dangling, x.len));
}
// Safety: carrying over safety variants from DiplomatOwnedSlice
Box::from_raw(core::ptr::slice_from_raw_parts_mut(x.ptr, x.len))
}
}
}
impl<T> Deref for DiplomatOwnedSlice<T> {
type Target = [T];
fn deref(&self) -> &[T] {
if self.ptr.is_null() {
debug_assert!(self.len == 0);
return &[];
}
// Safety: The type invariants allow us to treat is as a valid Box<[T]>
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
}
}
impl<T> DerefMut for DiplomatOwnedSlice<T> {
fn deref_mut(&mut self) -> &mut [T] {
if self.ptr.is_null() {
debug_assert!(self.len == 0);
return &mut [];
}
// Safety: The type invariants allow us to treat is as a valid Box<[T]>
unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
}
}
/// This is equivalent to &str, except it has a stable repr(C) layout
// Safety invariant: contained slice must be valid UTF-8
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct DiplomatUtf8StrSlice<'a>(DiplomatSlice<'a, u8>);
impl<'a> From<&'a str> for DiplomatUtf8StrSlice<'a> {
fn from(x: &'a str) -> Self {
// Safety: invariant upheld; obtained from `str`
Self(x.as_bytes().into())
}
}
impl<'a> From<DiplomatUtf8StrSlice<'a>> for &'a str {
fn from(x: DiplomatUtf8StrSlice<'a>) -> Self {
unsafe {
// We can assume this because of the invariant on DiplomatUtf8StrSlice
core::str::from_utf8_unchecked(<&[u8]>::from(x.0))
}
}
}
impl Deref for DiplomatUtf8StrSlice<'_> {
type Target = str;
fn deref(&self) -> &str {
(*self).into()
}
}
/// This is equivalent to Box<str>, except it has a stable repr(C) layout
// Safety invariant: contained slice must be valid UTF-8
#[repr(transparent)]
pub struct DiplomatOwnedUTF8StrSlice(DiplomatOwnedSlice<u8>);
impl From<Box<str>> for DiplomatOwnedUTF8StrSlice {
fn from(x: Box<str>) -> Self {
// Safety: invariant upheld; obtained from `str`
Self(Box::<[u8]>::from(x).into())
}
}
impl From<DiplomatOwnedUTF8StrSlice> for Box<str> {
fn from(x: DiplomatOwnedUTF8StrSlice) -> Self {
let buf = Box::<[u8]>::from(x.0);
let len = buf.len();
let raw = Box::into_raw(buf);
let raw = if raw.is_null() {
debug_assert!(len == 0);
NonNull::<u8>::dangling().as_ptr()
} else {
raw as *mut u8
};
unsafe {
// We deconstructed the Box already so we don't have to worry about provenance
// We're technically making an &mut [u8] here, because there isn't an easy route to construct
// string types that are owned
let slice = core::slice::from_raw_parts_mut(raw, len);
// We can assume this because of the invariant on DiplomatOwnedUTF8StrSlice
let strslice = core::str::from_utf8_unchecked_mut(slice);
Box::from_raw(strslice as *mut str)
}
}
}
impl Deref for DiplomatOwnedUTF8StrSlice {
type Target = str;
fn deref(&self) -> &str {
let slice = &self.0;
unsafe {
// We can assume this because of the invariant on DiplomatOwnedUTF8StrSlice
core::str::from_utf8_unchecked(slice)
}
}
}
/// Like &str, but unvalidated
pub type DiplomatStrSlice<'a> = DiplomatSlice<'a, u8>;
/// Like Box<str>, but unvalidated
pub type DiplomatOwnedStrSlice = DiplomatOwnedSlice<u8>;
/// An unvalidated UTF-16 string
pub type DiplomatStr16Slice<'a> = DiplomatSlice<'a, u16>;
/// An unvalidated, owned UTF-16 string
pub type DiplomatOwnedStr16Slice<'a> = DiplomatOwnedSlice<u16>;