Skip to content

Commit

Permalink
Clean up IntoConcreteBlock trait
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Aug 16, 2022
1 parent aec3181 commit 380dbf7
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 10 deletions.
2 changes: 2 additions & 0 deletions block2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed
* **BREAKING**: Cleaned up `BlockArguments` trait, it is now sealed and a
subtrait of `EncodeArguments`.
* **BREAKING**: Cleaned up `IntoConcreteBlock` trait, it is now sealed and the
associated output type has been renamed to `Output`.

## 0.2.0-alpha.5 - 2022-07-19

Expand Down
38 changes: 28 additions & 10 deletions block2/src/concrete_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,45 @@ use objc2_encode::{Encode, Encoding, RefEncode};

use crate::{ffi, Block, BlockArguments, RcBlock};

/// Types that may be converted into a `ConcreteBlock`.
pub trait IntoConcreteBlock<A: BlockArguments>: Sized {
mod private {
pub trait Sealed<A> {}
}

/// Types that may be converted into a [`ConcreteBlock`].
///
/// This is implemented for [`Fn`] closures of up to 12 arguments, where each
/// argument and the return type implements [`Encode`].
///
///
/// # Safety
///
/// This is a sealed trait, and should not need to be implemented. Open an
/// issue if you know a use-case where this restrition should be lifted!
pub unsafe trait IntoConcreteBlock<A: BlockArguments>: private::Sealed<A> + Sized {
/// The return type of the resulting `ConcreteBlock`.
type Ret: Encode;
type Output: Encode;

/// Consumes self to create a `ConcreteBlock`.
fn into_concrete_block(self) -> ConcreteBlock<A, Self::Ret, Self>;
#[doc(hidden)]
fn __into_concrete_block(self) -> ConcreteBlock<A, Self::Output, Self>;
}

macro_rules! concrete_block_impl {
($f:ident) => (
concrete_block_impl!($f,);
);
($f:ident, $($a:ident : $t:ident),*) => (
impl<$($t: Encode,)* R: Encode, X> IntoConcreteBlock<($($t,)*)> for X
impl<$($t: Encode,)* R: Encode, X> private::Sealed<($($t,)*)> for X
where
X: Fn($($t,)*) -> R,
{}

unsafe impl<$($t: Encode,)* R: Encode, X> IntoConcreteBlock<($($t,)*)> for X
where
X: Fn($($t,)*) -> R,
{
type Ret = R;
type Output = R;

fn into_concrete_block(self) -> ConcreteBlock<($($t,)*), R, X> {
fn __into_concrete_block(self) -> ConcreteBlock<($($t,)*), R, X> {
extern "C" fn $f<$($t,)* R, X>(
block: &ConcreteBlock<($($t,)*), R, X>,
$($a: $t,)*
Expand Down Expand Up @@ -156,13 +174,13 @@ impl<A, R, F> ConcreteBlock<A, R, F>
where
A: BlockArguments,
R: Encode,
F: IntoConcreteBlock<A, Ret = R>,
F: IntoConcreteBlock<A, Output = R>,
{
/// Constructs a `ConcreteBlock` with the given closure.
/// When the block is called, it will return the value that results from
/// calling the closure.
pub fn new(closure: F) -> Self {
closure.into_concrete_block()
closure.__into_concrete_block()
}
}

Expand Down

0 comments on commit 380dbf7

Please sign in to comment.