Skip to content

Commit

Permalink
Add public EncodeReturn, EncodeArgument and EncodeArguments
Browse files Browse the repository at this point in the history
And make the two conversion traits ConvertReturn and ConvertArgument in a sense "more" private
  • Loading branch information
madsmtm committed Sep 3, 2023
1 parent a9ff910 commit c98e6cc
Show file tree
Hide file tree
Showing 30 changed files with 481 additions and 410 deletions.
7 changes: 3 additions & 4 deletions crates/block2/src/block.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use core::marker::PhantomData;
use core::mem;

use objc2::encode::__unstable::EncodeReturn;
use objc2::encode::{Encode, Encoding, RefEncode};
use objc2::encode::{EncodeArgument, EncodeReturn, Encoding, RefEncode};

use crate::ffi;

/// Types that may be used as the arguments of an Objective-C block.
///
/// This is implemented for tuples of up to 12 arguments, where each argument
/// implements [`Encode`].
/// implements [`EncodeArgument`].
///
///
/// # Safety
Expand All @@ -28,7 +27,7 @@ pub unsafe trait BlockArguments: Sized {

macro_rules! block_args_impl {
($($a:ident: $t:ident),*) => (
unsafe impl<$($t: Encode),*> BlockArguments for ($($t,)*) {
unsafe impl<$($t: EncodeArgument),*> BlockArguments for ($($t,)*) {
#[inline]
unsafe fn __call_block<R: EncodeReturn>(
invoke: unsafe extern "C" fn(),
Expand Down
10 changes: 5 additions & 5 deletions crates/block2/src/concrete_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use core::ops::Deref;
use core::ptr;
use std::os::raw::c_ulong;

use objc2::encode::__unstable::EncodeReturn;
use objc2::encode::{Encode, Encoding, RefEncode};
use objc2::encode::{EncodeArgument, EncodeReturn, Encoding, RefEncode};

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

Expand All @@ -17,7 +16,8 @@ mod private {
/// 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`].
/// argument implements [`EncodeArgument`] and the return type implements
/// [`EncodeReturn`].
///
///
/// # Safety
Expand All @@ -37,12 +37,12 @@ macro_rules! concrete_block_impl {
concrete_block_impl!($f,);
);
($f:ident, $($a:ident : $t:ident),*) => (
impl<$($t: Encode,)* R: EncodeReturn, X> private::Sealed<($($t,)*)> for X
impl<$($t: EncodeArgument,)* R: EncodeReturn, X> private::Sealed<($($t,)*)> for X
where
X: Fn($($t,)*) -> R,
{}

unsafe impl<$($t: Encode,)* R: EncodeReturn, X> IntoConcreteBlock<($($t,)*)> for X
unsafe impl<$($t: EncodeArgument,)* R: EncodeReturn, X> IntoConcreteBlock<($($t,)*)> for X
where
X: Fn($($t,)*) -> R,
{
Expand Down
2 changes: 1 addition & 1 deletion crates/block2/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::ops::Deref;
use core::ptr;
use std::os::raw::c_ulong;

use objc2::encode::__unstable::EncodeReturn;
use objc2::encode::EncodeReturn;

use super::{ffi, Block};
use crate::BlockArguments;
Expand Down
2 changes: 2 additions & 0 deletions crates/objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Added
* Added `mutability::IsMainThreadOnly`.
* Added new `encode` traits `EncodeReturn`, `EncodeArgument` and
`EncodeArguments`.


## 0.4.1 - 2023-07-31
Expand Down
168 changes: 168 additions & 0 deletions crates/objc2/src/__macro_helpers/convert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
use crate::encode::{EncodeArgument, EncodeReturn};
use crate::rc::Id;
use crate::runtime::Bool;
use crate::Message;

mod argument_private {
pub trait Sealed {}
}

/// Represents types that can be converted to/from an [`EncodeArgument`] type.
///
/// This is implemented specially for [`bool`] to allow using that as
/// Objective-C `BOOL`, where it would otherwise not be allowed (since they
/// are not ABI compatible).
///
/// This is also done specially for `&mut Id<_>`-like arguments, to allow
/// using those as "out" parameters.
pub trait ConvertArgument: argument_private::Sealed {
/// The inner type that this can be converted to and from.
#[doc(hidden)]
type __Inner: EncodeArgument;

/// A helper type for out parameters.
#[doc(hidden)]
type __StoredBeforeMessage: Sized;

#[doc(hidden)]
fn __from_declared_param(inner: Self::__Inner) -> Self;

#[doc(hidden)]
fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage);

#[doc(hidden)]
unsafe fn __process_after_message_send(_stored: Self::__StoredBeforeMessage) {}
}

// Implemented in writeback.rs
impl<T: Message> argument_private::Sealed for &mut Id<T> {}
impl<T: Message> argument_private::Sealed for Option<&mut Id<T>> {}
impl<T: Message> argument_private::Sealed for &mut Option<Id<T>> {}
impl<T: Message> argument_private::Sealed for Option<&mut Option<Id<T>>> {}

impl<T: EncodeArgument> argument_private::Sealed for T {}
impl<T: EncodeArgument> ConvertArgument for T {
type __Inner = Self;

type __StoredBeforeMessage = ();

#[inline]
fn __from_declared_param(inner: Self::__Inner) -> Self {
inner
}

#[inline]
fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) {
(self, ())
}
}

impl argument_private::Sealed for bool {}
impl ConvertArgument for bool {
type __Inner = Bool;

type __StoredBeforeMessage = ();

#[inline]
fn __from_declared_param(inner: Self::__Inner) -> Self {
inner.as_bool()
}

#[inline]
fn __into_argument(self) -> (Self::__Inner, Self::__StoredBeforeMessage) {
(Bool::new(self), ())
}
}

mod return_private {
pub trait Sealed {}
}

/// Same as [`ConvertArgument`], but for return types.
pub trait ConvertReturn: return_private::Sealed {
/// The inner type that this can be converted to and from.
#[doc(hidden)]
type __Inner: EncodeReturn;

#[doc(hidden)]
fn __into_declared_return(self) -> Self::__Inner;

#[doc(hidden)]
fn __from_return(inner: Self::__Inner) -> Self;
}

impl<T: EncodeReturn> return_private::Sealed for T {}
impl<T: EncodeReturn> ConvertReturn for T {
type __Inner = Self;

#[inline]
fn __into_declared_return(self) -> Self::__Inner {
self
}

#[inline]
fn __from_return(inner: Self::__Inner) -> Self {
inner
}
}

impl return_private::Sealed for bool {}
impl ConvertReturn for bool {
type __Inner = Bool;

#[inline]
fn __into_declared_return(self) -> Self::__Inner {
Bool::new(self)
}

#[inline]
fn __from_return(inner: Self::__Inner) -> Self {
inner.as_bool()
}
}

#[cfg(test)]
mod tests {
use super::*;

use core::any::TypeId;

#[test]
fn convert_normally_noop() {
assert_eq!(
TypeId::of::<<i32 as ConvertArgument>::__Inner>(),
TypeId::of::<i32>()
);
assert_eq!(<i32 as ConvertArgument>::__from_declared_param(42), 42);
assert_eq!(ConvertArgument::__into_argument(42i32).0, 42);
}

#[test]
fn convert_i8() {
assert_eq!(
TypeId::of::<<i8 as ConvertArgument>::__Inner>(),
TypeId::of::<i8>()
);
assert_eq!(<i8 as ConvertArgument>::__from_declared_param(-3), -3);
assert_eq!(ConvertArgument::__into_argument(-3i32).0, -3);
}

#[test]
fn convert_bool() {
assert!(!<bool as ConvertArgument>::__from_declared_param(Bool::NO));
assert!(<bool as ConvertArgument>::__from_declared_param(Bool::YES));
assert!(!<bool as ConvertReturn>::__from_return(Bool::NO));
assert!(<bool as ConvertReturn>::__from_return(Bool::YES));

assert!(!ConvertArgument::__into_argument(false).0.as_bool());
assert!(ConvertArgument::__into_argument(true).0.as_bool());
assert!(!ConvertReturn::__into_declared_return(false).as_bool());
assert!(ConvertReturn::__into_declared_return(true).as_bool());

#[cfg(all(feature = "apple", target_os = "macos", target_arch = "x86_64"))]
assert_eq!(
<bool as ConvertArgument>::__Inner::ENCODING_ARGUMENT,
crate::encode::Encoding::Char,
);
}
}
7 changes: 5 additions & 2 deletions crates/objc2/src/__macro_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ pub use std::sync::Once;

mod cache;
mod common_selectors;
mod convert;
mod declare_class;
mod writeback;

pub use self::cache::{CachedClass, CachedSel};
pub use self::common_selectors::{alloc_sel, dealloc_sel, init_sel, new_sel};
pub use self::declare_class::{
assert_mutability_matches_superclass_mutability, MaybeOptionId, MessageRecieveId,
ValidSubclassMutability,
};
pub use convert::{ConvertArgument, ConvertReturn};

/// Helper for specifying the retain semantics for a given selector family.
///
Expand Down Expand Up @@ -125,8 +128,8 @@ pub trait MsgSendId<T, U> {
} else {
// In this case, the error has very likely been created, but has
// been autoreleased (as is common for "out parameters", see
// `src/rc/writeback.rs`). Hence we need to retain it if we want
// it to live across autorelease pools.
// `src/__macro_helpers/writeback.rs`). Hence we need to retain it
// if we want it to live across autorelease pools.
//
// SAFETY: The message send is guaranteed to populate the error
// object, or leave it as NULL. The error is shared, and all
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
use core::mem::ManuallyDrop;
use core::ptr::NonNull;

use crate::encode::__unstable::EncodeConvertArgument;
use super::ConvertArgument;
use crate::rc::Id;
use crate::Message;

// Note the `'static` bound here - this may not be necessary, but I'm unsure
// of the exact requirements, so we better keep it for now.
impl<T: Message + 'static> EncodeConvertArgument for &mut Id<T> {
impl<T: Message + 'static> ConvertArgument for &mut Id<T> {
// We use `*mut T` as the inner value instead of `NonNull<T>`, since we
// want to do debug checking that the value hasn't unexpectedly been
// overwritten to contain NULL (which is clear UB, but the user might have
Expand Down Expand Up @@ -109,7 +109,7 @@ impl<T: Message + 'static> EncodeConvertArgument for &mut Id<T> {
}
}

impl<T: Message + 'static> EncodeConvertArgument for &mut Option<Id<T>> {
impl<T: Message + 'static> ConvertArgument for &mut Option<Id<T>> {
type __Inner = NonNull<*mut T>;

type __StoredBeforeMessage = (Self::__Inner, *mut T);
Expand Down Expand Up @@ -156,7 +156,7 @@ impl<T: Message + 'static> EncodeConvertArgument for &mut Option<Id<T>> {
// known at compile-time, and for the `None` case it would be detrimental to
// have extra `retain/release` calls here.

impl<T: Message + 'static> EncodeConvertArgument for Option<&mut Id<T>> {
impl<T: Message + 'static> ConvertArgument for Option<&mut Id<T>> {
type __Inner = Option<NonNull<*mut T>>;

type __StoredBeforeMessage = Option<(NonNull<*mut T>, NonNull<T>)>;
Expand Down Expand Up @@ -185,7 +185,7 @@ impl<T: Message + 'static> EncodeConvertArgument for Option<&mut Id<T>> {
}
}

impl<T: Message + 'static> EncodeConvertArgument for Option<&mut Option<Id<T>>> {
impl<T: Message + 'static> ConvertArgument for Option<&mut Option<Id<T>>> {
type __Inner = Option<NonNull<*mut T>>;

type __StoredBeforeMessage = Option<(NonNull<*mut T>, *mut T)>;
Expand Down
15 changes: 7 additions & 8 deletions crates/objc2/src/declare/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ use core::ptr;
use core::ptr::NonNull;
use std::ffi::CString;

use crate::encode::__unstable::{EncodeArguments, EncodeReturn};
use crate::encode::{Encode, Encoding, RefEncode};
use crate::encode::{Encode, EncodeArgument, EncodeArguments, EncodeReturn, Encoding, RefEncode};
use crate::ffi;
use crate::mutability::IsMutable;
use crate::rc::Allocated;
Expand Down Expand Up @@ -171,14 +170,14 @@ macro_rules! method_decl_impl {
where
T: ?Sized + $t_bound,
$r: EncodeReturn,
$($t: Encode,)*
$($t: EncodeArgument,)*
{}

impl<$($l,)* T, $r, $($t),*> MethodImplementation for $f
where
T: ?Sized + $t_bound,
$r: EncodeReturn,
$($t: Encode,)*
$($t: EncodeArgument,)*
{
type Callee = T;
type Ret = $r;
Expand All @@ -193,13 +192,13 @@ macro_rules! method_decl_impl {
impl<$($l,)* $r, $($t),*> private::Sealed for $f
where
$r: EncodeReturn,
$($t: Encode,)*
$($t: EncodeArgument,)*
{}

impl<$($l,)* $r, $($t),*> MethodImplementation for $f
where
$r: EncodeReturn,
$($t: Encode,)*
$($t: EncodeArgument,)*
{
type Callee = $callee;
type Ret = $r;
Expand All @@ -215,14 +214,14 @@ macro_rules! method_decl_impl {
impl<T, $($t),*> private::Sealed for $f
where
T: ?Sized + Message,
$($t: Encode,)*
$($t: EncodeArgument,)*
{}

#[doc(hidden)]
impl<T, $($t),*> MethodImplementation for $f
where
T: ?Sized + Message,
$($t: Encode,)*
$($t: EncodeArgument,)*
{
type Callee = T;
type Ret = __IdReturnValue;
Expand Down
Loading

0 comments on commit c98e6cc

Please sign in to comment.