#[rustfmt::skip]
pub use
::safer_ffi::{
dyn_traits::DynDrop,
layout::ReprC,
prelude::{char_p, Out},
}
;
#[diagnostic::on_unimplemented(
note = "\
This is a marker trait used to distinguish normal, well-defined, non-FFI-opaque types, from \
the latter, the `extern \"C\" {{ type`s.\n\nIf you are sure this is the case for this \
pointee type, then you can simply silence this error by manually writing the \
appropriate:\n\n impl NonOpaque for Foo {{}}\n",
label = "Missing `impl NonOpaque for … {{}}`"
)]
pub trait NonOpaque: Sized {}
pub mod c_slice {
use super::*;
guarded_type_alias! {
pub
type Box<T> where { T : NonOpaque } = ::safer_ffi::prelude::c_slice::Box<T>;
}
guarded_type_alias! {
pub
type Ref<'lt, T> where { T : 'lt + NonOpaque } = ::safer_ffi::prelude::c_slice::Ref<'lt, T>;
}
}
impl NonOpaque for char_p::Box {}
impl NonOpaque for char_p::Ref<'_> {}
impl<T: NonOpaque> NonOpaque for ::safer_ffi::prelude::c_slice::Box<T> {}
impl<T: NonOpaque> NonOpaque for ::safer_ffi::prelude::c_slice::Ref<'_, T> {}
impl NonOpaque for i64 {}
impl NonOpaque for u64 {}
impl NonOpaque for usize {}
impl NonOpaque for u8 {}
impl NonOpaque for bool {}
impl<T> NonOpaque for repr_c::Box<T> where T: FfiDropBox {}
impl<T> NonOpaque for repr_c::Arc<T> where T: FfiDropArc {}
pub trait HasNiche {}
impl<T: HasNiche> NonOpaque for Option<T> {}
impl HasNiche for char_p::Box {}
impl HasNiche for char_p::Ref<'_> {}
impl<T: NonOpaque> HasNiche for ::safer_ffi::prelude::c_slice::Box<T> {}
impl<T: NonOpaque> HasNiche for ::safer_ffi::prelude::c_slice::Ref<'_, T> {}
#[diagnostic::on_unimplemented(
message = "Pointee type may be opaque",
note = "\
If the pointee is some concrete type, rather than one defined by the FFI and opaque, then \
consider `impl`ementing `NonOpaque` for it.\n\nOtherwise, you will need to involve a \
companion `#[drop(…)] fn` declaration in the `unsafe extern \"C\" {{}}` block."
)]
pub trait FfiDropBox: Sized + ReprC {
unsafe fn drop_boxed(it: &mut repr_c::Box<Self>);
}
impl<T: NonOpaque + ReprC> FfiDropBox for T {
unsafe fn drop_boxed(it: &mut repr_c::Box<T>) {
unsafe {
drop(::std::boxed::Box::from_raw(it.0.ptr.as_mut_ptr()));
}
}
}
#[diagnostic::on_unimplemented(
message = "Pointee type may be opaque",
note = "\
If the pointee is some concrete type, rather than one defined by the FFI and opaque, then \
consider `impl`ementing `NonOpaque` for it.\n\nOtherwise, you will need to involve a \
companion `#[drop(…)] fn` declaration in the `unsafe extern \"C\" {{}}` block."
)]
pub trait FfiDropArc: Sized + ReprC {
unsafe fn drop_arced(it: &mut repr_c::Arc<Self>);
}
impl<T: NonOpaque + ReprC> FfiDropArc for T {
unsafe fn drop_arced(it: &mut repr_c::Arc<T>) {
unsafe {
drop(::std::sync::Arc::from_raw(it.0.ptr.as_mut_ptr()));
}
}
}
pub mod repr_c {
use ::safer_ffi::layout::ReprC;
pub use ::safer_ffi::prelude::repr_c::*;
use super::*;
guarded_type_alias! {
pub
type Vec<T> where { T : NonOpaque } = ::safer_ffi::prelude::repr_c::Vec<T>;
}
#[::safer_ffi::derive_ReprC]
#[repr(transparent)]
pub struct ThinBox<T>
where
T: FfiDropBox,
{
pub(super) ptr: ::safer_ffi::ptr::NonNullOwned<T>,
}
impl<T> Drop for ThinBox<T>
where
T: FfiDropBox,
{
fn drop(&mut self) {
unsafe {
T::drop_boxed(::core::mem::transmute(self));
}
}
}
unsafe impl<T> Send for ThinBox<T>
where
T: FfiDropBox,
::std::boxed::Box<T>: Send,
{
}
unsafe impl<T> Sync for ThinBox<T>
where
T: FfiDropBox,
::std::boxed::Box<T>: Sync,
{
}
pub use self::Box as Box_;
#[::safer_ffi::derive_ReprC]
#[repr(transparent)]
pub struct Box<T: ?Sized + PointeeFitForCBox>(pub(super) <T as PointeeFitForCBox>::CBoxed);
#[diagnostic::on_unimplemented(
message = "`repr_c::Box<dyn …>` requires `FnMut` rather than `Fn`, alongside `Send` only \
(no `Sync`)",
label = "double-check that this be using `FnMut` rather than `Fn`, alongside `Send` only \
(no `Sync`)"
)]
pub trait PointeeFitForCBox<Diagnostics = ()> {
type CBoxed: ReprC;
}
impl<T: Sized + NonOpaque + ReprC> PointeeFitForCBox for [T] {
type CBoxed = c_slice::Box<T>;
}
impl<T: Sized + FfiDropBox> PointeeFitForCBox for T {
type CBoxed = ThinBox<T>;
}
closure_impls! {
dyn Send + FnMut() -> R,
dyn Send + FnMut(A) -> R,
dyn Send + FnMut(A, B) -> R,
dyn Send + FnMut(A, B, C) -> R,
dyn Send + FnMut(A, B, C, D) -> R,
}
#[rustfmt::skip]
macro_rules! closure_impls {(
$(
dyn Send + FnMut($($Arg:ident),*) -> $R:ident,
)*
) => (
$(
impl<
$R : ReprC $(, $Arg : ReprC)*
>
PointeeFitForCBox
for
dyn 'static + Send + FnMut($($Arg),*) -> $R
{
type CBoxed = ::safer_ffi::prelude::repr_c::Box<
dyn 'static + Send + FnMut($($Arg),*) -> $R,
>;
}
impl<
T,
$R : ReprC $(, $Arg : ReprC)*
>
From<::std::boxed::Box<T>>
for
Box<dyn 'static + Send + FnMut($($Arg),*) -> $R>
where
T : 'static + Send + FnMut($($Arg),*) -> $R,
{
fn from(f: ::std::boxed::Box<T>) -> Self {
Self(f.into())
}
}
impl<$R : ReprC $(, $Arg : ReprC)*>
Box<dyn 'static + Send + FnMut($($Arg),*) -> $R>
{
#[allow(nonstandard_style)]
pub fn call(&mut self $(, $Arg: $Arg)*) -> $R {
self.0.call($($Arg),*)
}
}
repr_c_ptr_dyn_diagnostics::improve_lack_of_PointeeFitForCBox_impl_diagnostics! {
dyn Send? + Sync? + Fn?($($Arg),*) -> $R,
}
)*
)}
use closure_impls;
impl<T> ::core::ops::Deref for Box<T>
where
T: FfiDropBox,
{
type Target = T;
fn deref(self: &'_ Self) -> &'_ T {
unsafe { self.0.ptr.as_ref() }
}
}
impl<T> ::core::ops::DerefMut for Box<T>
where
T: FfiDropBox,
{
fn deref_mut(self: &'_ mut Self) -> &'_ mut T {
unsafe { self.0.ptr.as_mut() }
}
}
impl<T> ::core::ops::Deref for Box<[T]>
where
T: NonOpaque + ReprC,
{
type Target = [T];
fn deref(self: &'_ Self) -> &'_ [T] {
&self.0[..]
}
}
impl<T> ::core::ops::DerefMut for Box<[T]>
where
T: NonOpaque + ReprC,
{
fn deref_mut(self: &'_ mut Self) -> &'_ mut [T] {
&mut self.0[..]
}
}
impl<T: ::std::fmt::Debug> ::std::fmt::Debug for Box<T>
where
T: FfiDropBox,
{
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
T::fmt(self, f)
}
}
#[::safer_ffi::derive_ReprC]
#[repr(transparent)]
pub struct ThinArc<T>
where
T: FfiDropArc,
{
pub(super) ptr: ::safer_ffi::ptr::NonNullOwned<T>,
}
impl<T> Drop for ThinArc<T>
where
T: FfiDropArc,
{
fn drop(&mut self) {
unsafe {
T::drop_arced(::core::mem::transmute(self));
}
}
}
impl<T> Clone for ThinArc<T>
where
T: FfiDropArc,
{
fn clone(&self) -> Self {
unsafe {
::std::sync::Arc::increment_strong_count(self.ptr.as_ptr());
}
Self {
ptr: ::safer_ffi::ptr::NonNullOwned::from(self.ptr.0),
}
}
}
unsafe impl<T> Send for ThinArc<T>
where
T: FfiDropArc,
::std::sync::Arc<T>: Send,
{
}
unsafe impl<T> Sync for ThinArc<T>
where
T: FfiDropArc,
::std::sync::Arc<T>: Sync,
{
}
pub use self::Arc as Arc_;
#[::safer_ffi::derive_ReprC]
#[repr(transparent)]
pub struct Arc<T: ?Sized + PointeeFitForCArc>(pub(super) <T as PointeeFitForCArc>::CArced);
#[diagnostic::on_unimplemented(
message = "`repr_c::Arc<dyn …>` requires `Fn` rather than `FnMut`, alongside `Send + Sync`",
label = "double-check that this be using `Fn` rather than `FnMut`, alongside `Send + Sync`"
)]
pub trait PointeeFitForCArc<Diagnostics = ()> {
type CArced: ReprC;
}
impl<T: Sized + FfiDropArc> PointeeFitForCArc for T {
type CArced = ThinArc<T>;
}
arc_closure_impls! {
dyn Send + Sync + Fn() -> R,
dyn Send + Sync + Fn(A) -> R,
dyn Send + Sync + Fn(A, B) -> R,
dyn Send + Sync + Fn(A, B, C) -> R,
dyn Send + Sync + Fn(A, B, C, D) -> R,
}
#[rustfmt::skip]
macro_rules! arc_closure_impls {(
$(
dyn Send + Sync + Fn($($Arg:ident),*) -> $R:ident,
)*
) => (
$(
impl<
$R : ReprC $(, $Arg : ReprC)*
>
PointeeFitForCArc
for
dyn 'static + Send + Sync + Fn($($Arg),*) -> $R
{
type CArced = ::safer_ffi::prelude::repr_c::Arc<
dyn 'static + Send + Sync + Fn($($Arg),*) -> $R,
>;
}
impl<
T,
$R : ReprC $(, $Arg : ReprC)*
>
From<::std::sync::Arc<T>>
for
Arc<dyn 'static + Send + Sync + Fn($($Arg),*) -> $R>
where
T : 'static + Send + Sync + Fn($($Arg),*) -> $R,
{
fn from(f: ::std::sync::Arc<T>) -> Self {
Self(f.into())
}
}
impl<$R : ReprC $(, $Arg : ReprC)*>
Arc<dyn 'static + Send + Sync + Fn($($Arg),*) -> $R>
{
#[allow(nonstandard_style)]
pub fn call(&self $(, $Arg: $Arg)*) -> $R {
self.0.call($($Arg),*)
}
}
repr_c_ptr_dyn_diagnostics::improve_lack_of_PointeeFitForCArc_impl_diagnostics! {
dyn Send? + Sync? + FnMut?($($Arg),*) -> $R,
}
)*
)}
use arc_closure_impls;
mod repr_c_ptr_dyn_diagnostics {
include!("repr_c_ptr_dyn_diagnostics.rs");
}
impl<T> ::core::ops::Deref for Arc<T>
where
T: FfiDropArc,
{
type Target = T;
fn deref(self: &'_ Self) -> &'_ T {
unsafe { self.0.ptr.as_ref() }
}
}
impl<T> ::core::ops::DerefMut for Arc<T>
where
T: FfiDropArc,
{
fn deref_mut(self: &'_ mut Self) -> &'_ mut T {
unsafe { self.0.ptr.as_mut() }
}
}
impl<T: ::std::fmt::Debug> ::std::fmt::Debug for Arc<T>
where
T: FfiDropArc,
{
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
T::fmt(self, f)
}
}
impl<T> Clone for repr_c::Arc<T>
where
T: FfiDropArc,
{
fn clone(&self) -> Self {
Self { 0: self.0.clone() }
}
}
pub use result::*;
mod result {
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/", "result.rs"));
}
}
#[cfg_attr(all(rustfmt), rustfmt::skip)]
macro_rules! extern_type_polyfill {
(
$( #[$attrs:meta] )*
unsafe extern $($abi:literal)? {
$($contents:tt)*
}
) => (
$crate::ffi_utils::extern_type_polyfill! {
@internal
[$($attrs)*]
[$($abi)?]
$($contents)*
}
);
(
@internal $attrs:tt $abi:tt
$( #[$ty_attrs:meta] )*
$pub:vis type $TypeName:ident
$(:
$SendOrSync:ident
$(+ $SendOrSync2:ident)*
$(+)?
)?
;
$($rest:tt)*
) => (
$( #[$ty_attrs] )*
#[::safer_ffi::derive_ReprC]
#[repr(opaque)]
$pub
struct $TypeName {
_private: [u8; 0],
__not_send_nor_sync: ::core::marker::PhantomData<*const ()>,
}
::paste::paste! {
$pub type [<Boxed $TypeName>] =
$crate::ffi_utils::repr_c::Box<$TypeName>
;
}
$(
unsafe impl $SendOrSync for $TypeName {}
$(
unsafe impl $SendOrSync2 for $TypeName {}
)*
)?
impl $crate::ffi_utils::NonOpaque for $TypeName
where
for<'_never_true> $TypeName : $crate::ffi_utils::diagnostic_hack::ExternDropFnAnnotation
,
{}
$crate::ffi_utils::extern_type_polyfill! {
@internal $attrs $abi
$($rest)*
}
);
(
@internal $attrs:tt $abi:tt
#[drop(to impl FfiDropBox for $T:ty)]
$pub:vis fn $fname:ident (
$arg_name:tt : $BoxedTy:ty $(,)?
);
$($rest:tt)*
) => (
$crate::ffi_utils::extern_type_polyfill! {
@internal $attrs $abi
$pub fn $fname (
$arg_name : $BoxedTy,
);
$($rest)*
}
impl $crate::ffi_utils::FfiDropBox for $T {
unsafe
fn drop_boxed (it: &'_ mut $BoxedTy)
{
unsafe {
$fname(<*const $BoxedTy>::read(it))
}
}
}
);
(
@internal $attrs:tt $abi:tt
#[drop(to impl FfiDropArc for $T:ty)]
$pub:vis fn $fname:ident (
$arg_name:tt : $ArcedTy:ty $(,)?
);
$($rest:tt)*
) => (
$crate::ffi_utils::extern_type_polyfill! {
@internal $attrs $abi
$pub fn $fname (
$arg_name : $ArcedTy,
);
$($rest)*
}
impl $crate::ffi_utils::FfiDropArc for $T {
unsafe
fn drop_arced (it: &'_ mut $ArcedTy)
{
unsafe {
$fname(<*const $ArcedTy>::read(it))
}
}
}
);
(
@internal [$($attrs:tt)*] [$($abi:literal)?]
$(#[$fn_attrs:meta])*
$pub:vis
$(unsafe $(@$if_unsafe:tt)?)?
fn $fname:ident $(< $($a:lifetime $(: $b:lifetime)?),* >)? (
$($arg_name:ident : $ArgTy:ty),* $(,)?
) $(-> $Ret:ty)?;
$($rest:tt)*
) => (
$(#[$fn_attrs])*
#[inline]
$pub
$($($if_unsafe)?
unsafe
)?
fn $fname $(< $($a $(: $b)?),* >)? (
$($arg_name : $ArgTy),*
) $(-> $Ret)?
{
$( #[$attrs] )*
#[allow(improper_ctypes)]
extern $($abi)? {
$(#[$fn_attrs])*
$pub
fn $fname $(< $($a $(: $b)?),* >)? (
$($arg_name : $ArgTy),*
) $(-> $Ret)?
;
}
unsafe {
$fname($($arg_name),*)
}
}
$crate::ffi_utils::extern_type_polyfill! {
@internal [$($attrs)*] [$($abi)?]
$($rest)*
}
);
(
@internal $attrs:tt $abi:tt
) => (
);
}
pub(crate) use extern_type_polyfill;
#[cfg_attr(all(rustfmt), rustfmt::skip)]
macro_rules! guarded_type_alias {
(
$( #[doc = $doc:tt] )*
$pub:vis
type $TypeName:ident [$($generics:tt)*]
where {
$($where_clauses:tt)*
} = $T:ty;
) => (::paste::paste! {
#[cfg(not(doc))]
#[allow(nonstandard_style)]
$pub
trait [<__ChecksForTyAlias__$TypeName>] <$($generics)*>
where
$($where_clauses)*
{
type T : ?Sized;
}
#[cfg(not(doc))]
impl<$($generics)*>
[<__ChecksForTyAlias__$TypeName>] <$($generics)*>
for
()
where
$($where_clauses)*
{
type T = $T;
}
#[cfg(not(doc))]
$pub type $TypeName<$($generics)*> =
<
()
as
[<__ChecksForTyAlias__$TypeName>] <$($generics)*>
>::T
;
$( #[doc = $doc] )*
#[cfg(doc)]
$pub type $TypeName<$($generics)*> where $($where_clauses)* = $T;
});
(
$( #[doc = $doc:expr] )*
$pub:vis type $TypeName:ident
<
$($lt:lifetime),*
$(,)?
$($T:ident),*
> $($rest:tt)*
) => (
$crate::ffi_utils::guarded_type_alias! {
$(#[doc = $doc])*
$pub type $TypeName [$($lt ,)* $($T),*] $($rest)*
}
);
}
pub(crate) use guarded_type_alias;
#[cfg_attr(all(rustfmt), rustfmt::skip)]
macro_rules! non_exhaustive_ffi_enum {(
#[repr($int:tt)]
$( #$attr:tt )*
$pub:vis
enum $EnumName:ident {
$(
$( #[doc $($doc:tt)*] )*
$Variant:ident $(= $value:expr)?
),* $(,)?
}
) => (
#[repr(transparent)]
$( #$attr )*
$pub
struct $EnumName {
discriminant: $int,
}
#[allow(warnings, clippy::all)]
const _: () = {
#[derive(Debug)]
#[repr($int)]
enum Discriminants {
$(
$Variant $(= $value)?
),*
}
impl $EnumName {
$(
$( #[doc $($doc)*] )*
$pub const $Variant: Self = Self {
discriminant: Discriminants::$Variant as _,
};
)*
}
impl ::core::fmt::Debug for $EnumName {
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
-> ::core::fmt::Result
{
match *self {
$(
| Self::$Variant => Discriminants::$Variant.fmt(f),
)*
| Self { discriminant: unknown_discriminant } => {
#[::core::prelude::v1::derive(::core::fmt::Debug)]
struct $EnumName {
unknown_discriminant: $int,
}
$EnumName { unknown_discriminant }.fmt(f)
}
}
}
}
};
)}
pub(crate) use non_exhaustive_ffi_enum;
pub mod diagnostic_hack {
mod seal {
pub trait NeverImplemented {}
}
#[rustfmt::skip]
#[diagnostic::on_unimplemented(
message = "\
The pointee type is missing its companion `#[drop(…)] fn …;` declaration.",
note = "\
`extern type`s have no known size or statically-dispatchable `drop_in_place()` logic, \
which is otherwise ordinarily the case, and the reason `drop::<Box<T>>()` is \
well-defined.
Since it is not the case here, we need to manually tell Rust how \"an owned pointed to \
a `T`\" (a `c::Box<T>`) is to be dropped.
This is done through the `FfiDropBox` trait, which is automagically defined and \
implemented for `extern type`s which have the following kind of companion annotation:
#[apply(extern_type_polyfill!)]
extern \"C\" {{
…
type Foo : …;
#[drop(to impl FfiDropBox for Foo)]
fn dittoffi_current_type_free(_: c::Box<Foo>);
…
}}
\
",
)]
pub trait ExternDropFnAnnotation: Sized + seal::NeverImplemented {}
}