Source code

Revision control

Copy as Markdown

Other Tools

use core::mem;
use crate::__macro_helpers::RetainedReturnValue;
use crate::encode::{EncodeArgument, EncodeArguments, EncodeReturn, RefEncode};
use crate::rc::Allocated;
use crate::runtime::{Imp, MessageReceiver, Sel};
use crate::Message;
mod private {
pub trait Sealed {}
}
/// Types that can be used as the implementation of an Objective-C method.
///
/// This is a sealed trait that is implemented for a lot of `extern "C"`
/// function pointer types.
//
// Note: `Sized` is intentionally added to make the trait dyn-incompatible.
pub trait MethodImplementation: private::Sealed + Sized {
/// The callee type of the method.
type Callee: ?Sized + RefEncode;
/// The argument types of the method.
type Arguments: EncodeArguments;
/// The return type of the method.
type Return: EncodeReturn;
#[doc(hidden)]
fn __imp(self) -> Imp;
}
macro_rules! method_impl_inner {
($(($unsafe:ident))? $abi:literal; $($t:ident),*) => {
impl<T, R, $($t),*> private::Sealed for $($unsafe)? extern $abi fn(T, Sel $(, $t)*) -> R
where
T: ?Sized + MessageReceiver,
R: EncodeReturn,
$($t: EncodeArgument,)*
{}
impl<T, R, $($t),*> MethodImplementation for $($unsafe)? extern $abi fn(T, Sel $(, $t)*) -> R
where
T: ?Sized + MessageReceiver,
R: EncodeReturn,
$($t: EncodeArgument,)*
{
type Callee = T::__Inner;
type Arguments = ($($t,)*);
type Return = R;
fn __imp(self) -> Imp {
// SAFETY: Transmuting to an `unsafe` function pointer
unsafe { mem::transmute(self) }
}
}
impl<T, $($t),*> private::Sealed for $($unsafe)? extern $abi fn(Allocated<T>, Sel $(, $t)*) -> RetainedReturnValue
where
T: ?Sized + Message,
$($t: EncodeArgument,)*
{}
#[doc(hidden)]
impl<T, $($t),*> MethodImplementation for $($unsafe)? extern $abi fn(Allocated<T>, Sel $(, $t)*) -> RetainedReturnValue
where
T: ?Sized + Message,
$($t: EncodeArgument,)*
{
type Callee = T;
type Arguments = ($($t,)*);
type Return = RetainedReturnValue;
fn __imp(self) -> Imp {
// SAFETY: `Allocated<T>` is the same as `NonNull<T>`, except
// with the assumption of a +1 calling convention.
//
// The calling convention is ensured to be upheld by having
// `RetainedReturnValue` in the type, since that type is private
// and hence only internal macros like `#[method_id]` will be
// able to produce it (and that, in turn, only allows it if
// the selector is `init` as checked by `MessageReceiveRetained`).
unsafe { mem::transmute(self) }
}
}
};
}
macro_rules! method_impl {
($($t:ident),*) => {
method_impl_inner!((unsafe) "C"; $($t),*);
method_impl_inner!("C"; $($t),*);
method_impl_inner!((unsafe) "C-unwind"; $($t),*);
method_impl_inner!("C-unwind"; $($t),*);
};
}
// Up to 16 arguments.
method_impl!();
method_impl!(A);
method_impl!(A, B);
method_impl!(A, B, C);
method_impl!(A, B, C, D);
method_impl!(A, B, C, D, E);
method_impl!(A, B, C, D, E, F);
method_impl!(A, B, C, D, E, F, G);
method_impl!(A, B, C, D, E, F, G, H);
method_impl!(A, B, C, D, E, F, G, H, I);
method_impl!(A, B, C, D, E, F, G, H, I, J);
method_impl!(A, B, C, D, E, F, G, H, I, J, K);
method_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
method_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M);
method_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
method_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
method_impl!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);