waterui_ffi/
array.rs

1use core::{
2    ops::{Deref, DerefMut},
3    ptr::{NonNull, slice_from_raw_parts, slice_from_raw_parts_mut},
4};
5
6use alloc::{boxed::Box, vec::Vec};
7
8use super::{IntoFFI, IntoRust};
9
10/// A type alias representing binary data as a byte array.
11pub type WuiData = WuiArray<u8>;
12
13/// A generic array structure for FFI, representing a contiguous sequence of elements.
14/// `WuiArray` can represent multiple types of arrays, for instance, a `&[T]` (in this case, the lifetime of WuiArray is bound to the caller's scope),
15/// or a value type having a static lifetime like `Vec<T>`, `Box<[T]>`, `Bytes`, or even a foreign allocated array.
16/// For a value type, `WuiArray` contains a destructor function pointer to free the array buffer, whatever it is allocated by Rust side or foreign side.
17/// We assume `T` does not contain any non-trivial drop logic, and `WuiArray` will not call `drop` on each element when it is dropped.
18#[repr(C)]
19pub struct WuiArray<T: 'static> {
20    // Store the original boxed data for proper dropping
21    data: NonNull<()>,
22    vtable: WuiArrayVTable<T>,
23}
24
25#[repr(C)]
26pub struct WuiArrayVTable<T> {
27    drop: unsafe extern "C" fn(*mut ()),
28    slice: unsafe extern "C" fn(*const ()) -> WuiArraySlice<T>,
29}
30
31#[repr(C)]
32pub struct WuiArraySlice<T> {
33    head: *mut T,
34    len: usize,
35}
36
37impl<T> WuiArrayVTable<T> {
38    pub const fn from_raw(
39        drop: unsafe extern "C" fn(*mut ()),
40        slice: unsafe extern "C" fn(*const ()) -> WuiArraySlice<T>,
41    ) -> Self {
42        Self { drop, slice }
43    }
44
45    pub const fn new<U>() -> Self
46    where
47        U: AsRef<[T]> + 'static,
48    {
49        unsafe extern "C" fn drop<U2>(data: *mut ()) {
50            unsafe {
51                let _: Box<U2> = Box::from_raw(data as *mut U2);
52            }
53        }
54
55        unsafe extern "C" fn slice<U2, T2>(data: *const ()) -> WuiArraySlice<T2>
56        where
57            U2: AsRef<[T2]>,
58        {
59            unsafe {
60                let slice = &*data.cast::<U2>();
61                let s = slice.as_ref();
62                let len = s.len();
63                let head = s.as_ptr() as *mut T2;
64                WuiArraySlice { head, len }
65            }
66        }
67
68        Self {
69            drop: drop::<U>,
70            slice: slice::<U, T>,
71        }
72    }
73}
74
75impl<T> WuiArray<T> {
76    /// Creates a new `WuiArray` from a raw pointer and length.
77    ///
78    /// # Safety
79    ///
80    /// The caller must ensure that the pointer is valid and points to an array of the specified length.
81    /// The memory must remain valid for the lifetime of the `WuiArray`.
82    pub const unsafe fn from_raw(data: *mut (), vtable: WuiArrayVTable<T>) -> Self {
83        Self {
84            data: unsafe { NonNull::new_unchecked(data) },
85            vtable,
86        }
87    }
88
89    pub fn new<U>(array: U) -> Self
90    where
91        U: AsRef<[T]> + 'static,
92    {
93        let boxed = Box::new(array);
94        let data = Box::into_raw(boxed) as *mut ();
95        let vtable = WuiArrayVTable::new::<U>();
96        unsafe { Self::from_raw(data, vtable) }
97    }
98
99    pub fn len(&self) -> usize {
100        self.as_slice().len()
101    }
102
103    pub fn is_empty(&self) -> bool {
104        self.len() == 0
105    }
106
107    pub fn as_slice(&self) -> &[T] {
108        unsafe {
109            let slice = (self.vtable.slice)(self.data.as_ptr());
110            &*slice_from_raw_parts(slice.head, slice.len)
111        }
112    }
113
114    pub fn as_mut_slice(&mut self) -> &mut [T] {
115        unsafe {
116            let slice = (self.vtable.slice)(self.data.as_ptr());
117            &mut *slice_from_raw_parts_mut(slice.head, slice.len)
118        }
119    }
120}
121
122impl<T: IntoRust + Default> IntoIterator for WuiArray<T> {
123    type Item = T::Rust;
124    type IntoIter = alloc::vec::IntoIter<T::Rust>;
125    fn into_iter(self) -> Self::IntoIter {
126        unsafe { self.into_rust().into_iter() }
127    }
128}
129
130impl<T> Deref for WuiArray<T> {
131    type Target = [T];
132    fn deref(&self) -> &Self::Target {
133        self.as_slice()
134    }
135}
136
137impl<T> DerefMut for WuiArray<T> {
138    fn deref_mut(&mut self) -> &mut Self::Target {
139        self.as_mut_slice()
140    }
141}
142
143impl<T> AsRef<[T]> for WuiArray<T> {
144    fn as_ref(&self) -> &[T] {
145        self
146    }
147}
148
149impl<T: IntoFFI> IntoFFI for Vec<T>
150where
151    <T as IntoFFI>::FFI: 'static,
152{
153    type FFI = WuiArray<T::FFI>;
154
155    fn into_ffi(self) -> Self::FFI {
156        WuiArray::new(
157            self.into_iter()
158                .map(|item| item.into_ffi())
159                .collect::<Vec<_>>(),
160        )
161    }
162}
163
164impl<T: Default + IntoRust> IntoRust for WuiArray<T> {
165    type Rust = Vec<T::Rust>;
166    unsafe fn into_rust(mut self) -> Self::Rust {
167        self.deref_mut()
168            .iter_mut()
169            .map(|item| unsafe { core::mem::take(item).into_rust() })
170            .collect::<Vec<_>>()
171    }
172}