use core::{
ops::{Deref, DerefMut},
ptr::{NonNull, slice_from_raw_parts, slice_from_raw_parts_mut},
};
use alloc::{boxed::Box, vec::Vec};
use crate::{IntoFFI, IntoRust};
pub type WuiData = WuiArray<u8>;
#[repr(C)]
#[derive(Debug)]
pub struct WuiArray<T: 'static> {
data: NonNull<()>,
vtable: WuiArrayVTable<T>,
}
#[repr(C)]
#[derive(Debug)]
pub struct WuiArrayVTable<T> {
drop: unsafe extern "C" fn(*mut ()),
slice: unsafe extern "C" fn(*const ()) -> WuiArraySlice<T>,
}
#[repr(C)]
#[derive(Debug)]
pub struct WuiArraySlice<T> {
head: *mut T,
len: usize,
}
impl<T> Default for WuiArray<T> {
fn default() -> Self {
Self::new(Vec::<T>::new())
}
}
impl<T> WuiArrayVTable<T> {
pub const fn from_raw(
drop: unsafe extern "C" fn(*mut ()),
slice: unsafe extern "C" fn(*const ()) -> WuiArraySlice<T>,
) -> Self {
Self { drop, slice }
}
#[must_use]
pub const fn new<U>() -> Self
where
U: AsRef<[T]> + 'static,
{
unsafe extern "C" fn drop<U2>(data: *mut ()) {
unsafe {
let _: Box<U2> = Box::from_raw(data.cast::<U2>());
}
}
unsafe extern "C" fn slice<U2, T2>(data: *const ()) -> WuiArraySlice<T2>
where
U2: AsRef<[T2]>,
{
unsafe {
let slice = &*data.cast::<U2>();
let s = slice.as_ref();
let len = s.len();
let head = s.as_ptr().cast_mut();
WuiArraySlice { head, len }
}
}
Self {
drop: drop::<U>,
slice: slice::<U, T>,
}
}
}
impl<T> WuiArray<T> {
pub const unsafe fn from_raw(data: *mut (), vtable: WuiArrayVTable<T>) -> Self {
Self {
data: unsafe { NonNull::new_unchecked(data) },
vtable,
}
}
pub fn new<U>(array: U) -> Self
where
U: AsRef<[T]> + 'static,
{
let boxed = Box::new(array);
let data = Box::into_raw(boxed).cast::<()>();
let vtable = WuiArrayVTable::new::<U>();
unsafe { Self::from_raw(data, vtable) }
}
#[must_use]
pub fn len(&self) -> usize {
self.as_slice().len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn as_slice(&self) -> &[T] {
unsafe {
let slice = (self.vtable.slice)(self.data.as_ptr());
&*slice_from_raw_parts(slice.head, slice.len)
}
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe {
let slice = (self.vtable.slice)(self.data.as_ptr());
&mut *slice_from_raw_parts_mut(slice.head, slice.len)
}
}
}
impl<T: IntoRust + Default> IntoIterator for WuiArray<T> {
type Item = T::Rust;
type IntoIter = alloc::vec::IntoIter<T::Rust>;
fn into_iter(self) -> Self::IntoIter {
unsafe { self.into_rust().into_iter() }
}
}
impl<T> Deref for WuiArray<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T> DerefMut for WuiArray<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}
impl<T> WuiArray<T> {
pub fn consume(self) {
unsafe {
(self.vtable.drop)(self.data.as_ptr());
}
}
}
impl<T> AsRef<[T]> for WuiArray<T> {
fn as_ref(&self) -> &[T] {
self
}
}
impl<T: IntoFFI> IntoFFI for Vec<T>
where
<T as IntoFFI>::FFI: 'static,
{
type FFI = WuiArray<T::FFI>;
fn into_ffi(self) -> Self::FFI {
WuiArray::new(
self.into_iter()
.map(super::super::IntoFFI::into_ffi)
.collect::<Vec<_>>(),
)
}
}
impl<T: Default + IntoRust> IntoRust for WuiArray<T> {
type Rust = Vec<T::Rust>;
unsafe fn into_rust(mut self) -> Self::Rust {
let values = self
.deref_mut()
.iter_mut()
.map(|item| unsafe { core::mem::take(item).into_rust() })
.collect::<Vec<_>>();
self.consume();
values
}
}