diff --git a/.travis.yml b/.travis.yml index 5a04ad86c..cb51db9ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,70 @@ -language: rust -rust: - - stable - - nightly -os: - - osx - - linux -env: - - FEATURES="" IOS_ARCHS="" -matrix: - include: - - os: osx - rust: stable - env: FEATURES="exception verify_message" IOS_ARCHS="" - - os: osx - osx_image: xcode7.3 - rust: 1.41.0 - env: FEATURES="exception" IOS_ARCHS="i386 x86_64 armv7 armv7s aarch64" sudo: false -install: ./travis_install.sh +language: rust +cache: cargo + +addons: + apt: + packages: + - clang + - cmake +install: > + if [ "$TRAVIS_OS_NAME" = "linux" ]; then + git clone -b 1.9 https://github.com/gnustep/libobjc2.git && + mkdir libobjc2/build && + cd libobjc2/build && + export CC="clang" && + export CXX="clang++" && + cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/libobjc2_staging ../ && + make install + fi before_script: > if [ "$TRAVIS_OS_NAME" = "linux" ]; then export LIBRARY_PATH=$HOME/libobjc2_staging/lib:$LIBRARY_PATH; export LD_LIBRARY_PATH=$HOME/libobjc2_staging/lib:$LD_LIBRARY_PATH; fi -script: ./travis_test.sh -addons: - apt: - packages: - - clang - - cmake +script: cargo test --verbose + +jobs: + include: + - name: Check formatting + os: linux + rust: stable + install: rustup component add rustfmt + script: cargo fmt --all -- --check + + - name: MacOS stable + os: osx + rust: stable + - name: MacOS nightly + os: osx + rust: nightly + - name: MacOS stable w. features + os: osx + rust: stable + script: cargo test --verbose --features "exception verify_message" + - name: MacOS 32bit + os: osx + osx_image: xcode9.4 + rust: nightly + # 32-bit targets only have tier 3 support + install: rustup component add rust-src + script: cargo test -Z build-std --target i686-apple-darwin --verbose + + - name: Linux stable + os: linux + rust: stable + - name: Linux nightly + os: linux + rust: nightly + + - name: iOS nightly + os: osx + osx_image: xcode7.3 + rust: nightly + before_install: rustup component add rust-src + # Install rust-test-ios + install: curl -LO https://github.com/SSheldon/rust-test-ios/releases/download/0.1.1/rust-test-ios && chmod +x rust-test-ios + # Enable -Z build-std, 32-bit targets only have tier 3 support + before_script: printf '[unstable]\nbuild-std = ["std"]\n' > $HOME/.cargo/config.toml + env: FEATURES="exception" + script: ./rust-test-ios diff --git a/CHANGELOG.md b/CHANGELOG.md index c8b1bf894..a7a83c30f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,7 +84,7 @@ * C types are now used from `std::os::raw` rather than `libc`. This means `Encode` may not be implemented for `libc` types; switch them to the `std::os::raw` equivalents instead. This avoids an issue that would arise - from simultaneously using different versions of the libc crate. + from simultaneously using different versions of the libc crate. * Dynamic messaging was moved into the `Message` trait; instead of `().send(obj, sel!(description))`, use @@ -110,7 +110,7 @@ ### Fixed * Corrected alignment of ivars in `ClassDecl`; declared classes may now have a - smaller size. + smaller size. * With the `"exception"` or `"verify_message"` feature enabled, panics from `msg_send!` will now be triggered from the line and file where the macro is diff --git a/examples/example.rs b/examples/example.rs index a3ae0adc6..a6f06b3d2 100644 --- a/examples/example.rs +++ b/examples/example.rs @@ -1,9 +1,9 @@ #[macro_use] extern crate objc; -use objc::Encode; use objc::rc::StrongPtr; use objc::runtime::{Class, Object}; +use objc::Encode; fn main() { // Get a class @@ -25,9 +25,7 @@ fn main() { println!("NSObject address: {:p}", obj); // Access an ivar of the object - let isa: *const Class = unsafe { - *(**obj).get_ivar("isa") - }; + let isa: *const Class = unsafe { *(**obj).get_ivar("isa") }; println!("NSObject isa: {:?}", isa); // Inspect a method of the class @@ -38,8 +36,6 @@ fn main() { assert!(*hash_return == usize::ENCODING); // Invoke a method on the object - let hash: usize = unsafe { - msg_send![*obj, hash] - }; + let hash: usize = unsafe { msg_send![*obj, hash] }; println!("NSObject hash: {}", hash); } diff --git a/src/cache.rs b/src/cache.rs index 14bf98182..7400c1f04 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -2,19 +2,19 @@ use std::os::raw::c_void; use std::ptr; use std::sync::atomic::{AtomicPtr, Ordering}; -use crate::runtime::{Class, Sel, self}; +use crate::runtime::{self, Class, Sel}; /// Allows storing a `Sel` in a static and lazily loading it. #[doc(hidden)] pub struct CachedSel { - ptr: AtomicPtr + ptr: AtomicPtr, } impl CachedSel { /// Constructs a new `CachedSel`. pub const fn new() -> CachedSel { CachedSel { - ptr: AtomicPtr::new(ptr::null_mut()) + ptr: AtomicPtr::new(ptr::null_mut()), } } @@ -38,14 +38,14 @@ impl CachedSel { /// Allows storing a `Class` reference in a static and lazily loading it. #[doc(hidden)] pub struct CachedClass { - ptr: AtomicPtr + ptr: AtomicPtr, } impl CachedClass { /// Constructs a new `CachedClass`. pub const fn new() -> CachedClass { CachedClass { - ptr: AtomicPtr::new(ptr::null_mut()) + ptr: AtomicPtr::new(ptr::null_mut()), } } diff --git a/src/declare.rs b/src/declare.rs index 729a650aa..3f39b251a 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -38,7 +38,7 @@ use std::ffi::CString; use std::mem; use std::ptr; -use crate::runtime::{BOOL, Class, Imp, NO, Object, Protocol, Sel, self}; +use crate::runtime::{self, Class, Imp, Object, Protocol, Sel, BOOL, NO}; use crate::{Encode, EncodeArguments, Encoding, Message}; /// Types that can be used as the implementation of an Objective-C method. @@ -93,8 +93,7 @@ fn count_args(sel: Sel) -> usize { fn method_type_encoding(ret: &Encoding, args: &[Encoding]) -> CString { // First two arguments are always self and the selector - let mut types = format!("{}{}{}", - ret, <*mut Object>::ENCODING, Sel::ENCODING); + let mut types = format!("{}{}{}", ret, <*mut Object>::ENCODING, Sel::ENCODING); for enc in args { use std::fmt::Write; write!(&mut types, "{}", enc).unwrap(); @@ -117,13 +116,10 @@ pub struct ClassDecl { } impl ClassDecl { - fn with_superclass(name: &str, superclass: Option<&Class>) - -> Option { + fn with_superclass(name: &str, superclass: Option<&Class>) -> Option { let name = CString::new(name).unwrap(); let super_ptr = superclass.map_or(ptr::null(), |c| c); - let cls = unsafe { - runtime::objc_allocateClassPair(super_ptr, name.as_ptr(), 0) - }; + let cls = unsafe { runtime::objc_allocateClassPair(super_ptr, name.as_ptr(), 0) }; if cls.is_null() { None } else { @@ -150,8 +146,7 @@ impl ClassDecl { Functionality it expects, like implementations of `-retain` and `-release` used by ARC, will not be present otherwise. */ - pub fn root(name: &str, intitialize_fn: extern fn(&Class, Sel)) - -> Option { + pub fn root(name: &str, intitialize_fn: extern "C" fn(&Class, Sel)) -> Option { let mut decl = ClassDecl::with_superclass(name, None); if let Some(ref mut decl) = decl { unsafe { @@ -167,17 +162,20 @@ impl ClassDecl { /// Unsafe because the caller must ensure that the types match those that /// are expected when the method is invoked from Objective-C. pub unsafe fn add_method(&mut self, sel: Sel, func: F) - where F: MethodImplementation { + where + F: MethodImplementation, + { let encs = F::Args::ENCODINGS; let sel_args = count_args(sel); - assert!(sel_args == encs.len(), + assert!( + sel_args == encs.len(), "Selector accepts {} arguments, but function accepts {}", - sel_args, encs.len(), + sel_args, + encs.len(), ); let types = method_type_encoding(&F::Ret::ENCODING, encs); - let success = runtime::class_addMethod(self.cls, sel, func.imp(), - types.as_ptr()); + let success = runtime::class_addMethod(self.cls, sel, func.imp(), types.as_ptr()); assert!(success != NO, "Failed to add method {:?}", sel); } @@ -187,31 +185,36 @@ impl ClassDecl { /// Unsafe because the caller must ensure that the types match those that /// are expected when the method is invoked from Objective-C. pub unsafe fn add_class_method(&mut self, sel: Sel, func: F) - where F: MethodImplementation { + where + F: MethodImplementation, + { let encs = F::Args::ENCODINGS; let sel_args = count_args(sel); - assert!(sel_args == encs.len(), + assert!( + sel_args == encs.len(), "Selector accepts {} arguments, but function accepts {}", - sel_args, encs.len(), + sel_args, + encs.len(), ); let types = method_type_encoding(&F::Ret::ENCODING, encs); let metaclass = (*self.cls).metaclass() as *const _ as *mut _; - let success = runtime::class_addMethod(metaclass, sel, func.imp(), - types.as_ptr()); + let success = runtime::class_addMethod(metaclass, sel, func.imp(), types.as_ptr()); assert!(success != NO, "Failed to add class method {:?}", sel); } /// Adds an ivar with type `T` and the provided name to self. /// Panics if the ivar wasn't successfully added. - pub fn add_ivar(&mut self, name: &str) where T: Encode { + pub fn add_ivar(&mut self, name: &str) + where + T: Encode, + { let c_name = CString::new(name).unwrap(); let encoding = CString::new(T::ENCODING.to_string()).unwrap(); let size = mem::size_of::(); let align = log2_align_of::(); let success = unsafe { - runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align, - encoding.as_ptr()) + runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align, encoding.as_ptr()) }; assert!(success != NO, "Failed to add ivar {}", name); } @@ -247,7 +250,7 @@ impl Drop for ClassDecl { /// A type for declaring a new protocol and adding new methods to it /// before registering it. pub struct ProtocolDecl { - proto: *mut Protocol + proto: *mut Protocol, } impl ProtocolDecl { @@ -255,9 +258,7 @@ impl ProtocolDecl { /// protocol couldn't be allocated. pub fn new(name: &str) -> Option { let c_name = CString::new(name).unwrap(); - let proto = unsafe { - runtime::objc_allocateProtocol(c_name.as_ptr()) - }; + let proto = unsafe { runtime::objc_allocateProtocol(c_name.as_ptr()) }; if proto.is_null() { None } else { @@ -265,34 +266,50 @@ impl ProtocolDecl { } } - fn add_method_description_common(&mut self, sel: Sel, is_required: bool, - is_instance_method: bool) - where Args: EncodeArguments, - Ret: Encode { + fn add_method_description_common( + &mut self, + sel: Sel, + is_required: bool, + is_instance_method: bool, + ) where + Args: EncodeArguments, + Ret: Encode, + { let encs = Args::ENCODINGS; let sel_args = count_args(sel); - assert!(sel_args == encs.len(), + assert!( + sel_args == encs.len(), "Selector accepts {} arguments, but function accepts {}", - sel_args, encs.len(), + sel_args, + encs.len(), ); let types = method_type_encoding(&Ret::ENCODING, encs); unsafe { runtime::protocol_addMethodDescription( - self.proto, sel, types.as_ptr(), is_required as BOOL, is_instance_method as BOOL); + self.proto, + sel, + types.as_ptr(), + is_required as BOOL, + is_instance_method as BOOL, + ); } } /// Adds an instance method declaration with a given description to self. pub fn add_method_description(&mut self, sel: Sel, is_required: bool) - where Args: EncodeArguments, - Ret: Encode { + where + Args: EncodeArguments, + Ret: Encode, + { self.add_method_description_common::(sel, is_required, true) } /// Adds a class method declaration with a given description to self. pub fn add_class_method_description(&mut self, sel: Sel, is_required: bool) - where Args: EncodeArguments, - Ret: Encode { + where + Args: EncodeArguments, + Ret: Encode, + { self.add_method_description_common::(sel, is_required, false) } diff --git a/src/encode.rs b/src/encode.rs index 87d5a4669..9e277cf49 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -54,8 +54,8 @@ encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L); #[cfg(test)] mod tests { - use objc_encode::Encode; use crate::runtime::{Class, Object, Sel}; + use objc_encode::Encode; #[test] fn test_encode() { diff --git a/src/exception.rs b/src/exception.rs index 78a866c65..3e16c92cf 100644 --- a/src/exception.rs +++ b/src/exception.rs @@ -4,8 +4,8 @@ use crate::rc::StrongPtr; use crate::runtime::Object; pub unsafe fn catch_exception(closure: F) -> Result - where F: FnOnce() -> R { - objc_exception::r#try(closure).map_err(|exception| { - StrongPtr::new(exception as *mut Object) - }) +where + F: FnOnce() -> R, +{ + objc_exception::r#try(closure).map_err(|exception| StrongPtr::new(exception as *mut Object)) } diff --git a/src/lib.rs b/src/lib.rs index 5f2d4e9f1..2f88a9796 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,6 @@ The bindings can be used on Linux or *BSD utilizing the #![crate_name = "objc"] #![crate_type = "lib"] - #![warn(missing_docs)] extern crate malloc_buf; @@ -83,14 +82,14 @@ pub use crate::message::send_super_message as __send_super_message; #[macro_use] mod macros; -pub mod runtime; -pub mod declare; -pub mod rc; mod cache; +pub mod declare; mod encode; #[cfg(feature = "exception")] mod exception; mod message; +pub mod rc; +pub mod runtime; #[cfg(test)] mod test_utils; diff --git a/src/macros.rs b/src/macros.rs index f0e9fabc0..328f7a0c4 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -14,7 +14,7 @@ let cls = class!(NSObject); */ #[macro_export] macro_rules! class { - ($name:ident) => ({ + ($name:ident) => {{ static CLASS: $crate::__CachedClass = $crate::__CachedClass::new(); let name = concat!(stringify!($name), '\0'); #[allow(unused_unsafe)] @@ -23,7 +23,7 @@ macro_rules! class { Some(cls) => cls, None => panic!("Class with name {} could not be found", stringify!($name)), } - }) + }}; } /** diff --git a/src/message/apple/arm.rs b/src/message/apple/arm.rs index 6355e7ccb..6754088a2 100644 --- a/src/message/apple/arm.rs +++ b/src/message/apple/arm.rs @@ -1,9 +1,11 @@ -use std::any::{Any, TypeId}; -use std::mem; +use core::mem; +use super::MsgSendFn; use crate::runtime::Imp; +use crate::{Encode, Encoding}; -extern { +// TODO: C-unwind +extern "C" { fn objc_msgSend(); fn objc_msgSend_stret(); @@ -11,30 +13,26 @@ extern { fn objc_msgSendSuper_stret(); } -pub fn msg_send_fn() -> Imp { - // Double-word sized fundamental data types don't use stret, - // but any composite type larger than 4 bytes does. - // - - let type_id = TypeId::of::(); - if mem::size_of::() <= 4 || - type_id == TypeId::of::() || - type_id == TypeId::of::() || - type_id == TypeId::of::() { - objc_msgSend - } else { - objc_msgSend_stret - } -} - -pub fn msg_send_super_fn() -> Imp { - let type_id = TypeId::of::(); - if mem::size_of::() <= 4 || - type_id == TypeId::of::() || - type_id == TypeId::of::() || - type_id == TypeId::of::() { - objc_msgSendSuper - } else { - objc_msgSendSuper_stret - } +/// Double-word sized fundamental data types don't use stret, +/// but any composite type larger than 4 bytes does. +/// +impl MsgSendFn for T { + const MSG_SEND: Imp = { + if let Encoding::LongLong | Encoding::ULongLong | Encoding::Double = T::ENCODING { + objc_msgSend + } else if mem::size_of::() <= 4 { + objc_msgSend + } else { + objc_msgSend_stret + } + }; + const MSG_SEND_SUPER: Imp = { + if let Encoding::LongLong | Encoding::ULongLong | Encoding::Double = T::ENCODING { + objc_msgSendSuper + } else if mem::size_of::() <= 4 { + objc_msgSendSuper + } else { + objc_msgSendSuper_stret + } + }; } diff --git a/src/message/apple/arm64.rs b/src/message/apple/arm64.rs index f10812857..aa67e3410 100644 --- a/src/message/apple/arm64.rs +++ b/src/message/apple/arm64.rs @@ -1,18 +1,17 @@ +use super::MsgSendFn; use crate::runtime::Imp; +use crate::Encode; -extern { +// TODO: C-unwind +extern "C" { fn objc_msgSend(); fn objc_msgSendSuper(); } -pub fn msg_send_fn() -> Imp { - // stret is not even available in arm64. - // - - objc_msgSend -} - -pub fn msg_send_super_fn() -> Imp { - objc_msgSendSuper +/// stret is not even available in arm64. +/// +impl MsgSendFn for T { + const MSG_SEND: Imp = objc_msgSend; + const MSG_SEND_SUPER: Imp = objc_msgSendSuper; } diff --git a/src/message/apple/mod.rs b/src/message/apple/mod.rs index 34b6f14c0..c9c500b8e 100644 --- a/src/message/apple/mod.rs +++ b/src/message/apple/mod.rs @@ -1,7 +1,5 @@ -use std::any::Any; - -use crate::runtime::{Class, Object, Sel}; -use super::{Message, MessageArguments, MessageError, Super}; +use super::{Encode, Message, MessageArguments, MessageError, Super}; +use crate::runtime::{Class, Imp, Object, Sel}; #[cfg(target_arch = "x86")] #[path = "x86.rs"] @@ -16,25 +14,40 @@ mod arch; #[path = "arm64.rs"] mod arch; -use self::arch::{msg_send_fn, msg_send_super_fn}; +/// On the above architectures we can statically find the correct method to +/// call from the return type, by looking at it's Encode implementation. +trait MsgSendFn: Encode { + const MSG_SEND: Imp; + const MSG_SEND_SUPER: Imp; +} -pub unsafe fn send_unverified(obj: *const T, sel: Sel, args: A) - -> Result - where T: Message, A: MessageArguments, R: Any { +pub unsafe fn send_unverified(obj: *const T, sel: Sel, args: A) -> Result +where + T: Message, + A: MessageArguments, + R: Encode + 'static, +{ let receiver = obj as *mut T as *mut Object; - let msg_send_fn = msg_send_fn::(); - objc_try!({ - A::invoke(msg_send_fn, receiver, sel, args) - }) + let msg_send_fn = R::MSG_SEND; + objc_try!({ A::invoke(msg_send_fn, receiver, sel, args) }) } -pub unsafe fn send_super_unverified(obj: *const T, superclass: &Class, - sel: Sel, args: A) -> Result - where T: Message, A: MessageArguments, R: Any { - let sup = Super { receiver: obj as *mut T as *mut Object, superclass: superclass }; +pub unsafe fn send_super_unverified( + obj: *const T, + superclass: &Class, + sel: Sel, + args: A, +) -> Result +where + T: Message, + A: MessageArguments, + R: Encode + 'static, +{ + let sup = Super { + receiver: obj as *mut T as *mut Object, + superclass: superclass, + }; let receiver = &sup as *const Super as *mut Object; - let msg_send_fn = msg_send_super_fn::(); - objc_try!({ - A::invoke(msg_send_fn, receiver, sel, args) - }) + let msg_send_fn = R::MSG_SEND_SUPER; + objc_try!({ A::invoke(msg_send_fn, receiver, sel, args) }) } diff --git a/src/message/apple/x86.rs b/src/message/apple/x86.rs index ddb988fb1..c3a64d3bb 100644 --- a/src/message/apple/x86.rs +++ b/src/message/apple/x86.rs @@ -1,9 +1,11 @@ -use std::any::{Any, TypeId}; -use std::mem; +use core::mem; +use super::MsgSendFn; use crate::runtime::Imp; +use crate::{Encode, Encoding}; -extern { +// TODO: C-unwind +extern "C" { fn objc_msgSend(); fn objc_msgSend_fpret(); fn objc_msgSend_stret(); @@ -12,29 +14,25 @@ extern { fn objc_msgSendSuper_stret(); } -pub fn msg_send_fn() -> Imp { - // Structures 1 or 2 bytes in size are placed in EAX. - // Structures 4 or 8 bytes in size are placed in: EAX and EDX. - // Structures of other sizes are placed at the address supplied by the caller. - // - - let type_id = TypeId::of::(); - let size = mem::size_of::(); - if type_id == TypeId::of::() || - type_id == TypeId::of::() { - objc_msgSend_fpret - } else if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 { - objc_msgSend - } else { - objc_msgSend_stret - } -} - -pub fn msg_send_super_fn() -> Imp { - let size = mem::size_of::(); - if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 { - objc_msgSendSuper - } else { - objc_msgSendSuper_stret - } +impl MsgSendFn for T { + /// Structures 1 or 2 bytes in size are placed in EAX. + /// Structures 4 or 8 bytes in size are placed in: EAX and EDX. + /// Structures of other sizes are placed at the address supplied by the caller. + /// + const MSG_SEND: Imp = { + if let Encoding::Float | Encoding::Double = T::ENCODING { + objc_msgSend_fpret + } else if let 0 | 1 | 2 | 4 | 8 = mem::size_of::() { + objc_msgSend + } else { + objc_msgSend_stret + } + }; + const MSG_SEND_SUPER: Imp = { + if let 0 | 1 | 2 | 4 | 8 = mem::size_of::() { + objc_msgSendSuper + } else { + objc_msgSendSuper_stret + } + }; } diff --git a/src/message/apple/x86_64.rs b/src/message/apple/x86_64.rs index 11db0e954..0d63e6823 100644 --- a/src/message/apple/x86_64.rs +++ b/src/message/apple/x86_64.rs @@ -1,8 +1,11 @@ -use std::mem; +use core::mem; +use super::MsgSendFn; use crate::runtime::Imp; +use crate::Encode; -extern { +// TODO: C-unwind +extern "C" { fn objc_msgSend(); fn objc_msgSend_stret(); @@ -10,23 +13,23 @@ extern { fn objc_msgSendSuper_stret(); } -pub fn msg_send_fn() -> Imp { - // If the size of an object is larger than two eightbytes, it has class MEMORY. - // If the type has class MEMORY, then the caller provides space for the return - // value and passes the address of this storage. - // - - if mem::size_of::() <= 16 { - objc_msgSend - } else { - objc_msgSend_stret - } -} - -pub fn msg_send_super_fn() -> Imp { - if mem::size_of::() <= 16 { - objc_msgSendSuper - } else { - objc_msgSendSuper_stret - } +/// If the size of an object is larger than two eightbytes, it has class MEMORY. +/// If the type has class MEMORY, then the caller provides space for the return +/// value and passes the address of this storage. +/// +impl MsgSendFn for T { + const MSG_SEND: Imp = { + if mem::size_of::() <= 16 { + objc_msgSend + } else { + objc_msgSend_stret + } + }; + const MSG_SEND_SUPER: Imp = { + if mem::size_of::() <= 16 { + objc_msgSendSuper + } else { + objc_msgSendSuper_stret + } + }; } diff --git a/src/message/gnustep.rs b/src/message/gnustep.rs index 382ef8625..5c2d164c8 100644 --- a/src/message/gnustep.rs +++ b/src/message/gnustep.rs @@ -1,35 +1,42 @@ -use std::any::Any; -use std::mem; +use core::mem; -use crate::runtime::{Class, Object, Imp, Sel}; use super::{Message, MessageArguments, MessageError, Super}; +use crate::runtime::{Class, Imp, Object, Sel}; -extern { +extern "C" { fn objc_msg_lookup(receiver: *mut Object, op: Sel) -> Imp; fn objc_msg_lookup_super(sup: *const Super, sel: Sel) -> Imp; } -pub unsafe fn send_unverified(obj: *const T, sel: Sel, args: A) - -> Result - where T: Message, A: MessageArguments, R: Any { +pub unsafe fn send_unverified(obj: *const T, sel: Sel, args: A) -> Result +where + T: Message, + A: MessageArguments, +{ if obj.is_null() { return mem::zeroed(); } let receiver = obj as *mut T as *mut Object; let msg_send_fn = objc_msg_lookup(receiver, sel); - objc_try!({ - A::invoke(msg_send_fn, receiver, sel, args) - }) + objc_try!({ A::invoke(msg_send_fn, receiver, sel, args) }) } -pub unsafe fn send_super_unverified(obj: *const T, superclass: &Class, - sel: Sel, args: A) -> Result - where T: Message, A: MessageArguments, R: Any { +pub unsafe fn send_super_unverified( + obj: *const T, + superclass: &Class, + sel: Sel, + args: A, +) -> Result +where + T: Message, + A: MessageArguments, +{ let receiver = obj as *mut T as *mut Object; - let sup = Super { receiver: receiver, superclass: superclass }; + let sup = Super { + receiver: receiver, + superclass: superclass, + }; let msg_send_fn = objc_msg_lookup_super(&sup, sel); - objc_try!({ - A::invoke(msg_send_fn, receiver, sel, args) - }) + objc_try!({ A::invoke(msg_send_fn, receiver, sel, args) }) } diff --git a/src/message/mod.rs b/src/message/mod.rs index 86f80dcee..5c6da8826 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -1,4 +1,3 @@ -use std::any::Any; use std::error::Error; use std::fmt; use std::mem; @@ -8,20 +7,22 @@ use crate::{Encode, EncodeArguments}; #[cfg(feature = "exception")] macro_rules! objc_try { - ($b:block) => ( - $crate::exception::catch_exception(|| $b).map_err(|exception| + ($b:block) => { + $crate::exception::catch_exception(|| $b).map_err(|exception| { if exception.is_null() { MessageError("Uncaught exception nil".to_owned()) } else { MessageError(format!("Uncaught exception {:?}", &**exception)) } - ) - ) + }) + }; } #[cfg(not(feature = "exception"))] macro_rules! objc_try { - ($b:block) => (Ok($b)) + ($b:block) => { + Ok($b) + }; } mod verify; @@ -33,8 +34,8 @@ mod platform; #[path = "gnustep.rs"] mod platform; -use self::platform::{send_unverified, send_super_unverified}; -use self::verify::{VerificationError, verify_message_signature}; +use self::platform::{send_super_unverified, send_unverified}; +use self::verify::{verify_message_signature, VerificationError}; /// Specifies the superclass of an instance. #[repr(C)] @@ -59,17 +60,23 @@ pub unsafe trait Message { `msg_send!` macro rather than this method. */ #[cfg(not(feature = "verify_message"))] - unsafe fn send_message(&self, sel: Sel, args: A) - -> Result - where Self: Sized, A: MessageArguments, R: Any { + unsafe fn send_message(&self, sel: Sel, args: A) -> Result + where + Self: Sized, + A: MessageArguments, + R: Encode + 'static, + { send_message(self, sel, args) } + #[allow(missing_docs)] #[cfg(feature = "verify_message")] - unsafe fn send_message(&self, sel: Sel, args: A) - -> Result - where Self: Sized, A: MessageArguments + EncodeArguments, - R: Any + Encode { + unsafe fn send_message(&self, sel: Sel, args: A) -> Result + where + Self: Sized, + A: MessageArguments + EncodeArguments, + R: Encode + 'static, + { send_message(self, sel, args) } @@ -97,16 +104,19 @@ pub unsafe trait Message { ``` */ fn verify_message(&self, sel: Sel) -> Result<(), MessageError> - where Self: Sized, A: EncodeArguments, R: Encode { + 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) + verify_message_signature::(obj.class(), sel).map_err(MessageError::from) } } -unsafe impl Message for Object { } +unsafe impl Message for Object {} -unsafe impl Message for Class { } +unsafe impl Message for Class {} /// Types that may be used as the arguments of an Objective-C message. pub trait MessageArguments: Sized { @@ -115,15 +125,13 @@ pub trait MessageArguments: Sized { /// This method is the primitive used when sending messages and should not /// be called directly; instead, use the `msg_send!` macro or, in cases /// with a dynamic selector, the `Message::send_message` method. - unsafe fn invoke(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R - where R: Any; + unsafe fn invoke(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R; } macro_rules! message_args_impl { ($($a:ident : $t:ident),*) => ( impl<$($t),*> MessageArguments for ($($t,)*) { - unsafe fn invoke(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R - where R: Any { + unsafe fn invoke(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R { let imp: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R = mem::transmute(imp); imp(obj, sel $(, $a)*) @@ -143,8 +151,33 @@ 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); +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 +); /** An error encountered while attempting to send a message. @@ -179,19 +212,24 @@ impl<'a> From> for MessageError { #[doc(hidden)] #[inline(always)] #[cfg(not(feature = "verify_message"))] -pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) - -> Result - where T: Message, A: MessageArguments, R: Any { +pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) -> Result +where + T: Message, + A: MessageArguments, + R: Encode + 'static, +{ send_unverified(obj, sel, args) } #[doc(hidden)] #[inline(always)] #[cfg(feature = "verify_message")] -pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) - -> Result - where T: Message, A: MessageArguments + EncodeArguments, - R: Any + Encode { +pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) -> Result +where + T: Message, + A: MessageArguments + EncodeArguments, + R: Encode + 'static, +{ let cls = if obj.is_null() { return Err(VerificationError::NilReceiver(sel).into()); } else { @@ -205,19 +243,34 @@ pub unsafe fn send_message(obj: *const T, sel: Sel, args: A) #[doc(hidden)] #[inline(always)] #[cfg(not(feature = "verify_message"))] -pub unsafe fn send_super_message(obj: *const T, superclass: &Class, - sel: Sel, args: A) -> Result - where T: Message, A: MessageArguments, R: Any { +pub unsafe fn send_super_message( + obj: *const T, + superclass: &Class, + sel: Sel, + args: A, +) -> Result +where + T: Message, + A: MessageArguments, + R: Encode + 'static, +{ send_super_unverified(obj, superclass, sel, args) } #[doc(hidden)] #[inline(always)] #[cfg(feature = "verify_message")] -pub unsafe fn send_super_message(obj: *const T, superclass: &Class, - sel: Sel, args: A) -> Result - where T: Message, A: MessageArguments + EncodeArguments, - R: Any + Encode { +pub unsafe fn send_super_message( + obj: *const T, + superclass: &Class, + sel: Sel, + args: A, +) -> Result +where + T: Message, + A: MessageArguments + EncodeArguments, + R: Encode + 'static, +{ if obj.is_null() { return Err(VerificationError::NilReceiver(sel).into()); } @@ -228,9 +281,8 @@ pub unsafe fn send_super_message(obj: *const T, superclass: &Class, #[cfg(test)] mod tests { + use super::*; use crate::test_utils; - use crate::runtime::Object; - use super::Message; #[test] fn test_send_message() { @@ -245,10 +297,13 @@ mod tests { #[test] fn test_send_message_stret() { let obj = test_utils::custom_object(); - let result: test_utils::CustomStruct = unsafe { - msg_send![obj, customStruct] + let result: test_utils::CustomStruct = unsafe { msg_send![obj, customStruct] }; + let expected = test_utils::CustomStruct { + a: 1, + b: 2, + c: 3, + d: 4, }; - let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 }; assert!(result == expected); } @@ -256,19 +311,13 @@ mod tests { #[test] fn test_send_message_nil() { let nil: *mut Object = ::std::ptr::null_mut(); - let result: usize = unsafe { - msg_send![nil, hash] - }; + let result: usize = unsafe { msg_send![nil, hash] }; assert!(result == 0); - let result: *mut Object = unsafe { - msg_send![nil, description] - }; + let result: *mut Object = unsafe { msg_send![nil, description] }; assert!(result.is_null()); - let result: f64 = unsafe { - msg_send![nil, doubleValue] - }; + let result: f64 = unsafe { msg_send![nil, doubleValue] }; assert!(result == 0.0); } diff --git a/src/message/verify.rs b/src/message/verify.rs index 6bafabe16..06a5a6b37 100644 --- a/src/message/verify.rs +++ b/src/message/verify.rs @@ -1,7 +1,7 @@ use std::fmt; use crate::runtime::{Class, Method, Object, Sel}; -use crate::{Encode, Encoding, EncodeArguments}; +use crate::{Encode, EncodeArguments, Encoding}; pub enum VerificationError<'a> { NilReceiver(Sel), @@ -22,26 +22,44 @@ impl<'a> fmt::Display for VerificationError<'a> { } 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()) + 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) + 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) + 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<(), VerificationError> - where A: EncodeArguments, R: Encode { +pub fn verify_message_signature(cls: &Class, sel: Sel) -> Result<(), VerificationError> +where + A: EncodeArguments, + R: Encode, +{ let method = match cls.instance_method(sel) { Some(method) => method, None => return Err(VerificationError::MethodNotFound(cls, sel)), diff --git a/src/rc/autorelease.rs b/src/rc/autorelease.rs index 17df8af39..7c7be6952 100644 --- a/src/rc/autorelease.rs +++ b/src/rc/autorelease.rs @@ -1,5 +1,5 @@ +use crate::runtime::{objc_autoreleasePoolPop, objc_autoreleasePoolPush}; use std::os::raw::c_void; -use crate::runtime::{objc_autoreleasePoolPush, objc_autoreleasePoolPop}; // we use a struct to ensure that objc_autoreleasePoolPop during unwinding. struct AutoReleaseHelper { @@ -8,7 +8,9 @@ struct AutoReleaseHelper { impl AutoReleaseHelper { unsafe fn new() -> Self { - AutoReleaseHelper { context: objc_autoreleasePoolPush() } + AutoReleaseHelper { + context: objc_autoreleasePoolPush(), + } } } diff --git a/src/rc/mod.rs b/src/rc/mod.rs index c703f585d..b609eb55a 100644 --- a/src/rc/mod.rs +++ b/src/rc/mod.rs @@ -40,20 +40,20 @@ assert!(weak.load().is_null()); ``` */ +mod autorelease; mod strong; mod weak; -mod autorelease; +pub use self::autorelease::autoreleasepool; pub use self::strong::StrongPtr; pub use self::weak::WeakPtr; -pub use self::autorelease::autoreleasepool; // These tests use NSObject, which isn't present for GNUstep #[cfg(all(test, any(target_os = "macos", target_os = "ios")))] mod tests { - use crate::runtime::Object; - use super::StrongPtr; use super::autoreleasepool; + use super::StrongPtr; + use crate::runtime::Object; #[test] fn test_strong_clone() { @@ -61,9 +61,7 @@ mod tests { unsafe { msg_send![obj, retainCount] } } - let obj = unsafe { - StrongPtr::new(msg_send![class!(NSObject), new]) - }; + let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) }; assert!(retain_count(*obj) == 1); let cloned = obj.clone(); @@ -76,9 +74,7 @@ mod tests { #[test] fn test_weak() { - let obj = unsafe { - StrongPtr::new(msg_send![class!(NSObject), new]) - }; + let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) }; let weak = obj.weak(); let strong = weak.load(); @@ -91,9 +87,7 @@ mod tests { #[test] fn test_weak_copy() { - let obj = unsafe { - StrongPtr::new(msg_send![class!(NSObject), new]) - }; + let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) }; let weak = obj.weak(); let weak2 = weak.clone(); @@ -103,9 +97,7 @@ mod tests { #[test] fn test_autorelease() { - let obj = unsafe { - StrongPtr::new(msg_send![class!(NSObject), new]) - }; + let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) }; fn retain_count(obj: *mut Object) -> usize { unsafe { msg_send![obj, retainCount] } @@ -113,8 +105,8 @@ mod tests { let cloned = obj.clone(); autoreleasepool(|| { - obj.autorelease(); - assert!(retain_count(*cloned) == 2); + obj.autorelease(); + assert!(retain_count(*cloned) == 2); }); // make sure that the autoreleased value has been released diff --git a/src/rc/strong.rs b/src/rc/strong.rs index d6e417172..4536586ca 100644 --- a/src/rc/strong.rs +++ b/src/rc/strong.rs @@ -2,8 +2,8 @@ use std::fmt; use std::mem; use std::ops::Deref; -use crate::runtime::{Object, self}; use super::WeakPtr; +use crate::runtime::{self, Object}; /// A pointer that strongly references an object, ensuring it won't be deallocated. pub struct StrongPtr(*mut Object); @@ -52,9 +52,7 @@ impl Drop for StrongPtr { impl Clone for StrongPtr { fn clone(&self) -> StrongPtr { - unsafe { - StrongPtr::retain(self.0) - } + unsafe { StrongPtr::retain(self.0) } } } diff --git a/src/rc/weak.rs b/src/rc/weak.rs index aa2f693e6..4a748f9f4 100644 --- a/src/rc/weak.rs +++ b/src/rc/weak.rs @@ -1,8 +1,8 @@ use std::cell::UnsafeCell; use std::ptr; -use crate::runtime::{Object, self}; use super::StrongPtr; +use crate::runtime::{self, Object}; // Our pointer must have the same address even if we are moved, so Box it. // Although loading the WeakPtr may modify the pointer, it is thread safe, diff --git a/src/runtime.rs b/src/runtime.rs index dd8f3aa09..7e2092e60 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -3,12 +3,12 @@ //! For more information on foreign functions, see Apple's documentation: //! +use malloc_buf::Malloc; use std::ffi::{CStr, CString}; use std::fmt; use std::os::raw::{c_char, c_int, c_uint, c_void}; use std::ptr; use std::str; -use malloc_buf::Malloc; use crate::Encode; @@ -62,7 +62,7 @@ pub struct Class { /// A type that represents an Objective-C protocol. #[repr(C)] pub struct Protocol { - _priv: PrivateMarker + _priv: PrivateMarker, } /// A type that represents an instance of a class. @@ -72,10 +72,11 @@ pub struct Object { } /// A pointer to the start of a method implementation. -pub type Imp = unsafe extern fn(); +pub type Imp = unsafe extern "C" fn(); +#[allow(missing_docs)] #[link(name = "objc", kind = "dylib")] -extern { +extern "C" { pub fn sel_registerName(name: *const c_char) -> Sel; pub fn sel_getName(sel: Sel) -> *const c_char; @@ -87,12 +88,23 @@ extern { pub fn class_copyMethodList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Method; pub fn class_copyIvarList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Ivar; pub fn class_addMethod(cls: *mut Class, name: Sel, imp: Imp, types: *const c_char) -> BOOL; - pub fn class_addIvar(cls: *mut Class, name: *const c_char, size: usize, alignment: u8, types: *const c_char) -> BOOL; + pub fn class_addIvar( + cls: *mut Class, + name: *const c_char, + size: usize, + alignment: u8, + types: *const c_char, + ) -> BOOL; pub fn class_addProtocol(cls: *mut Class, proto: *const Protocol) -> BOOL; pub fn class_conformsToProtocol(cls: *const Class, proto: *const Protocol) -> BOOL; - pub fn class_copyProtocolList(cls: *const Class, outCount: *mut c_uint) -> *mut *const Protocol; - - pub fn objc_allocateClassPair(superclass: *const Class, name: *const c_char, extraBytes: usize) -> *mut Class; + pub fn class_copyProtocolList(cls: *const Class, outCount: *mut c_uint) + -> *mut *const Protocol; + + pub fn objc_allocateClassPair( + superclass: *const Class, + name: *const c_char, + extraBytes: usize, + ) -> *mut Class; pub fn objc_disposeClassPair(cls: *mut Class); pub fn objc_registerClassPair(cls: *mut Class); @@ -111,12 +123,20 @@ extern { pub fn objc_autoreleasePoolPush() -> *mut c_void; pub fn objc_autoreleasePoolPop(context: *mut c_void); - pub fn protocol_addMethodDescription(proto: *mut Protocol, name: Sel, types: *const c_char, isRequiredMethod: BOOL, - isInstanceMethod: BOOL); + pub fn protocol_addMethodDescription( + proto: *mut Protocol, + name: Sel, + types: *const c_char, + isRequiredMethod: BOOL, + isInstanceMethod: BOOL, + ); pub fn protocol_addProtocol(proto: *mut Protocol, addition: *const Protocol); pub fn protocol_getName(proto: *const Protocol) -> *const c_char; pub fn protocol_isEqual(proto: *const Protocol, other: *const Protocol) -> BOOL; - pub fn protocol_copyProtocolList(proto: *const Protocol, outCount: *mut c_uint) -> *mut *const Protocol; + pub fn protocol_copyProtocolList( + proto: *const Protocol, + outCount: *mut c_uint, + ) -> *mut *const Protocol; pub fn protocol_conformsToProtocol(proto: *const Protocol, other: *const Protocol) -> BOOL; pub fn ivar_getName(ivar: *const Ivar) -> *const c_char; @@ -146,16 +166,12 @@ impl Sel { /// maps the method name to a selector, and returns the selector value. pub fn register(name: &str) -> Sel { let name = CString::new(name).unwrap(); - unsafe { - sel_registerName(name.as_ptr()) - } + unsafe { sel_registerName(name.as_ptr()) } } /// Returns the name of the method specified by self. pub fn name(&self) -> &str { - let name = unsafe { - CStr::from_ptr(sel_getName(*self)) - }; + let name = unsafe { CStr::from_ptr(sel_getName(*self)) }; str::from_utf8(name.to_bytes()).unwrap() } @@ -164,9 +180,7 @@ impl Sel { /// This is almost never what you want; use `Sel::register()` instead. #[inline] pub unsafe fn from_ptr(ptr: *const c_void) -> Sel { - Sel { - ptr: ptr, - } + Sel { ptr: ptr } } /// Returns a pointer to the raw selector. @@ -182,16 +196,18 @@ impl PartialEq for Sel { } } -impl Eq for Sel { } +impl Eq for Sel {} // Sel is safe to share across threads because it is immutable -unsafe impl Sync for Sel { } -unsafe impl Send for Sel { } +unsafe impl Sync for Sel {} +unsafe impl Send for Sel {} -impl Copy for Sel { } +impl Copy for Sel {} impl Clone for Sel { - fn clone(&self) -> Sel { *self } + fn clone(&self) -> Sel { + *self + } } impl fmt::Debug for Sel { @@ -203,25 +219,19 @@ impl fmt::Debug for Sel { impl Ivar { /// Returns the name of self. pub fn name(&self) -> &str { - let name = unsafe { - CStr::from_ptr(ivar_getName(self)) - }; + let name = unsafe { CStr::from_ptr(ivar_getName(self)) }; str::from_utf8(name.to_bytes()).unwrap() } /// Returns the offset of self. pub fn offset(&self) -> isize { - let offset = unsafe { - ivar_getOffset(self) - }; + let offset = unsafe { ivar_getOffset(self) }; offset as isize } /// Returns the `Encoding` of self. pub fn type_encoding(&self) -> &str { - let encoding = unsafe { - CStr::from_ptr(ivar_getTypeEncoding(self)) - }; + let encoding = unsafe { CStr::from_ptr(ivar_getTypeEncoding(self)) }; str::from_utf8(encoding.to_bytes()).unwrap() } } @@ -229,9 +239,7 @@ impl Ivar { impl Method { /// Returns the name of self. pub fn name(&self) -> Sel { - unsafe { - method_getName(self) - } + unsafe { method_getName(self) } } /// Returns the `Encoding` of self's return type. @@ -257,16 +265,12 @@ impl Method { /// Returns the number of arguments accepted by self. pub fn arguments_count(&self) -> usize { - unsafe { - method_getNumberOfArguments(self) as usize - } + unsafe { method_getNumberOfArguments(self) as usize } } /// Returns the implementation of self. pub fn implementation(&self) -> Imp { - unsafe { - method_getImplementation(self) - } + unsafe { method_getImplementation(self) } } } @@ -277,7 +281,11 @@ impl Class { let name = CString::new(name).unwrap(); unsafe { let cls = objc_getClass(name.as_ptr()); - if cls.is_null() { None } else { Some(&*cls) } + if cls.is_null() { + None + } else { + Some(&*cls) + } } } @@ -292,16 +300,12 @@ impl Class { /// Returns the total number of registered classes. pub fn classes_count() -> usize { - unsafe { - objc_getClassList(ptr::null_mut(), 0) as usize - } + unsafe { objc_getClassList(ptr::null_mut(), 0) as usize } } /// Returns the name of self. pub fn name(&self) -> &str { - let name = unsafe { - CStr::from_ptr(class_getName(self)) - }; + let name = unsafe { CStr::from_ptr(class_getName(self)) }; str::from_utf8(name.to_bytes()).unwrap() } @@ -309,7 +313,11 @@ impl Class { pub fn superclass(&self) -> Option<&Class> { unsafe { let superclass = class_getSuperclass(self); - if superclass.is_null() { None } else { Some(&*superclass) } + if superclass.is_null() { + None + } else { + Some(&*superclass) + } } } @@ -323,9 +331,7 @@ impl Class { /// Returns the size of instances of self. pub fn instance_size(&self) -> usize { - unsafe { - class_getInstanceSize(self) as usize - } + unsafe { class_getInstanceSize(self) as usize } } /// Returns a specified instance method for self, or `None` if self and @@ -334,7 +340,11 @@ impl Class { pub fn instance_method(&self, sel: Sel) -> Option<&Method> { unsafe { let method = class_getInstanceMethod(self, sel); - if method.is_null() { None } else { Some(&*method) } + if method.is_null() { + None + } else { + Some(&*method) + } } } @@ -344,7 +354,11 @@ impl Class { let name = CString::new(name).unwrap(); unsafe { let ivar = class_getInstanceVariable(self, name.as_ptr()); - if ivar.is_null() { None } else { Some(&*ivar) } + if ivar.is_null() { + None + } else { + Some(&*ivar) + } } } @@ -355,7 +369,6 @@ impl Class { let methods = class_copyMethodList(self, &mut count); Malloc::from_array(methods as *mut _, count as usize) } - } /// Checks whether this class conforms to the specified protocol. @@ -390,7 +403,7 @@ impl PartialEq for Class { } } -impl Eq for Class { } +impl Eq for Class {} impl fmt::Debug for Class { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -405,7 +418,11 @@ impl Protocol { let name = CString::new(name).unwrap(); unsafe { let proto = objc_getProtocol(name.as_ptr()); - if proto.is_null() { None } else { Some(&*proto) } + if proto.is_null() { + None + } else { + Some(&*proto) + } } } @@ -434,9 +451,7 @@ impl Protocol { /// Returns the name of self. pub fn name(&self) -> &str { - let name = unsafe { - CStr::from_ptr(protocol_getName(self)) - }; + let name = unsafe { CStr::from_ptr(protocol_getName(self)) }; str::from_utf8(name.to_bytes()).unwrap() } } @@ -447,7 +462,7 @@ impl PartialEq for Protocol { } } -impl Eq for Protocol { } +impl Eq for Protocol {} impl fmt::Debug for Protocol { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -458,16 +473,17 @@ impl fmt::Debug for Protocol { impl Object { /// Returns the class of self. pub fn class(&self) -> &Class { - unsafe { - &*object_getClass(self) - } + unsafe { &*object_getClass(self) } } /// Returns a reference to the ivar of self with the given name. /// Panics if self has no ivar with the given name. /// Unsafe because the caller must ensure that the ivar is actually /// of type `T`. - pub unsafe fn get_ivar(&self, name: &str) -> &T where T: Encode { + pub unsafe fn get_ivar(&self, name: &str) -> &T + where + T: Encode, + { let offset = { let cls = self.class(); match cls.instance_variable(name) { @@ -490,7 +506,9 @@ impl Object { /// Unsafe because the caller must ensure that the ivar is actually /// of type `T`. pub unsafe fn get_mut_ivar(&mut self, name: &str) -> &mut T - where T: Encode { + where + T: Encode, + { let offset = { let cls = self.class(); match cls.instance_variable(name) { @@ -513,7 +531,9 @@ impl Object { /// Unsafe because the caller must ensure that the ivar is actually /// of type `T`. pub unsafe fn set_ivar(&mut self, name: &str, value: T) - where T: Encode { + where + T: Encode, + { *self.get_mut_ivar::(name) = value; } } @@ -526,9 +546,9 @@ impl fmt::Debug for Object { #[cfg(test)] mod tests { + use super::{Class, Protocol, Sel}; use crate::test_utils; use crate::Encode; - use super::{Class, Protocol, Sel}; #[test] fn test_ivar() { @@ -593,9 +613,7 @@ mod tests { #[test] fn test_protocol_method() { let class = test_utils::custom_class(); - let result: i32 = unsafe { - msg_send![class, addNumber:1 toNumber:2] - }; + let result: i32 = unsafe { msg_send![class, addNumber:1 toNumber:2] }; assert_eq!(result, 3); } diff --git a/src/test_utils.rs b/src/test_utils.rs index 226be9fe5..128954935 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -3,7 +3,7 @@ use std::os::raw::c_char; use std::sync::Once; use crate::declare::{ClassDecl, ProtocolDecl}; -use crate::runtime::{Class, Object, Protocol, Sel, self}; +use crate::runtime::{self, Class, Object, Protocol, Sel}; use crate::{Encode, Encoding}; pub struct CustomObject { @@ -12,9 +12,7 @@ pub struct CustomObject { impl CustomObject { fn new(class: &Class) -> Self { - let obj = unsafe { - runtime::class_createInstance(class, 0) - }; + let obj = unsafe { runtime::class_createInstance(class, 0) }; CustomObject { obj: obj } } } @@ -42,6 +40,7 @@ impl Drop for CustomObject { } #[derive(Eq, PartialEq)] +#[repr(C)] pub struct CustomStruct { pub a: u64, pub b: u64, @@ -50,8 +49,10 @@ pub struct CustomStruct { } unsafe impl Encode for CustomStruct { - const ENCODING: Encoding<'static> = - Encoding::Struct("CustomStruct", &[u64::ENCODING, u64::ENCODING, u64::ENCODING, u64::ENCODING]); + const ENCODING: Encoding<'static> = Encoding::Struct( + "CustomStruct", + &[u64::ENCODING, u64::ENCODING, u64::ENCODING, u64::ENCODING], + ); } pub fn custom_class() -> &'static Class { @@ -59,7 +60,7 @@ pub fn custom_class() -> &'static Class { REGISTER_CUSTOM_CLASS.call_once(|| { // The runtime will call this method, so it has to be implemented - extern fn custom_obj_class_initialize(_this: &Class, _cmd: Sel) { } + extern "C" fn custom_obj_class_initialize(_this: &Class, _cmd: Sel) {} let mut decl = ClassDecl::root("CustomObject", custom_obj_class_initialize).unwrap(); let proto = custom_protocol(); @@ -67,43 +68,58 @@ pub fn custom_class() -> &'static Class { decl.add_protocol(proto); decl.add_ivar::("_foo"); - extern fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) { - unsafe { this.set_ivar::("_foo", foo); } + extern "C" fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) { + unsafe { + this.set_ivar::("_foo", foo); + } } - extern fn custom_obj_get_foo(this: &Object, _cmd: Sel) -> u32 { + extern "C" fn custom_obj_get_foo(this: &Object, _cmd: Sel) -> u32 { unsafe { *this.get_ivar::("_foo") } } - extern fn custom_obj_get_struct(_this: &Object, _cmd: Sel) -> CustomStruct { - CustomStruct { a: 1, b: 2, c: 3, d: 4 } + extern "C" fn custom_obj_get_struct(_this: &Object, _cmd: Sel) -> CustomStruct { + CustomStruct { + a: 1, + b: 2, + c: 3, + d: 4, + } } - extern fn custom_obj_class_method(_this: &Class, _cmd: Sel) -> u32 { + extern "C" fn custom_obj_class_method(_this: &Class, _cmd: Sel) -> u32 { 7 } - extern fn custom_obj_set_bar(this: &mut Object, _cmd: Sel, bar: u32) { - unsafe { this.set_ivar::("_foo", bar) ;} + extern "C" fn custom_obj_set_bar(this: &mut Object, _cmd: Sel, bar: u32) { + unsafe { + this.set_ivar::("_foo", bar); + } } - extern fn custom_obj_add_number_to_number(_this: &Class, _cmd: Sel, fst: i32, snd: i32) -> i32 { + extern "C" fn custom_obj_add_number_to_number( + _this: &Class, + _cmd: Sel, + fst: i32, + snd: i32, + ) -> i32 { fst + snd } unsafe { - let set_foo: extern fn(&mut Object, Sel, u32) = custom_obj_set_foo; + let set_foo: extern "C" fn(&mut Object, Sel, u32) = custom_obj_set_foo; decl.add_method(sel!(setFoo:), set_foo); - let get_foo: extern fn(&Object, Sel) -> u32 = custom_obj_get_foo; + let get_foo: extern "C" fn(&Object, Sel) -> u32 = custom_obj_get_foo; decl.add_method(sel!(foo), get_foo); - let get_struct: extern fn(&Object, Sel) -> CustomStruct = custom_obj_get_struct; + let get_struct: extern "C" fn(&Object, Sel) -> CustomStruct = custom_obj_get_struct; decl.add_method(sel!(customStruct), get_struct); - let class_method: extern fn(&Class, Sel) -> u32 = custom_obj_class_method; + let class_method: extern "C" fn(&Class, Sel) -> u32 = custom_obj_class_method; decl.add_class_method(sel!(classFoo), class_method); - let protocol_instance_method: extern fn(&mut Object, Sel, u32) = custom_obj_set_bar; + let protocol_instance_method: extern "C" fn(&mut Object, Sel, u32) = custom_obj_set_bar; decl.add_method(sel!(setBar:), protocol_instance_method); - let protocol_class_method: extern fn(&Class, Sel, i32, i32) -> i32 = custom_obj_add_number_to_number; + let protocol_class_method: extern "C" fn(&Class, Sel, i32, i32) -> i32 = + custom_obj_add_number_to_number; decl.add_class_method(sel!(addNumber:toNumber:), protocol_class_method); } @@ -156,15 +172,13 @@ pub fn custom_subclass() -> &'static Class { let superclass = custom_class(); let mut decl = ClassDecl::new("CustomSubclassObject", superclass).unwrap(); - extern fn custom_subclass_get_foo(this: &Object, _cmd: Sel) -> u32 { - let foo: u32 = unsafe { - msg_send![super(this, custom_class()), foo] - }; + extern "C" fn custom_subclass_get_foo(this: &Object, _cmd: Sel) -> u32 { + let foo: u32 = unsafe { msg_send![super(this, custom_class()), foo] }; foo + 2 } unsafe { - let get_foo: extern fn(&Object, Sel) -> u32 = custom_subclass_get_foo; + let get_foo: extern "C" fn(&Object, Sel) -> u32 = custom_subclass_get_foo; decl.add_method(sel!(foo), get_foo); } diff --git a/tests-ios/prelude.rs b/tests-ios/prelude.rs index ed541de3a..2eabd4c83 100644 --- a/tests-ios/prelude.rs +++ b/tests-ios/prelude.rs @@ -1,9 +1,9 @@ #[macro_use] extern crate objc; -pub use objc::*; -use objc::runtime::*; use objc::rc::*; +use objc::runtime::*; +pub use objc::*; #[path = "../src/test_utils.rs"] mod test_utils; diff --git a/tests/use_macros.rs b/tests/use_macros.rs index 7ebe28fe2..b078503f0 100644 --- a/tests/use_macros.rs +++ b/tests/use_macros.rs @@ -2,8 +2,8 @@ extern crate objc; -use objc::{class, msg_send, sel}; use objc::runtime::Object; +use objc::{class, msg_send, sel}; #[test] fn use_class_and_msg_send() { @@ -20,4 +20,3 @@ fn use_sel() { let _sel = sel!(description); let _sel = sel!(setObject:forKey:); } - diff --git a/travis_install.sh b/travis_install.sh deleted file mode 100755 index 13b0fc330..000000000 --- a/travis_install.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /usr/bin/env sh - -set -eu - -gnustep_install() { - git clone -b 1.9 https://github.com/gnustep/libobjc2.git - mkdir libobjc2/build - cd libobjc2/build - export CC="clang" - export CXX="clang++" - cmake -DCMAKE_INSTALL_PREFIX:PATH=$HOME/libobjc2_staging ../ - make install -} - -for arch in $IOS_ARCHS; do - rustup target add "${arch}-apple-ios" -done - -if [ -n "$IOS_ARCHS" ]; then - curl -LO https://github.com/SSheldon/rust-test-ios/releases/download/0.1.1/rust-test-ios - chmod +x rust-test-ios -fi - -if [ "$TRAVIS_OS_NAME" = "linux" ]; then - gnustep_install -fi diff --git a/travis_test.sh b/travis_test.sh deleted file mode 100755 index 1e0999389..000000000 --- a/travis_test.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /usr/bin/env sh - -set -eu - -if [ -z "$IOS_ARCHS" ]; then - cargo build --verbose --features "$FEATURES" - cargo test --verbose --features "$FEATURES" -else - ./rust-test-ios -fi