use alloc::string::String;
use core::fmt;
use core::mem;
use core::mem::ManuallyDrop;
use core::ptr::NonNull;
use std::error::Error;
use crate::rc::{Id, Ownership};
use crate::runtime::{Class, Imp, Object, Sel};
use crate::{Encode, EncodeArguments, RefEncode};
#[cfg(feature = "catch_all")]
unsafe fn conditional_try<R: Encode>(f: impl FnOnce() -> R) -> Result<R, MessageError> {
use alloc::borrow::ToOwned;
unsafe { crate::exception::catch(f) }.map_err(|exception| {
if let Some(exception) = exception {
MessageError(alloc::format!("Uncaught exception {:?}", exception))
} else {
MessageError("Uncaught exception nil".to_owned())
}
})
}
#[cfg(not(feature = "catch_all"))]
#[inline(always)]
unsafe fn conditional_try<R: Encode>(f: impl FnOnce() -> R) -> Result<R, MessageError> {
Ok(f())
}
#[cfg(feature = "malloc")]
mod verify;
#[cfg(apple)]
#[path = "apple/mod.rs"]
mod platform;
#[cfg(gnustep)]
#[path = "gnustep.rs"]
mod platform;
use self::platform::{send_super_unverified, send_unverified};
#[cfg(feature = "malloc")]
use self::verify::{verify_message_signature, VerificationError};
pub unsafe trait Message: RefEncode {}
unsafe impl<T: Message + ?Sized> Message for ManuallyDrop<T> {}
unsafe impl Message for Object {}
unsafe impl Message for Class {}
pub(crate) mod private {
use super::{Id, ManuallyDrop, Message, MessageReceiver, NonNull, Ownership};
pub trait Sealed {}
impl<T: Message + ?Sized> Sealed for *const T {}
impl<T: Message + ?Sized> Sealed for *mut T {}
impl<'a, T: Message + ?Sized> Sealed for &'a T {}
impl<'a, T: Message + ?Sized> Sealed for &'a mut T {}
impl<T: Message + ?Sized> Sealed for NonNull<T> {}
impl<T: Message + ?Sized, O: Ownership> Sealed for Id<T, O> {}
impl<T: MessageReceiver + ?Sized> Sealed for ManuallyDrop<T> {}
}
pub unsafe trait MessageReceiver: private::Sealed {
fn as_raw_receiver(&self) -> *mut Object;
#[cfg_attr(not(feature = "verify_message"), inline(always))]
unsafe fn send_message<A, R>(&self, sel: Sel, args: A) -> Result<R, MessageError>
where
A: MessageArguments,
R: Encode,
{
let this = self.as_raw_receiver();
#[cfg(feature = "verify_message")]
{
let this = unsafe { this.as_ref() };
let cls = if let Some(this) = this {
this.class()
} else {
return Err(VerificationError::NilReceiver(sel).into());
};
verify_message_signature::<A, R>(cls, sel)?;
}
unsafe { send_unverified(this, sel, args) }
}
#[cfg_attr(not(feature = "verify_message"), inline(always))]
unsafe fn send_super_message<A, R>(
&self,
superclass: &Class,
sel: Sel,
args: A,
) -> Result<R, MessageError>
where
A: MessageArguments,
R: Encode,
{
let this = self.as_raw_receiver();
#[cfg(feature = "verify_message")]
{
if this.is_null() {
return Err(VerificationError::NilReceiver(sel).into());
}
verify_message_signature::<A, R>(superclass, sel)?;
}
unsafe { send_super_unverified(this, superclass, sel, args) }
}
#[cfg(feature = "malloc")]
fn verify_message<A, R>(&self, sel: Sel) -> Result<(), MessageError>
where
A: EncodeArguments,
R: Encode,
{
let obj = unsafe { &*self.as_raw_receiver() };
verify_message_signature::<A, R>(obj.class(), sel).map_err(MessageError::from)
}
}
unsafe impl<T: Message + ?Sized> MessageReceiver for *const T {
#[inline]
fn as_raw_receiver(&self) -> *mut Object {
*self as *mut T as *mut Object
}
}
unsafe impl<T: Message + ?Sized> MessageReceiver for *mut T {
#[inline]
fn as_raw_receiver(&self) -> *mut Object {
*self as *mut Object
}
}
unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a T {
#[inline]
fn as_raw_receiver(&self) -> *mut Object {
*self as *const T as *mut T as *mut Object
}
}
unsafe impl<'a, T: Message + ?Sized> MessageReceiver for &'a mut T {
#[inline]
fn as_raw_receiver(&self) -> *mut Object {
*self as *const T as *mut T as *mut Object
}
}
unsafe impl<T: Message + ?Sized> MessageReceiver for NonNull<T> {
#[inline]
fn as_raw_receiver(&self) -> *mut Object {
self.as_ptr() as *mut Object
}
}
unsafe impl<T: Message + ?Sized, O: Ownership> MessageReceiver for Id<T, O> {
#[inline]
fn as_raw_receiver(&self) -> *mut Object {
(&**self).as_raw_receiver()
}
}
unsafe impl<T: MessageReceiver + ?Sized> MessageReceiver for ManuallyDrop<T> {
#[inline]
fn as_raw_receiver(&self) -> *mut Object {
(**self).as_raw_receiver()
}
}
pub trait MessageArguments: EncodeArguments {
#[doc(hidden)]
unsafe fn __invoke<R: Encode>(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R;
}
macro_rules! message_args_impl {
($($a:ident : $t:ident),*) => (
impl<$($t: Encode),*> MessageArguments for ($($t,)*) {
#[inline]
#[doc(hidden)]
unsafe fn __invoke<R: Encode>(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R {
let imp: unsafe extern "C" fn(*mut Object, Sel $(, $t)*) -> R = unsafe {
mem::transmute(imp)
};
unsafe { imp(obj, sel $(, $a)*) }
}
}
);
}
message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K
);
message_args_impl!(
a: A,
b: B,
c: C,
d: D,
e: E,
f: F,
g: G,
h: H,
i: I,
j: J,
k: K,
l: L
);
#[derive(Debug)]
pub struct MessageError(String);
impl fmt::Display for MessageError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl Error for MessageError {
fn description(&self) -> &str {
&self.0
}
}
#[cfg(feature = "malloc")]
impl<'a> From<VerificationError<'a>> for MessageError {
fn from(err: VerificationError<'_>) -> MessageError {
use alloc::string::ToString;
MessageError(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils;
#[test]
fn test_send_message() {
let obj = test_utils::custom_object();
let result: u32 = unsafe {
let _: () = msg_send![obj, setFoo: 4u32];
msg_send![obj, foo]
};
assert_eq!(result, 4);
}
#[test]
fn test_send_message_stret() {
let obj = test_utils::custom_object();
let result: test_utils::CustomStruct = unsafe { msg_send![obj, customStruct] };
let expected = test_utils::CustomStruct {
a: 1,
b: 2,
c: 3,
d: 4,
};
assert_eq!(result, expected);
}
#[cfg(not(feature = "verify_message"))]
#[test]
fn test_send_message_nil() {
let nil: *mut Object = ::core::ptr::null_mut();
let result: *mut Object = unsafe { msg_send![nil, description] };
assert!(result.is_null());
let result: usize = unsafe { msg_send![nil, hash] };
assert_eq!(result, 0);
#[cfg(target_pointer_width = "16")]
let result: f32 = 0.0;
#[cfg(target_pointer_width = "32")]
let result: f32 = unsafe { msg_send![nil, floatValue] };
#[cfg(target_pointer_width = "64")]
let result: f64 = unsafe { msg_send![nil, doubleValue] };
assert_eq!(result, 0.0);
let result: *mut Object = unsafe { msg_send![nil, multiple: 1u32, arguments: 2i8] };
assert!(result.is_null());
}
#[test]
fn test_send_message_super() {
let obj = test_utils::custom_subclass_object();
let superclass = test_utils::custom_class();
unsafe {
let _: () = msg_send![obj, setFoo: 4u32];
let foo: u32 = msg_send![super(obj, superclass), foo];
assert_eq!(foo, 4);
let foo: u32 = msg_send![obj, foo];
assert_eq!(foo, 6);
}
}
#[test]
fn test_send_message_manuallydrop() {
let obj = test_utils::custom_object();
let obj = ManuallyDrop::new(obj);
let result: u32 = unsafe {
let _: () = msg_send![obj, setFoo: 4u32];
msg_send![obj, foo]
};
assert_eq!(result, 4);
let obj: *const ManuallyDrop<Object> = (&**obj as *const Object).cast();
let result: u32 = unsafe { msg_send![obj, foo] };
assert_eq!(result, 4);
}
#[test]
#[cfg(feature = "malloc")]
fn test_verify_message() {
let obj = test_utils::custom_object();
assert!(obj.verify_message::<(), u32>(sel!(foo)).is_ok());
assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo:)).is_ok());
assert!(obj.verify_message::<(), u64>(sel!(setFoo:)).is_err());
assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo)).is_err());
}
}