diff --git a/src/message/mod.rs b/src/message/mod.rs index b88190fd4..86f80dcee 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -34,7 +34,7 @@ mod platform; mod platform; use self::platform::{send_unverified, send_super_unverified}; -use self::verify::verify_message_signature; +use self::verify::{VerificationError, verify_message_signature}; /// Specifies the superclass of an instance. #[repr(C)] @@ -100,6 +100,7 @@ pub unsafe trait Message { where Self: Sized, A: EncodeArguments, R: Encode { let obj = unsafe { &*(self as *const _ as *const Object) }; verify_message_signature::(obj.class(), sel) + .map_err(MessageError::from) } } @@ -169,6 +170,12 @@ impl Error for MessageError { } } +impl<'a> From> for MessageError { + fn from(err: VerificationError) -> MessageError { + MessageError(err.to_string()) + } +} + #[doc(hidden)] #[inline(always)] #[cfg(not(feature = "verify_message"))] @@ -186,14 +193,13 @@ pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) where T: Message, A: MessageArguments + EncodeArguments, R: Any + Encode { let cls = if obj.is_null() { - return Err(MessageError(format!("Messaging {:?} to nil", sel))); + return Err(VerificationError::NilReceiver(sel).into()); } else { (*(obj as *const Object)).class() }; - verify_message_signature::(cls, sel).and_then(|_| { - send_unverified(obj, sel, args) - }) + verify_message_signature::(cls, sel)?; + send_unverified(obj, sel, args) } #[doc(hidden)] @@ -213,12 +219,11 @@ pub unsafe fn send_super_message(obj: *const T, superclass: &Class, where T: Message, A: MessageArguments + EncodeArguments, R: Any + Encode { if obj.is_null() { - return Err(MessageError(format!("Messaging {:?} to nil", sel))); + return Err(VerificationError::NilReceiver(sel).into()); } - verify_message_signature::(superclass, sel).and_then(|_| { - send_super_unverified(obj, superclass, sel, args) - }) + verify_message_signature::(superclass, sel)?; + send_super_unverified(obj, superclass, sel, args) } #[cfg(test)] diff --git a/src/message/verify.rs b/src/message/verify.rs index 602aeb7f6..ac86fbbec 100644 --- a/src/message/verify.rs +++ b/src/message/verify.rs @@ -1,25 +1,56 @@ -use crate::runtime::{Class, Object, Sel}; -use crate::{Encode, EncodeArguments}; -use super::MessageError; +use std::fmt; + +use crate::runtime::{Class, Method, Object, Sel}; +use crate::{Encode, Encoding, EncodeArguments}; + +pub enum VerificationError<'a> { + NilReceiver(Sel), + MethodNotFound(&'a Class, Sel), + MismatchedReturn(&'a Method, Encoding<'static>), + MismatchedArgumentsCount(&'a Method, usize), + MismatchedArgument(&'a Method, usize, Encoding<'static>), +} + +impl<'a> fmt::Display for VerificationError<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + VerificationError::NilReceiver(sel) => { + write!(f, "Messsaging {:?} to nil", sel) + } + VerificationError::MethodNotFound(cls, sel) => { + write!(f, "Method {:?} not found on class {:?}", sel, cls) + } + VerificationError::MismatchedReturn(method, ret) => { + let expected_ret = method.return_type(); + write!(f, "Return type code {} does not match expected {} for method {:?}", + ret, expected_ret, method.name()) + } + VerificationError::MismatchedArgumentsCount(method, count) => { + let expected_count = method.arguments_count(); + write!(f, "Method {:?} accepts {} arguments, but {} were given", + method.name(), expected_count, count) + } + VerificationError::MismatchedArgument(method, i, arg) => { + let expected = method.argument_type(i).unwrap(); + write!(f, "Method {:?} expected argument at index {} with type code {:?} but was given {:?}", + method.name(), i, expected, arg) + } + } + } +} pub fn verify_message_signature(cls: &Class, sel: Sel) - -> Result<(), MessageError> + -> Result<(), VerificationError> where A: EncodeArguments, R: Encode { let method = match cls.instance_method(sel) { Some(method) => method, - None => return Err(MessageError( - format!("Method {:?} not found on class {:?}", - sel, cls) - )), + None => return Err(VerificationError::MethodNotFound(cls, sel)), }; let ret = R::ENCODING; let expected_ret = method.return_type(); if ret != *expected_ret { - return Err(MessageError( - format!("Return type code {} does not match expected {} for method {:?}", - ret, expected_ret, method.name()) - )); + return Err(VerificationError::MismatchedReturn(method, ret)); } let self_and_cmd = [<*mut Object>::ENCODING, Sel::ENCODING]; @@ -28,19 +59,13 @@ pub fn verify_message_signature(cls: &Class, sel: Sel) let count = self_and_cmd.len() + args.len(); let expected_count = method.arguments_count(); if count != expected_count { - return Err(MessageError( - format!("Method {:?} accepts {} arguments, but {} were given", - method.name(), expected_count, count) - )); + return Err(VerificationError::MismatchedArgumentsCount(method, count)); } - for (i, arg) in self_and_cmd.iter().chain(args).enumerate() { + for (i, arg) in self_and_cmd.iter().chain(args).copied().enumerate() { let expected = method.argument_type(i).unwrap(); - if *arg != *expected { - return Err(MessageError( - format!("Method {:?} expected argument at index {} with type code {:?} but was given {:?}", - method.name(), i, expected, arg) - )); + if arg != *expected { + return Err(VerificationError::MismatchedArgument(method, i, arg)); } }