use std::ffi::CStr;
use std::fmt::Debug;
use std::marker::{PhantomData, PhantomPinned};
use std::mem::MaybeUninit;
use std::pin::Pin;
#[cfg(feature = "alloc")]
use crate::alloc;
use crate::memory::{Storable, Storage};
use executorch_sys as sys;
pub(crate) trait Destroy {
unsafe fn destroy(&mut self);
}
pub(crate) enum NonTriviallyMovable<'a, T: Destroy> {
#[cfg(feature = "alloc")]
Boxed(Pin<alloc::Box<(T, PhantomPinned)>>),
OwnedRef(Pin<&'a mut (T, PhantomPinned)>),
Ref(Pin<&'a (T, PhantomPinned)>),
RefMut(Pin<&'a mut (T, PhantomPinned)>),
}
impl<'a, T: Destroy> NonTriviallyMovable<'a, T> {
#[cfg(feature = "alloc")]
pub(crate) unsafe fn try_new_boxed<E>(
init: impl FnOnce(*mut T) -> Result<(), E>,
) -> Result<Self, E> {
let mut p = alloc::Box::pin(MaybeUninit::<T>::uninit());
init(unsafe { p.as_mut().get_unchecked_mut().as_mut_ptr() })?;
let p = unsafe {
std::mem::transmute::<
Pin<alloc::Box<MaybeUninit<T>>>,
Pin<alloc::Box<(T, PhantomPinned)>>,
>(p)
};
Ok(NonTriviallyMovable::Boxed(p))
}
#[cfg(feature = "alloc")]
pub(crate) unsafe fn new_boxed(init: impl FnOnce(*mut T)) -> Self {
use core::convert::Infallible;
unsafe {
let res = Self::try_new_boxed::<Infallible>(|p| {
init(p);
Ok(())
});
res.unwrap_unchecked()
}
}
pub(crate) unsafe fn new_in_storage<S>(
init: impl FnOnce(*mut T),
storage: Pin<&'a mut Storage<S>>,
) -> Self
where
S: Storable<__Storage = T>,
{
let storage = unsafe { storage.get_unchecked_mut() };
init(storage.as_mut_ptr());
let p = unsafe { &mut *storage.as_mut_ptr() };
let p = unsafe { std::mem::transmute::<&'a mut T, &'a mut (T, PhantomPinned)>(p) };
let p = unsafe { Pin::new_unchecked(p) };
Self::OwnedRef(p)
}
pub(crate) fn from_ref(p: &'a T) -> Self {
let p = unsafe { std::mem::transmute::<&'a T, &'a (T, PhantomPinned)>(p) };
let p = unsafe { Pin::new_unchecked(p) };
Self::Ref(p)
}
pub(crate) fn from_mut_ref(p: &'a mut T) -> Self {
let p = unsafe { std::mem::transmute::<&'a mut T, &'a mut (T, PhantomPinned)>(p) };
let p = unsafe { Pin::new_unchecked(p) };
Self::RefMut(p)
}
}
impl<T: Destroy> Drop for NonTriviallyMovable<'_, T> {
fn drop(&mut self) {
let shoud_destroy = match self {
#[cfg(feature = "alloc")]
NonTriviallyMovable::Boxed(_) => true,
NonTriviallyMovable::OwnedRef(_) => true,
NonTriviallyMovable::Ref(_) | NonTriviallyMovable::RefMut(_) => false,
};
if shoud_destroy {
let p = unsafe { self.as_mut() }.unwrap();
unsafe { p.destroy() };
}
}
}
impl<T: Destroy> AsRef<T> for NonTriviallyMovable<'_, T> {
fn as_ref(&self) -> &T {
match self {
#[cfg(feature = "alloc")]
NonTriviallyMovable::Boxed(p) => &p.0,
NonTriviallyMovable::OwnedRef(p) => &p.0,
NonTriviallyMovable::Ref(p) => &p.0,
NonTriviallyMovable::RefMut(p) => &p.0,
}
}
}
impl<T: Destroy> NonTriviallyMovable<'_, T> {
pub(crate) unsafe fn as_mut(&mut self) -> Option<&mut T> {
match self {
#[cfg(feature = "alloc")]
NonTriviallyMovable::Boxed(p) => Some(&mut unsafe { p.as_mut().get_unchecked_mut() }.0),
NonTriviallyMovable::OwnedRef(p) => {
Some(unsafe { &mut p.as_mut().get_unchecked_mut().0 })
}
NonTriviallyMovable::Ref(_) => None,
NonTriviallyMovable::RefMut(p) => {
Some(unsafe { &mut p.as_mut().get_unchecked_mut().0 })
}
}
}
}
#[cfg(feature = "alloc")]
#[allow(unused)]
pub(crate) struct NonTriviallyMovableVec<T: Destroy>(Pin<alloc::Box<(PhantomPinned, [T])>>);
#[cfg(feature = "alloc")]
#[allow(unused)]
impl<T: Destroy> NonTriviallyMovableVec<T> {
pub(crate) unsafe fn new(len: usize, init: impl Fn(usize, &mut MaybeUninit<T>)) -> Self {
let vec = (0..len)
.map(|_| MaybeUninit::<T>::uninit())
.collect::<alloc::Vec<_>>()
.into_boxed_slice();
let mut vec = unsafe { Pin::new_unchecked(vec) };
for (i, elem) in unsafe { vec.as_mut().get_unchecked_mut().iter_mut().enumerate() } {
init(i, elem);
}
let vec = unsafe {
std::mem::transmute::<
Pin<alloc::Box<[MaybeUninit<T>]>>,
Pin<alloc::Box<(PhantomPinned, [T])>>,
>(vec)
};
NonTriviallyMovableVec(vec)
}
pub(crate) fn as_slice(&self) -> &[T] {
&self.0.1
}
}
#[cfg(feature = "alloc")]
impl<T: Destroy> Drop for NonTriviallyMovableVec<T> {
fn drop(&mut self) {
for elem in unsafe { &mut self.0.as_mut().get_unchecked_mut().1 } {
unsafe { elem.destroy() };
}
}
}
pub(crate) unsafe fn try_c_new<T>(f: impl FnOnce(*mut T) -> sys::ET_Error) -> crate::Result<T> {
let mut value = MaybeUninit::uninit();
let err = f(value.as_mut_ptr());
err.rs().map(|_| unsafe { value.assume_init() })
}
pub(crate) unsafe fn c_new<T>(f: impl FnOnce(*mut T)) -> T {
let res = unsafe {
try_c_new(|ptr| {
f(ptr);
sys::ET_Error::ET_Error_Ok
})
};
unsafe { res.unwrap_unchecked() }
}
pub(crate) trait IntoRust {
type RsType;
fn rs(self) -> Self::RsType;
}
pub(crate) trait IntoCpp {
type CppType;
fn cpp(self) -> Self::CppType;
}
#[allow(unused)]
pub struct ArrayRef<'a, T: ArrayRefElement>(pub(crate) T::__ArrayRefImpl, PhantomData<&'a ()>);
impl<'a, T: ArrayRefElement> ArrayRef<'a, T> {
pub(crate) unsafe fn from_inner(arr: T::__ArrayRefImpl) -> Self {
Self(arr, PhantomData)
}
pub fn from_slice(s: &'a [T]) -> Self {
Self(unsafe { T::__ArrayRefImpl::from_slice(s) }, PhantomData)
}
pub fn as_slice(&self) -> &'a [T]
where
T: 'static,
{
unsafe { self.0.as_slice() }
}
}
impl<'a> ArrayRef<'a, FfiChar> {
pub fn from_cstr(s: &'a CStr) -> Self {
Self::from_chars(crate::util::cstr2chars(s))
}
pub fn from_chars(chars: &'a [std::ffi::c_char]) -> Self {
Self::from_slice(FfiChar::slice_from_ffi(chars))
}
}
impl<T: ArrayRefElement + Debug + 'static> Debug for ArrayRef<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.as_slice().fmt(f)
}
}
impl<'a, T: ArrayRefElement> From<&'a [T]> for ArrayRef<'a, T> {
fn from(slice: &'a [T]) -> Self {
Self::from_slice(slice)
}
}
impl<'a, T: ArrayRefElement + 'static> From<ArrayRef<'a, T>> for &'a [T] {
fn from(arr: ArrayRef<'a, T>) -> Self {
arr.as_slice()
}
}
pub trait ArrayRefElement {
#[doc(hidden)]
type __ArrayRefImpl: __ArrayRefImpl<Element = Self>;
private_decl! {}
}
#[doc(hidden)]
pub trait __ArrayRefImpl {
type Element: ArrayRefElement<__ArrayRefImpl = Self>;
unsafe fn from_slice(slice: &[Self::Element]) -> Self;
unsafe fn as_slice(&self) -> &'static [Self::Element];
private_decl! {}
}
#[repr(transparent)]
pub struct FfiChar(pub std::ffi::c_char);
impl FfiChar {
pub(crate) fn slice_from_ffi(slice: &[std::ffi::c_char]) -> &[FfiChar] {
assert_eq!(
core::alloc::Layout::new::<std::ffi::c_char>(),
core::alloc::Layout::new::<FfiChar>()
);
unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), slice.len()) }
}
pub(crate) fn slice_to_ffi(slice: &[FfiChar]) -> &[std::ffi::c_char] {
assert_eq!(
core::alloc::Layout::new::<std::ffi::c_char>(),
core::alloc::Layout::new::<FfiChar>()
);
unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), slice.len()) }
}
}
impl From<std::ffi::c_char> for FfiChar {
fn from(c: std::ffi::c_char) -> Self {
Self(c)
}
}
impl From<FfiChar> for std::ffi::c_char {
fn from(c: FfiChar) -> Self {
c.0
}
}
macro_rules! impl_array_ref {
($element:path, $array_ref:path) => {
impl ArrayRefElement for $element {
type __ArrayRefImpl = $array_ref;
private_impl! {}
}
impl __ArrayRefImpl for $array_ref {
type Element = $element;
unsafe fn from_slice(slice: &[$element]) -> Self {
Self {
data: slice.as_ptr(),
len: slice.len(),
}
}
unsafe fn as_slice(&self) -> &'static [$element] {
unsafe { std::slice::from_raw_parts(self.data, self.len) }
}
private_impl! {}
}
};
}
impl_array_ref!(u8, sys::ET_ArrayRefU8);
impl_array_ref!(i32, sys::ET_ArrayRefI32);
impl_array_ref!(i64, sys::ET_ArrayRefI64);
impl_array_ref!(f64, sys::ET_ArrayRefF64);
impl_array_ref!(usize, sys::ET_ArrayRefUsizeType);
impl_array_ref!(bool, sys::ET_ArrayRefBool);
impl ArrayRefElement for FfiChar {
type __ArrayRefImpl = sys::ET_ArrayRefChar;
private_impl! {}
}
impl __ArrayRefImpl for sys::ET_ArrayRefChar {
type Element = FfiChar;
unsafe fn from_slice(slice: &[FfiChar]) -> Self {
let slice = FfiChar::slice_to_ffi(slice);
Self {
data: slice.as_ptr(),
len: slice.len(),
}
}
unsafe fn as_slice(&self) -> &'static [FfiChar] {
let slice = unsafe { std::slice::from_raw_parts(self.data, self.len) };
FfiChar::slice_from_ffi(slice)
}
private_impl! {}
}
impl ArrayRefElement for sys::ET_EValueStorage {
type __ArrayRefImpl = sys::ET_ArrayRefEValue;
private_impl! {}
}
impl __ArrayRefImpl for sys::ET_ArrayRefEValue {
type Element = sys::ET_EValueStorage;
unsafe fn from_slice(slice: &[sys::ET_EValueStorage]) -> Self {
Self {
data: sys::ET_EValueRef {
ptr: slice.as_ptr() as *const _,
},
len: slice.len(),
}
}
unsafe fn as_slice(&self) -> &'static [sys::ET_EValueStorage] {
let data = self.data.ptr as *const sys::ET_EValueStorage;
unsafe { std::slice::from_raw_parts(data, self.len) }
}
private_impl! {}
}
#[allow(unused)]
pub struct Span<'a, T: SpanElement>(pub(crate) T::__SpanImpl, PhantomData<&'a T>);
impl<'a, T: SpanElement> Span<'a, T> {
pub fn from_slice(s: &'a mut [T]) -> Self {
Self(unsafe { T::__SpanImpl::from_slice(s) }, PhantomData)
}
pub fn as_slice(&self) -> &'a mut [T]
where
T: 'static,
{
unsafe { self.0.as_slice() }
}
}
impl<T: SpanElement + Debug + 'static> Debug for Span<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.as_slice().fmt(f)
}
}
pub trait SpanElement {
#[doc(hidden)]
type __SpanImpl: __SpanImpl<Element = Self>;
private_decl! {}
}
#[doc(hidden)]
pub trait __SpanImpl {
type Element: SpanElement<__SpanImpl = Self>;
unsafe fn from_slice(slice: &mut [Self::Element]) -> Self;
unsafe fn as_slice(&self) -> &'static mut [Self::Element];
private_decl! {}
}
macro_rules! impl_span {
($element:path, $span:path) => {
impl SpanElement for $element {
type __SpanImpl = $span;
private_impl! {}
}
impl __SpanImpl for $span {
type Element = $element;
unsafe fn from_slice(slice: &mut [$element]) -> Self {
Self {
data: slice.as_mut_ptr(),
len: slice.len(),
}
}
unsafe fn as_slice(&self) -> &'static mut [$element] {
unsafe { std::slice::from_raw_parts_mut(self.data, self.len) }
}
private_impl! {}
}
};
}
impl_span!(u8, sys::ET_SpanU8);
pub(crate) fn cstr2chars(s: &CStr) -> &[std::ffi::c_char] {
unsafe { std::slice::from_raw_parts(s.as_ptr(), s.to_bytes().len()) }
}
pub(crate) fn str2chars(s: &str) -> &[std::ffi::c_char] {
assert_eq!(
core::alloc::Layout::new::<std::ffi::c_char>(),
core::alloc::Layout::new::<u8>()
);
unsafe { std::slice::from_raw_parts(s.as_ptr().cast(), s.len()) }
}
pub(crate) fn chars2str(s: &[std::ffi::c_char]) -> Result<&str, std::str::Utf8Error> {
assert_eq!(
core::alloc::Layout::new::<std::ffi::c_char>(),
core::alloc::Layout::new::<u8>()
);
let bytes = unsafe { std::mem::transmute::<&[std::ffi::c_char], &[u8]>(s) };
std::str::from_utf8(bytes)
}
#[cfg(feature = "std")]
pub(crate) fn chars2cstring(s: &[std::ffi::c_char]) -> Option<std::ffi::CString> {
assert_eq!(
core::alloc::Layout::new::<std::ffi::c_char>(),
core::alloc::Layout::new::<u8>()
);
let s = unsafe { std::mem::transmute::<&[std::ffi::c_char], &[u8]>(s) };
let mut buf = alloc::Vec::with_capacity(s.len() + 1);
buf.extend_from_slice(s);
buf.push(0);
std::ffi::CString::from_vec_with_nul(buf).ok()
}
#[cfg(feature = "std")]
#[allow(unused)]
pub(crate) fn path2cstring(path: &std::path::Path) -> Result<std::ffi::CString, crate::Error> {
let path_bytes = path.as_os_str().as_encoded_bytes();
std::ffi::CString::new(path_bytes).map_err(|_| crate::Error::InvalidString)
}
#[cfg(feature = "std")]
#[allow(unused)]
pub(crate) mod cpp_vec {
use super::IntoRust;
use executorch_sys as sys;
pub(crate) struct CppVec<T: CppVecElement>(T::VecImpl);
impl<T: CppVecElement> CppVec<T> {
pub fn new(vec: T::VecImpl) -> Self {
Self(vec)
}
pub fn as_slice(&self) -> &[T] {
self.0.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
self.0.as_mut_slice()
}
pub fn to_vec(&self) -> Vec<T>
where
T: Clone,
{
self.as_slice().to_vec()
}
}
impl<V: CppVecImpl> IntoRust for V {
type RsType = CppVec<V::Element>;
fn rs(self) -> Self::RsType {
CppVec(self)
}
}
impl<T: CppVecElement> Drop for CppVec<T> {
fn drop(&mut self) {
T::drop_vec(self);
}
}
pub(crate) trait CppVecElement: Sized {
type VecImpl: CppVecImpl<Element = Self>;
fn drop_vec(vec: &mut CppVec<Self>);
}
pub(crate) trait CppVecImpl {
type Element: CppVecElement<VecImpl = Self>;
fn as_slice(&self) -> &[Self::Element];
fn as_mut_slice(&mut self) -> &mut [Self::Element];
}
impl CppVecElement for std::ffi::c_char {
type VecImpl = sys::ET_VecChar;
fn drop_vec(vec: &mut CppVec<Self>) {
unsafe { sys::executorch_VecChar_destructor(&mut vec.0) }
}
}
impl CppVecImpl for sys::ET_VecChar {
type Element = std::ffi::c_char;
fn as_slice(&self) -> &[std::ffi::c_char] {
unsafe { std::slice::from_raw_parts(self.data, self.len) }
}
fn as_mut_slice(&mut self) -> &mut [std::ffi::c_char] {
unsafe { std::slice::from_raw_parts_mut(self.data, self.len) }
}
}
impl CppVecElement for sys::ET_EValueStorage {
type VecImpl = sys::ET_VecEValue;
fn drop_vec(vec: &mut CppVec<Self>) {
unsafe { sys::executorch_VecEValue_destructor(&mut vec.0) }
}
}
impl CppVecImpl for sys::ET_VecEValue {
type Element = sys::ET_EValueStorage;
fn as_slice(&self) -> &[sys::ET_EValueStorage] {
let data = self.data.ptr as *const sys::ET_EValueStorage;
unsafe { std::slice::from_raw_parts(data, self.len) }
}
fn as_mut_slice(&mut self) -> &mut [sys::ET_EValueStorage] {
let data = self.data.ptr as *mut sys::ET_EValueStorage;
unsafe { std::slice::from_raw_parts_mut(data, self.len) }
}
}
impl CppVecElement for sys::ET_VecChar {
type VecImpl = sys::ET_VecVecChar;
fn drop_vec(vec: &mut CppVec<Self>) {
unsafe { sys::executorch_VecVecChar_destructor(&mut vec.0) }
}
}
impl CppVecImpl for sys::ET_VecVecChar {
type Element = sys::ET_VecChar;
fn as_slice(&self) -> &[sys::ET_VecChar] {
unsafe { std::slice::from_raw_parts(self.data, self.len) }
}
fn as_mut_slice(&mut self) -> &mut [sys::ET_VecChar] {
unsafe { std::slice::from_raw_parts_mut(self.data, self.len) }
}
}
}
#[allow(unused)]
#[cfg(feature = "std")]
pub(crate) fn to_bytes<T>(val: &T) -> Vec<u8> {
(0..std::mem::size_of_val(val))
.map(|i| unsafe {
let ptr = val as *const T as *const u8;
*ptr.add(i)
})
.collect()
}