use crate::util::vec_into_raw_parts;
use std::ptr::NonNull;
pub(crate) trait PassByValue: Sized {
type RustType;
#[allow(clippy::wrong_self_convention)]
unsafe fn from_ctype(self) -> Self::RustType;
fn as_ctype(arg: Self::RustType) -> Self;
unsafe fn val_from_arg(arg: Self) -> Self::RustType {
unsafe { arg.from_ctype() }
}
unsafe fn take_val_from_arg(arg: *mut Self, mut replacement: Self) -> Self::RustType {
unsafe { std::ptr::swap(arg, &mut replacement) };
unsafe { PassByValue::val_from_arg(replacement) }
}
unsafe fn return_val(arg: Self::RustType) -> Self {
Self::as_ctype(arg)
}
unsafe fn val_to_arg_out(val: Self::RustType, arg_out: *mut Self) {
debug_assert!(!arg_out.is_null());
unsafe { *arg_out = Self::as_ctype(val) };
}
}
pub(crate) trait PassByPointer: Sized {
unsafe fn take_from_ptr_arg(arg: *mut Self) -> Self {
debug_assert!(!arg.is_null());
unsafe { *(Box::from_raw(arg)) }
}
unsafe fn from_ptr_arg_ref<'a>(arg: *const Self) -> &'a Self {
debug_assert!(!arg.is_null());
unsafe { &*arg }
}
unsafe fn from_ptr_arg_ref_mut<'a>(arg: *mut Self) -> &'a mut Self {
debug_assert!(!arg.is_null());
unsafe { &mut *arg }
}
unsafe fn return_ptr(self) -> *mut Self {
Box::into_raw(Box::new(self))
}
unsafe fn ptr_to_arg_out(self, arg_out: *mut *mut Self) {
debug_assert!(!arg_out.is_null());
unsafe { *arg_out = self.return_ptr() };
}
}
pub(crate) trait CList: Sized {
type Element;
unsafe fn from_raw_parts(items: *mut Self::Element, len: usize, cap: usize) -> Self;
fn slice(&mut self) -> &mut [Self::Element];
fn into_raw_parts(self) -> (*mut Self::Element, usize, usize);
fn null_value() -> Self {
unsafe { Self::from_raw_parts(std::ptr::null_mut(), 0, 0) }
}
}
pub(crate) unsafe fn drop_value_list<CL, T>(list: *mut CL)
where
CL: CList<Element = T>,
T: PassByValue,
{
debug_assert!(!list.is_null());
let mut vec = unsafe { CL::take_val_from_arg(list, CL::null_value()) };
for e in vec.drain(..) {
drop(unsafe { PassByValue::val_from_arg(e) });
}
drop(vec);
}
#[allow(dead_code)] pub(crate) unsafe fn drop_pointer_list<CL, T>(list: *mut CL)
where
CL: CList<Element = NonNull<T>>,
T: PassByPointer,
{
debug_assert!(!list.is_null());
let mut vec = unsafe { CL::take_val_from_arg(list, CL::null_value()) };
for e in vec.drain(..) {
drop(unsafe { PassByPointer::take_from_ptr_arg(e.as_ptr()) });
}
drop(vec);
}
pub(crate) unsafe fn drop_optional_pointer_list<CL, T>(list: *mut CL)
where
CL: CList<Element = Option<NonNull<T>>>,
T: PassByPointer,
{
debug_assert!(!list.is_null());
let mut vec = unsafe { CL::take_val_from_arg(list, CL::null_value()) };
for e in vec.drain(..).flatten() {
drop(unsafe { PassByPointer::take_from_ptr_arg(e.as_ptr()) });
}
drop(vec);
}
pub(crate) unsafe fn take_optional_pointer_list_item<CL, T>(
list: *mut CL,
index: usize,
) -> Option<NonNull<T>>
where
CL: CList<Element = Option<NonNull<T>>>,
T: PassByPointer,
{
debug_assert!(!list.is_null());
let slice = unsafe { list.as_mut() }.unwrap().slice();
if let Some(elt_ref) = slice.get_mut(index) {
let mut rv = None;
if let Some(elt) = elt_ref.as_mut() {
rv = Some(*elt);
*elt_ref = None; }
rv
} else {
None }
}
impl<A> PassByValue for A
where
A: CList,
{
type RustType = Vec<A::Element>;
unsafe fn from_ctype(self) -> Self::RustType {
let (items, len, cap) = self.into_raw_parts();
debug_assert!(!items.is_null());
unsafe { Vec::from_raw_parts(items as *mut _, len, cap) }
}
fn as_ctype(arg: Self::RustType) -> Self {
let (items, len, cap) = vec_into_raw_parts(arg);
unsafe { Self::from_raw_parts(items, len, cap) }
}
}