use std::fmt;
use std::fmt::Debug;
use std::mem::{self, MaybeUninit};
use std::ptr;
pub trait FreeForeign {
type Foreign;
unsafe fn free_foreign(p: *mut Self::Foreign);
}
pub trait CloneToForeign: FreeForeign {
fn clone_to_foreign(&self) -> OwnedPointer<Self>;
#[must_use]
fn clone_to_foreign_ptr(&self) -> *mut Self::Foreign {
self.clone_to_foreign().into_inner()
}
}
pub unsafe trait FixedAlloc: CloneToForeign + FromForeign + FreeForeign + Sized {
unsafe fn clone_into_foreign(dest: *mut Self::Foreign, src: &Self);
unsafe fn clone_array_from_foreign<const N: usize>(mut src: *const Self::Foreign) -> [Self; N] {
unsafe {
let mut uninit = MaybeUninit::<[Self; N]>::uninit();
let mut dest = uninit.as_mut_ptr().cast::<Self>();
for _ in 0..N {
ptr::write(dest, Self::cloned_from_foreign(src));
dest = dest.offset(1);
src = src.offset(1);
}
uninit.assume_init()
}
}
unsafe fn clone_from_native_slice(mut dest: *mut Self::Foreign, src: &[Self]) {
unsafe {
for item in src {
Self::clone_into_foreign(dest, item);
dest = dest.offset(1);
}
}
}
}
pub trait IntoNative<U> {
unsafe fn into_native(self) -> U;
}
impl<T, U> IntoNative<U> for *mut T
where
U: FromForeign<Foreign = T>,
{
unsafe fn into_native(self) -> U {
U::from_foreign(self)
}
}
pub trait FromForeign: FreeForeign + Sized {
unsafe fn cloned_from_foreign(p: *const Self::Foreign) -> Self;
unsafe fn from_foreign(p: *mut Self::Foreign) -> Self {
let result = Self::cloned_from_foreign(p);
Self::free_foreign(p);
result
}
}
pub struct OwnedPointer<T: FreeForeign + ?Sized> {
ptr: *mut <T as FreeForeign>::Foreign,
}
impl<T: FreeForeign + ?Sized> OwnedPointer<T> {
pub fn null_mut() -> Self {
OwnedPointer {
ptr: ptr::null_mut(),
}
}
pub unsafe fn new(ptr: *mut <T as FreeForeign>::Foreign) -> Self {
OwnedPointer { ptr }
}
pub fn from<U>(x: OwnedPointer<U>) -> Self
where
U: FreeForeign<Foreign = <T as FreeForeign>::Foreign> + ?Sized,
{
unsafe {
OwnedPointer::new(x.into_inner())
}
}
pub fn into<U>(self) -> OwnedPointer<U>
where
U: FreeForeign<Foreign = <T as FreeForeign>::Foreign>,
{
OwnedPointer::from(self)
}
pub fn as_ptr(&self) -> *const <T as FreeForeign>::Foreign {
self.ptr
}
pub fn as_mut_ptr(&self) -> *mut <T as FreeForeign>::Foreign {
self.ptr
}
#[must_use]
pub fn into_inner(mut self) -> *mut <T as FreeForeign>::Foreign {
let result = mem::replace(&mut self.ptr, ptr::null_mut());
mem::forget(self);
result
}
}
impl<T: FromForeign> OwnedPointer<T> {
pub fn into_native(self) -> T {
unsafe { T::from_foreign(self.into_inner()) }
}
}
impl<T: FreeForeign + ?Sized> Debug for OwnedPointer<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = std::any::type_name::<T>();
let name = format!("OwnedPointer<{name}>");
f.debug_tuple(&name).field(&self.as_ptr()).finish()
}
}
impl<T: CloneToForeign + Default> Default for OwnedPointer<T> {
fn default() -> Self {
<T as Default>::default().clone_to_foreign()
}
}
impl<T: FreeForeign + ?Sized> Drop for OwnedPointer<T> {
fn drop(&mut self) {
let p = mem::replace(&mut self.ptr, ptr::null_mut());
unsafe { T::free_foreign(p) }
}
}
pub struct BorrowedPointer<P: FreeForeign + ?Sized, T> {
ptr: *const <P as FreeForeign>::Foreign,
storage: T,
}
impl<P: FreeForeign + ?Sized, T> BorrowedPointer<P, T> {
pub unsafe fn new(ptr: *const <P as FreeForeign>::Foreign, storage: T) -> Self {
BorrowedPointer { ptr, storage }
}
pub fn as_ptr(&self) -> *const <P as FreeForeign>::Foreign {
self.ptr
}
pub(crate) fn into<Q>(self) -> BorrowedPointer<Q, T>
where
Q: FreeForeign<Foreign = <P as FreeForeign>::Foreign>,
{
BorrowedPointer {
ptr: self.ptr,
storage: self.storage,
}
}
pub(crate) fn map<Q: FreeForeign<Foreign = P::Foreign>, F: FnOnce(T) -> U, U>(
self,
f: F,
) -> BorrowedPointer<Q, U> {
BorrowedPointer {
ptr: self.ptr,
storage: f(self.storage),
}
}
}
impl<T: CloneToForeign + ?Sized> BorrowedPointer<T, &T> {
pub fn to_owned(&self) -> OwnedPointer<T> {
self.storage.clone_to_foreign()
}
}
impl<P: FreeForeign + ?Sized, T> Debug for BorrowedPointer<P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let ptr_name = std::any::type_name::<*mut <P as FreeForeign>::Foreign>();
let storage_name = std::any::type_name::<T>();
let name = format!("BorrowedPointer<{ptr_name}, {storage_name}>");
f.debug_tuple(&name).field(&self.as_ptr()).finish()
}
}
pub trait BorrowForeign<'a>: FreeForeign {
type Storage: 'a;
fn borrow_foreign(&'a self) -> BorrowedPointer<Self, Self::Storage>;
}
pub trait IntoForeign: FreeForeign {
type Storage: 'static;
fn into_foreign(self) -> BorrowedMutPointer<Self, Self::Storage>;
}
pub struct BorrowedMutPointer<P: FreeForeign + ?Sized, T> {
ptr: *mut <P as FreeForeign>::Foreign,
storage: T,
}
impl<P: FreeForeign + ?Sized, T> BorrowedMutPointer<P, T> {
pub unsafe fn new(ptr: *mut <P as FreeForeign>::Foreign, storage: T) -> Self {
BorrowedMutPointer { ptr, storage }
}
pub fn as_ptr(&self) -> *const <P as FreeForeign>::Foreign {
self.ptr
}
pub fn as_mut_ptr(&mut self) -> *mut <P as FreeForeign>::Foreign {
self.ptr
}
pub(crate) fn into<Q>(self) -> BorrowedMutPointer<Q, T>
where
Q: FreeForeign<Foreign = <P as FreeForeign>::Foreign>,
{
BorrowedMutPointer {
ptr: self.ptr,
storage: self.storage,
}
}
pub(crate) fn map<Q: FreeForeign<Foreign = P::Foreign>, U, F: FnOnce(T) -> U>(
self,
f: F,
) -> BorrowedMutPointer<Q, U> {
BorrowedMutPointer {
ptr: self.ptr,
storage: f(self.storage),
}
}
}
impl<P: FreeForeign + ?Sized, T> Debug for BorrowedMutPointer<P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = std::any::type_name::<*mut <P as FreeForeign>::Foreign>();
let name = format!("BorrowedMutPointer<{name}>");
f.debug_tuple(&name).field(&self.as_ptr()).finish()
}
}
pub trait BorrowForeignMut<'a>: FreeForeign {
type Storage: 'a;
fn borrow_foreign_mut(&'a mut self) -> BorrowedMutPointer<Self, Self::Storage>;
}