Skip to content

Commit

Permalink
Make repr_c::Box<dyn FnMut…> and by extension fn pointers, `Optio…
Browse files Browse the repository at this point in the history
…n`able
  • Loading branch information
danielhenrymantilla committed Sep 17, 2024
1 parent aaa4014 commit 0aade0a
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 79 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ serde_test = { version = "1.0.177" }
async-compat.optional = true
async-compat.version = "0.2.1"

extern-c.version = "0.1.0"

futures.optional = true
futures.version = "0.3.24"

Expand Down
61 changes: 31 additions & 30 deletions src/closure/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,26 +39,39 @@ macro_rules! with_tuple {(
}
{
env_ptr: ptr::NonNull<c_void>,
call:
call: Option<
unsafe extern "C"
fn (
env_ptr: ptr::NonNull<c_void> $(,
$A_N $(,
$A_k
)*)?
) -> Ret
,
free:
>,
free: Option<
unsafe extern "C"
fn (env_ptr: ptr::NonNull<c_void>)
,
>,
}
}

unsafe
impl<Ret $(, $A_N $(, $A_k)*)?>
$crate::layout::__HasNiche__
for
$BoxDynFnMut_N <Ret $(, $A_N $(, $A_k)*)?>
where
Ret : ReprC, $(
$A_N : ReprC, $(
$A_k : ReprC, )*)?
{}

/// `Box<dyn Send + ...> : Send`
unsafe
impl<Ret $(, $A_N $(, $A_k)*)?> Send
for $BoxDynFnMut_N <Ret $(, $A_N $(, $A_k)*)?>
impl<Ret $(, $A_N $(, $A_k)*)?>
Send
for
$BoxDynFnMut_N <Ret $(, $A_N $(, $A_k)*)?>
where
Ret : ReprC, $(
$A_N : ReprC, $(
Expand Down Expand Up @@ -93,7 +106,7 @@ macro_rules! with_tuple {(
{
#[inline]
pub
fn new<F> (f: rust::Box<F>) -> Self
fn new<F> (f: Box<F>) -> Self
where
F : FnMut( $($A_N $(, $A_k)*)? ) -> Ret,
F : Send + 'static,
Expand All @@ -102,33 +115,21 @@ macro_rules! with_tuple {(
// thanks to the generic bounds on F.
Self {
env_ptr: ptr::NonNull::from(Box::leak(f)).cast(),
free: {
unsafe extern "C"
fn free<F> (env_ptr: ptr::NonNull<c_void>)
where
F : Send + 'static,
{
drop::<Box<F>>(Box::from_raw(env_ptr.cast().as_ptr()));
}
free::<F>
},
call: {
unsafe extern "C"
fn call<F, Ret $(, $A_N $(, $A_k)*)?> (
free: Some(::extern_c::extern_c(|env_ptr: ptr::NonNull<c_void>| unsafe {
drop(Box::<F>::from_raw(env_ptr.cast().as_ptr()));
})),
call: Some(::extern_c::extern_c(
|
env_ptr: ptr::NonNull<c_void> $(,
$A_N : $A_N $(,
$A_k : $A_k )*)?
) -> Ret
where
F : FnMut($($A_N $(, $A_k)*)?) -> Ret,
F : Send + 'static,
| -> Ret
{
let mut env_ptr = env_ptr.cast();
let f: &mut F = env_ptr.as_mut();
let mut env_ptr: ptr::NonNull<F> = env_ptr.cast();
let f: &mut F = unsafe { env_ptr.as_mut() };
f( $($A_N $(, $A_k)*)? )
}
call::<F, Ret $(, $A_N $(, $A_k)*)?>
},
)),
}
}
}
Expand All @@ -143,7 +144,7 @@ macro_rules! with_tuple {(
fn drop (self: &'_ mut Self)
{
unsafe {
(self.free)(self.env_ptr)
self.free.expect("non-NULL `.free`")(self.env_ptr)
}
}
}
Expand All @@ -164,7 +165,7 @@ macro_rules! with_tuple {(
) -> Ret
{
unsafe {
(self.call)(self.env_ptr, $($A_N $(, $A_k)*)?)
self.call.expect("non-NULL `.call`")(self.env_ptr, $($A_N $(, $A_k)*)?)
}
}
}
Expand Down
74 changes: 25 additions & 49 deletions src/layout/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const _: () = { macro_rules! impl_CTypes {
}
#[cfg(docs)] impl_CTypes! { @fns (A1, A2) } #[cfg(not(docs))]
impl_CTypes! { @fns
(A9, A8, A7, A6, A5, A4, A3, A2, A1)
(A10, A9, A8, A7, A6, A5, A4, A3, A2, A1)
}
#[cfg(docs)] impl_CTypes! { @arrays 1 2 } #[cfg(not(docs))]
impl_CTypes! { @arrays
Expand Down Expand Up @@ -242,6 +242,30 @@ const _: () = { macro_rules! impl_CTypes {
}
)?

unsafe // Safety: this is the "blessed" type recommended across Rust
// literature. Still the alignment of function pointers is not
// as well-defined, as one would wish.
impl<
Ret : ReprC, $(
$An : ReprC, $(
$Ai : ReprC,
)*)?> $crate::layout::__HasNiche__
for
unsafe extern "C" fn ($($An, $($Ai ,)*)?) -> Ret
{}

unsafe // Safety: this is the "blessed" type recommended across Rust
// literature. Still the alignment of function pointers is not
// as well-defined, as one would wish.
impl<
Ret : ReprC, $(
$An : ReprC, $(
$Ai : ReprC,
)*)?> $crate::layout::__HasNiche__
for
/*unsafe*/ extern "C" fn ($($An, $($Ai ,)*)?) -> Ret
{}

// LegacyCType
/// Simplified for lighter documentation, but the actual impls include
/// **up to 9 function parameters**.
Expand Down Expand Up @@ -360,54 +384,6 @@ const _: () = { macro_rules! impl_CTypes {
}
} type OPAQUE_KIND = OpaqueKind::Concrete; }

/// Simplified for lighter documentation, but the actual impls include
/// **up to 9 function parameters**.
unsafe // Safety: byte-wise the layout is the same, but the safety
// invariants will still have to be checked at each site.
impl<
Ret : ReprC, $(
$An : ReprC, $(
$Ai : ReprC,
)*)?> ReprC
for Option<unsafe extern "C" fn ($($An, $($Ai ,)*)?) -> Ret>
{
type CLayout = Option<
unsafe extern "C"
fn ($($An::CLayout, $($Ai::CLayout ,)*)?) -> Ret::CLayout
>;

#[inline]
fn is_valid (_: &'_ Self::CLayout)
-> bool
{
true
}
}

/// Simplified for lighter documentation, but the actual impls include
/// **up to 9 function parameters**.
unsafe // Safety: byte-wise the layout is the same, but the safety
// invariants will still have to be checked at each site.
impl<
Ret : ReprC, $(
$An : ReprC, $(
$Ai : ReprC,
)*)?> ReprC
for Option</*unsafe*/ extern "C" fn ($($An, $($Ai ,)*)?) -> Ret>
{
type CLayout = Option<
unsafe extern "C"
fn ($($An::CLayout, $($Ai::CLayout ,)*)?) -> Ret::CLayout
>;

#[inline]
fn is_valid (_: &'_ Self::CLayout)
-> bool
{
true
}
}

/* == ReprC for Option-less == */

/// Simplified for lighter documentation, but the actual impls include
Expand Down

0 comments on commit 0aade0a

Please sign in to comment.