use crate::boxed::CBox;
#[cfg(feature = "layout_checks")]
use abi_stable::{abi_stability::check_layout_compatibility, type_layout::TypeLayout};
use core::mem::ManuallyDrop;
use core::ops::{Deref, DerefMut};
#[cfg(feature = "rust_void")]
#[allow(non_camel_case_types)]
pub type c_void = ();
#[cfg(not(feature = "rust_void"))]
#[allow(non_camel_case_types)]
#[repr(transparent)]
#[derive(Debug)]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
#[cfg_attr(feature = "abi_stable", sabi(unsafe_opaque_fields))]
pub struct c_void(core::ffi::c_void);
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
pub struct CGlueTraitObj<'a, T, V: 'a, C, R> {
vtbl: &'a V,
container: CGlueObjContainer<T, C, R>,
}
#[repr(C)]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
pub struct CGlueObjContainer<T, C, R> {
instance: T,
context: C,
ret_tmp: R,
}
pub unsafe trait Opaquable: Sized {
type OpaqueTarget;
fn into_opaque(self) -> Self::OpaqueTarget {
debug_assert_eq!(
core::mem::size_of::<Self>(),
core::mem::size_of::<Self::OpaqueTarget>()
);
let input = ManuallyDrop::new(self);
unsafe { core::ptr::read(&input as *const _ as *const _) }
}
}
pub trait Opaque: Sized + Opaquable<OpaqueTarget = Self> {}
impl<T: Opaquable<OpaqueTarget = T>> Opaque for T {}
unsafe impl<T: Opaquable, C, R> Opaquable for CGlueObjContainer<T, C, R> {
type OpaqueTarget = CGlueObjContainer<T::OpaqueTarget, C, R>;
}
unsafe impl<'a, T> Opaquable for &'a T {
type OpaqueTarget = &'a c_void;
}
unsafe impl<'a, T> Opaquable for &'a mut T {
type OpaqueTarget = &'a mut c_void;
}
pub type CGlueOpaqueTraitObjOutCBox<'a, V> = CGlueTraitObj<
'a,
CBox<'a, c_void>,
<V as CGlueBaseVtbl>::OpaqueVtbl,
<V as CGlueBaseVtbl>::Context,
<V as CGlueBaseVtbl>::RetTmp,
>;
pub type CGlueOpaqueTraitObjOutRef<'a, V> = CGlueTraitObj<
'a,
&'a c_void,
<V as CGlueBaseVtbl>::OpaqueVtbl,
<V as CGlueBaseVtbl>::Context,
<V as CGlueBaseVtbl>::RetTmp,
>;
pub type CGlueOpaqueTraitObjOutMut<'a, V> = CGlueTraitObj<
'a,
&'a mut c_void,
<V as CGlueBaseVtbl>::OpaqueVtbl,
<V as CGlueBaseVtbl>::Context,
<V as CGlueBaseVtbl>::RetTmp,
>;
pub type CGlueOpaqueTraitObj<'a, T, V> = CGlueTraitObj<
'a,
<T as Opaquable>::OpaqueTarget,
<V as CGlueBaseVtbl>::OpaqueVtbl,
<V as CGlueBaseVtbl>::Context,
<V as CGlueBaseVtbl>::RetTmp,
>;
unsafe impl<'a, T: Opaquable, F: CGlueBaseVtbl<Context = C, RetTmp = R>, C: ContextBounds, R: Default>
Opaquable for CGlueTraitObj<'a, T, F, C, R>
{
type OpaqueTarget = CGlueTraitObj<'a, T::OpaqueTarget, F::OpaqueVtbl, C, R>;
}
pub trait GetVtbl<V> {
fn get_vtbl(&self) -> &V;
}
impl<T, V, C, R> GetVtbl<V> for CGlueTraitObj<'_, T, V, C, R> {
fn get_vtbl(&self) -> &V {
self.vtbl
}
}
impl<T: Deref<Target = F>, F, C: ContextBounds, R: Default> From<(T, C)>
for CGlueObjContainer<T, C, R>
{
fn from((instance, context): (T, C)) -> Self {
Self {
instance,
ret_tmp: Default::default(),
context,
}
}
}
impl<T: Deref<Target = F>, F, R: Default> From<T> for CGlueObjContainer<T, NoContext, R> {
fn from(this: T) -> Self {
Self::from((this, Default::default()))
}
}
impl<'a, T, R: Default> From<T> for CGlueObjContainer<CBox<'a, T>, NoContext, R> {
fn from(this: T) -> Self {
Self::from(CBox::from(this))
}
}
impl<'a, T, C: ContextBounds, R: Default> From<(T, C)> for CGlueObjContainer<CBox<'a, T>, C, R> {
fn from((this, context): (T, C)) -> Self {
Self::from((CBox::from(this), context))
}
}
impl<
'a,
T: Deref<Target = F>,
F,
V: CGlueVtbl<CGlueObjContainer<T, C, R>, Context = C, RetTmp = R>,
C: ContextBounds,
R: Default,
> From<CGlueObjContainer<T, C, R>> for CGlueTraitObj<'a, T, V, V::Context, V::RetTmp>
where
&'a V: Default,
{
fn from(container: CGlueObjContainer<T, C, R>) -> Self {
Self {
container,
vtbl: Default::default(),
}
}
}
impl<
'a,
T: Deref<Target = F>,
F,
V: CGlueVtbl<CGlueObjContainer<T, C, R>, Context = C, RetTmp = R>,
C: ContextBounds,
R: Default,
> CGlueTraitObj<'a, T, V, V::Context, V::RetTmp>
where
&'a V: Default,
{
pub fn from_thingies(d: (T, V::Context)) -> Self {
Self::from(d)
}
}
impl<
'a,
T: Deref<Target = F>,
F,
V: CGlueVtbl<CGlueObjContainer<T, C, R>, Context = C, RetTmp = R>,
C: ContextBounds,
R: Default,
> From<(T, V::Context)> for CGlueTraitObj<'a, T, V, V::Context, V::RetTmp>
where
&'a V: Default,
{
fn from((instance, context): (T, V::Context)) -> Self {
Self::from(CGlueObjContainer::from((instance, context)))
}
}
impl<
'a,
T: Deref<Target = F>,
F,
V: CGlueVtbl<CGlueObjContainer<T, NoContext, R>, Context = NoContext, RetTmp = R>,
R: Default,
> From<T> for CGlueTraitObj<'a, T, V, V::Context, V::RetTmp>
where
&'a V: Default,
{
fn from(this: T) -> Self {
Self::from((this, Default::default()))
}
}
impl<
'a,
T,
V: CGlueVtbl<CGlueObjContainer<CBox<'a, T>, NoContext, R>, Context = NoContext, RetTmp = R>,
R: Default,
> From<T> for CGlueTraitObj<'a, CBox<'a, T>, V, V::Context, V::RetTmp>
where
&'a V: Default,
{
fn from(this: T) -> Self {
Self::from(CBox::from(this))
}
}
impl<
'a,
T,
V: CGlueVtbl<CGlueObjContainer<CBox<'a, T>, C, R>, Context = C, RetTmp = R>,
C: ContextBounds,
R: Default,
> From<(T, V::Context)> for CGlueTraitObj<'a, CBox<'a, T>, V, V::Context, V::RetTmp>
where
&'a V: Default,
{
fn from((this, context): (T, V::Context)) -> Self {
Self::from((CBox::from(this), context))
}
}
#[cfg(feature = "layout_checks")]
pub trait ContextBounds: 'static + Clone + Send + Sync + abi_stable::StableAbi {}
#[cfg(feature = "layout_checks")]
impl<T: 'static + Clone + Send + Sync + abi_stable::StableAbi> ContextBounds for T {}
#[cfg(not(feature = "layout_checks"))]
pub trait ContextBounds: 'static + Clone + Send + Sync {}
#[cfg(not(feature = "layout_checks"))]
impl<T: 'static + Clone + Send + Sync> ContextBounds for T {}
#[cfg(feature = "layout_checks")]
pub trait GenericTypeBounds: abi_stable::StableAbi {}
#[cfg(feature = "layout_checks")]
impl<T: abi_stable::StableAbi> GenericTypeBounds for T {}
#[cfg(not(feature = "layout_checks"))]
pub trait GenericTypeBounds {}
#[cfg(not(feature = "layout_checks"))]
impl<T> GenericTypeBounds for T {}
pub trait CGlueObjBase {
type ObjType;
type InstType: ::core::ops::Deref<Target = Self::ObjType>;
type Context: ContextBounds;
fn cobj_base_ref(&self) -> (&Self::ObjType, &Self::Context);
fn cobj_base_owned(self) -> (Self::InstType, Self::Context);
}
pub trait CGlueObjRef<R>: CGlueObjBase {
fn cobj_ref(&self) -> (&Self::ObjType, &R, &Self::Context);
}
impl<T: Deref<Target = F>, F, C: ContextBounds, R> CGlueObjBase for CGlueObjContainer<T, C, R> {
type ObjType = F;
type InstType = T;
type Context = C;
fn cobj_base_ref(&self) -> (&F, &Self::Context) {
(self.instance.deref(), &self.context)
}
fn cobj_base_owned(self) -> (T, Self::Context) {
(self.instance, self.context)
}
}
impl<T: Deref<Target = F>, F, C: ContextBounds, R> CGlueObjRef<R> for CGlueObjContainer<T, C, R> {
fn cobj_ref(&self) -> (&F, &R, &Self::Context) {
(self.instance.deref(), &self.ret_tmp, &self.context)
}
}
pub trait CGlueObjMut<R>: CGlueObjRef<R> {
fn cobj_mut(&mut self) -> (&mut Self::ObjType, &mut R, &Self::Context);
}
impl<T: Deref<Target = F> + DerefMut, F, C: ContextBounds, R> CGlueObjMut<R>
for CGlueObjContainer<T, C, R>
{
fn cobj_mut(&mut self) -> (&mut F, &mut R, &Self::Context) {
(self.instance.deref_mut(), &mut self.ret_tmp, &self.context)
}
}
pub trait GetContainer {
type ContType: CGlueObjBase;
fn ccont_ref(&self) -> &Self::ContType;
fn ccont_mut(&mut self) -> &mut Self::ContType;
fn into_ccont(self) -> Self::ContType;
fn build_with_ccont(&self, container: Self::ContType) -> Self;
}
impl<T: Deref<Target = F>, F, V, C: ContextBounds, R> GetContainer
for CGlueTraitObj<'_, T, V, C, R>
{
type ContType = CGlueObjContainer<T, C, R>;
fn ccont_ref(&self) -> &Self::ContType {
&self.container
}
fn ccont_mut(&mut self) -> &mut Self::ContType {
&mut self.container
}
fn into_ccont(self) -> Self::ContType {
self.container
}
fn build_with_ccont(&self, container: Self::ContType) -> Self {
Self {
container,
vtbl: self.vtbl,
}
}
}
pub trait IntoInner {
type InnerTarget;
unsafe fn into_inner(self) -> Self::InnerTarget;
}
pub trait CGlueVtbl<T>: CGlueBaseVtbl {}
pub trait CGlueVtblCont: Sized {
type ContType: CGlueObjBase;
}
pub unsafe trait CGlueBaseVtbl: Sized {
type OpaqueVtbl: OpaqueVtblBounds;
type Context: ContextBounds;
type RetTmp: Sized + Default;
fn as_opaque(&self) -> &Self::OpaqueVtbl {
unsafe { &*(self as *const Self as *const Self::OpaqueVtbl) }
}
}
#[cfg(not(feature = "layout_checks"))]
pub trait OpaqueVtblBounds: Sized + CGlueVtblCont {}
#[cfg(not(feature = "layout_checks"))]
impl<T: CGlueVtblCont> OpaqueVtblBounds for T {}
#[cfg(feature = "layout_checks")]
pub trait OpaqueVtblBounds: Sized + CGlueVtblCont + abi_stable::StableAbi {}
#[cfg(feature = "layout_checks")]
impl<T: CGlueVtblCont + abi_stable::StableAbi> OpaqueVtblBounds for T {}
pub type NoContext = std::marker::PhantomData<c_void>;
unsafe impl<T: Opaquable> Opaquable for std::marker::PhantomData<T> {
type OpaqueTarget = std::marker::PhantomData<T::OpaqueTarget>;
}
#[cfg(not(feature = "rust_void"))]
unsafe impl Opaquable for () {
type OpaqueTarget = ();
}
unsafe impl Opaquable for c_void {
type OpaqueTarget = c_void;
}
#[repr(u8)]
#[cfg(feature = "layout_checks")]
#[derive(Debug, Eq, PartialEq)]
pub enum VerifyLayout {
Valid,
Invalid,
Unknown,
}
#[cfg(feature = "layout_checks")]
#[no_mangle]
pub extern "C" fn compare_layouts(
expected: Option<&'static TypeLayout>,
found: Option<&'static TypeLayout>,
) -> VerifyLayout {
if let (Some(expected), Some(found)) = (expected, found) {
match check_layout_compatibility(expected, found).into_result() {
Ok(_) => VerifyLayout::Valid,
#[cfg(feature = "log")]
Err(e) => {
log::trace!("{}", e);
VerifyLayout::Invalid
}
#[cfg(not(feature = "log"))]
Err(_) => VerifyLayout::Invalid,
}
} else {
VerifyLayout::Unknown
}
}
#[cfg(feature = "layout_checks")]
impl VerifyLayout {
pub fn check<T: abi_stable::StableAbi>(
layout: Option<&'static abi_stable::type_layout::TypeLayout>,
) -> Self {
compare_layouts(Some(T::LAYOUT), layout)
}
pub fn is_valid_strict(&self) -> bool {
matches!(self, VerifyLayout::Valid)
}
pub fn is_valid_relaxed(&self) -> bool {
matches!(self, VerifyLayout::Valid | VerifyLayout::Unknown)
}
pub fn and(self, other: VerifyLayout) -> Self {
match self {
VerifyLayout::Valid => other,
VerifyLayout::Invalid => self,
_ => match other {
VerifyLayout::Valid => self,
_ => other,
},
}
}
}