My Rust Analyzer did not handle well the structs being generated as the outcome of a macro, so I decided to not use macros at all.
In my code, I've implemented a helper ctype module which uses a CTypeMeta trait in order to know how to implement the actual ForeignType and ForeignTypeRef.
use std::{
borrow::{Borrow, BorrowMut},
ptr::NonNull,
};
use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
use std::ops::{Deref, DerefMut};
pub trait CTypeMeta {
type CType;
unsafe fn drop_ptr(ptr: *mut Self::CType);
unsafe fn clone_ptr(ptr: *mut Self::CType) -> *mut Self::CType;
}
pub struct CTypeOwned<T: CTypeMeta>(NonNull<T::CType>);
pub struct CTypeRef<T: CTypeMeta>(Opaque, std::marker::PhantomData<T>);
unsafe impl<T: CTypeMeta> ForeignType for CTypeOwned<T> {
type CType = T::CType;
type Ref = CTypeRef<T>;
unsafe fn from_ptr(ptr: *mut Self::CType) -> Self {
Self(NonNull::new_unchecked(ptr))
}
fn as_ptr(&self) -> *mut Self::CType {
self.0.as_ptr()
}
}
unsafe impl<T: CTypeMeta> ForeignTypeRef for CTypeRef<T> {
type CType = T::CType;
}
unsafe impl<T: CTypeMeta> Sync for CTypeRef<T> {}
unsafe impl<T: CTypeMeta> Send for CTypeRef<T> {}
unsafe impl<T: CTypeMeta> Sync for CTypeOwned<T> {}
unsafe impl<T: CTypeMeta> Send for CTypeOwned<T> {}
impl<T: CTypeMeta> Deref for CTypeOwned<T> {
type Target = <Self as ForeignType>::Ref;
fn deref(&self) -> &Self::Target {
unsafe { <Self as ForeignType>::Ref::from_ptr(self.as_ptr()) }
}
}
impl<T: CTypeMeta> DerefMut for CTypeOwned<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { <Self as ForeignType>::Ref::from_ptr_mut(self.as_ptr()) }
}
}
impl<T: CTypeMeta> Drop for CTypeOwned<T> {
fn drop(&mut self) {
unsafe { T::drop_ptr(self.as_ptr()) }
}
}
impl<T: CTypeMeta> ToOwned for CTypeRef<T> {
type Owned = CTypeOwned<T>;
fn to_owned(&self) -> Self::Owned {
unsafe { Self::Owned::from_ptr(T::clone_ptr(self.as_ptr())) }
}
}
impl<T: CTypeMeta> Borrow<CTypeRef<T>> for CTypeOwned<T> {
fn borrow(&self) -> &CTypeRef<T> {
unsafe { CTypeRef::<T>::from_ptr(self.as_ptr()) }
}
}
impl<T: CTypeMeta> BorrowMut<CTypeRef<T>> for CTypeOwned<T> {
fn borrow_mut(&mut self) -> &mut CTypeRef<T> {
unsafe { CTypeRef::<T>::from_ptr_mut(self.as_ptr()) }
}
}
pub struct MyTypeMeta();
impl CTypeMeta for MyTypeMeta {
CType = mtype_t;
unsafe fn drop_ptr(ptr: *mut Self::CType) {
mtype_free(ptr);
}
unsafe fn clone_ptr(ptr: *mut Self::CType) -> *mut Self::CType {
mtype_clone(ptr);
}
}
pub type MyType = CTypeOwned<MyTypeMeta>;
pub type MyTypeRef = CTypeRef<MyTypeMeta>;
impl MyType {
// etc
}
impl MyTypeRef {
// etc
}