#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use core::ptr::NonNull;
use core::{
cell::{Cell, UnsafeCell},
mem::ManuallyDrop,
};
pub trait Wide {
type Data;
type Metadata;
fn metadata(&self) -> Self::Metadata;
fn as_ptr(&self) -> *const Self::Data;
fn as_mut_ptr(&mut self) -> *mut Self::Data;
#[cfg(feature = "alloc")]
fn into_non_null(self: Box<Self>) -> NonNull<Self::Data>;
unsafe fn from_raw_parts<'a>(data: *const Self::Data, metadata: Self::Metadata) -> &'a Self;
unsafe fn from_raw_parts_mut<'a>(
data: *mut Self::Data,
metadata: Self::Metadata,
) -> &'a mut Self;
#[cfg(feature = "alloc")]
unsafe fn from_non_null(data: NonNull<Self::Data>, metadata: Self::Metadata) -> Box<Self>;
}
macro_rules! impl_wide_for_transparent_wrapper {
($($wrapper:ident),+ $(,)?) => {$(
impl<R: Wide<Data: crate::ExternC> + ?Sized> Wide for $wrapper<R> {
type Data = R::Data;
type Metadata = R::Metadata;
fn metadata(&self) -> Self::Metadata {
unsafe { (&*(self as *const Self as *const R)).metadata() }
}
fn as_ptr(&self) -> *const Self::Data {
self as *const Self as *const Self::Data
}
fn as_mut_ptr(&mut self) -> *mut Self::Data {
self as *mut Self as *mut Self::Data
}
#[cfg(feature = "alloc")]
fn into_non_null(self: Box<Self>) -> NonNull<Self::Data> {
let ptr = Box::into_raw(self).cast::<Self::Data>();
unsafe { NonNull::new_unchecked(ptr) }
}
unsafe fn from_raw_parts<'a>(
data: *const Self::Data,
metadata: Self::Metadata,
) -> &'a Self {
let inner = unsafe { R::from_raw_parts(data, metadata) };
unsafe { &*(inner as *const R as *const Self) }
}
unsafe fn from_raw_parts_mut<'a>(
data: *mut Self::Data,
metadata: Self::Metadata,
) -> &'a mut Self {
let inner = unsafe { R::from_raw_parts_mut(data, metadata) };
unsafe { &mut *(inner as *mut R as *mut Self) }
}
#[cfg(feature = "alloc")]
unsafe fn from_non_null(
data: NonNull<Self::Data>,
metadata: Self::Metadata,
) -> Box<Self> {
let inner = unsafe { R::from_raw_parts_mut(data.as_ptr(), metadata) };
unsafe { Box::from_raw(inner as *mut R as *mut Self) }
}
}
)+};
}
impl_wide_for_transparent_wrapper!(UnsafeCell, Cell, ManuallyDrop);
impl<R> Wide for [R] {
type Data = R;
type Metadata = usize;
fn metadata(&self) -> Self::Metadata {
Self::len(self)
}
fn as_ptr(&self) -> *const Self::Data {
Self::as_ptr(self)
}
fn as_mut_ptr(&mut self) -> *mut Self::Data {
Self::as_mut_ptr(self)
}
#[cfg(feature = "alloc")]
fn into_non_null(self: Box<Self>) -> NonNull<Self::Data> {
let ptr = Box::into_raw(self).cast::<Self::Data>();
unsafe { NonNull::new_unchecked(ptr) }
}
unsafe fn from_raw_parts<'a>(data: *const Self::Data, len: Self::Metadata) -> &'a Self {
unsafe { core::slice::from_raw_parts(data, len) }
}
unsafe fn from_raw_parts_mut<'a>(data: *mut Self::Data, len: Self::Metadata) -> &'a mut Self {
unsafe { core::slice::from_raw_parts_mut(data, len) }
}
#[cfg(feature = "alloc")]
unsafe fn from_non_null(data: NonNull<Self::Data>, len: Self::Metadata) -> Box<Self> {
unsafe { Box::from_raw(core::ptr::slice_from_raw_parts_mut(data.as_ptr(), len)) }
}
}
impl Wide for str {
type Data = u8;
type Metadata = usize;
fn metadata(&self) -> Self::Metadata {
Self::len(self)
}
fn as_ptr(&self) -> *const Self::Data {
self.as_ptr()
}
fn as_mut_ptr(&mut self) -> *mut Self::Data {
self.as_mut_ptr()
}
#[cfg(feature = "alloc")]
fn into_non_null(self: Box<Self>) -> NonNull<Self::Data> {
self.into_boxed_bytes().into_non_null()
}
unsafe fn from_raw_parts<'a>(data: *const Self::Data, len: Self::Metadata) -> &'a Self {
let slice = unsafe { <[u8]>::from_raw_parts(data, len) };
unsafe { core::str::from_utf8_unchecked(slice) }
}
unsafe fn from_raw_parts_mut<'a>(data: *mut Self::Data, len: Self::Metadata) -> &'a mut Self {
let slice = unsafe { <[u8]>::from_raw_parts_mut(data, len) };
unsafe { core::str::from_utf8_unchecked_mut(slice) }
}
#[cfg(feature = "alloc")]
unsafe fn from_non_null(data: NonNull<Self::Data>, len: Self::Metadata) -> Box<Self> {
let slice = unsafe { <[u8]>::from_non_null(data, len) };
let slice = Box::into_raw(slice);
let str = unsafe { core::str::from_utf8_unchecked_mut(&mut *slice) };
unsafe { Box::from_raw(str) }
}
}
#[cfg(test)]
mod tests {
use core::{
cell::{Cell, UnsafeCell},
mem::ManuallyDrop,
};
use static_assertions::{assert_impl_all, assert_not_impl_any};
use super::Wide;
#[test]
fn wide_is_implemented_for_builtin_wide_types() {
assert_impl_all!([u8]: Wide<Data = u8, Metadata = usize>);
assert_impl_all!(str: Wide<Data = u8, Metadata = usize>);
assert_impl_all!(UnsafeCell<[u8]>: Wide<Data = u8, Metadata = usize>);
assert_impl_all!(UnsafeCell<str>: Wide<Data = u8, Metadata = usize>);
assert_impl_all!(Cell<[u8]>: Wide<Data = u8, Metadata = usize>);
assert_impl_all!(Cell<str>: Wide<Data = u8, Metadata = usize>);
assert_impl_all!(ManuallyDrop<[u8]>: Wide<Data = u8, Metadata = usize>);
assert_impl_all!(ManuallyDrop<str>: Wide<Data = u8, Metadata = usize>);
}
#[test]
fn wide_is_not_implemented_for_thin_types() {
assert_not_impl_any!(u8: Wide);
assert_not_impl_any!([u8; 4]: Wide);
assert_not_impl_any!(&[u8]: Wide);
}
}