diff --git a/Cargo.toml b/Cargo.toml index 47b27aed7..5fac7544e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "objc_encode", "objc_exception", "objc_foundation", + "objc_foundation_derive", "objc_id", ] exclude = ["objc/tests-ios"] diff --git a/README.md b/README.md new file mode 100644 index 000000000..5e43873f7 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# Objective-C in Rust + +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) diff --git a/objc/Cargo.toml b/objc/Cargo.toml index 83eaa46e5..f3748961d 100644 --- a/objc/Cargo.toml +++ b/objc/Cargo.toml @@ -1,19 +1,22 @@ [package] name = "objc" -version = "0.2.7" -authors = ["Steven Sheldon"] +version = "0.2.7" # Remember to update html_root_url in lib.rs +authors = ["Steven Sheldon", "Mads Marquart "] edition = "2018" -description = "Objective-C Runtime bindings and wrapper for Rust." -keywords = ["objective-c", "osx", "ios", "cocoa", "uikit"] +description = "Objective-C runtime bindings and interface." +keywords = ["objective-c", "macos", "ios", "objc_msgSend"] +categories = [ + "api-bindings", + "development-tools::ffi", + "os::macos-apis", +] readme = "README.md" -repository = "http://github.com/SSheldon/rust-objc" -documentation = "http://ssheldon.github.io/rust-objc/objc/" +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/objc/" license = "MIT" exclude = [ - ".gitignore", - ".travis.yml", "doc.sh", "tests-ios/**", ] diff --git a/objc/README.md b/objc/README.md index 55fba6484..0f05b14c7 100644 --- a/objc/README.md +++ b/objc/README.md @@ -1,19 +1,28 @@ -Objective-C Runtime bindings and wrapper for Rust. +# `objc` + +[![Latest version](https://badgen.net/crates/v/objc)](https://crates.io/crates/objc) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/objc/badge.svg)](https://docs.rs/objc/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) -* Documentation: http://ssheldon.github.io/rust-objc/objc/ -* Crate: https://crates.io/crates/objc +Objective-C Runtime bindings and wrapper for Rust. ## Messaging objects Objective-C objects can be messaged using the `msg_send!` macro: -``` rust +```rust , no_run +use objc::{class, msg_send}; +use objc::runtime::{BOOL, Object}; + let cls = class!(NSObject); -let obj: *mut Object = msg_send![cls, new]; -let hash: usize = msg_send![obj, hash]; -let is_kind: BOOL = msg_send![obj, isKindOfClass:cls]; -// Even void methods must have their return type annotated -let _: () = msg_send![obj, release]; +unsafe { + let obj: *mut Object = msg_send![cls, new]; + let hash: usize = msg_send![obj, hash]; + let is_kind: BOOL = msg_send![obj, isKindOfClass:cls]; + // Even void methods must have their return type annotated + let _: () = msg_send![obj, release]; +} ``` ## Reference counting @@ -24,7 +33,10 @@ A `StrongPtr` retains an object and releases the object when dropped. A `WeakPtr` will not retain the object, but can be upgraded to a `StrongPtr` and safely fails if the object has been deallocated. -``` rust +```rust , no_run +use objc::{class, msg_send}; +use objc::rc::{autoreleasepool, StrongPtr}; + // StrongPtr will release the object when dropped let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) @@ -52,7 +64,11 @@ methods can then be added before the class is ultimately registered. The following example demonstrates declaring a class named `MyNumber` that has one ivar, a `u32` named `_number` and a `number` method that returns it: -``` rust +```rust , no_run +use objc::{class, sel}; +use objc::declare::ClassDecl; +use objc::runtime::{Object, Sel}; + let superclass = class!(NSObject); let mut decl = ClassDecl::new("MyNumber", superclass).unwrap(); diff --git a/examples/objc.rs b/objc/examples/introspection.rs similarity index 96% rename from examples/objc.rs rename to objc/examples/introspection.rs index 5026a77b6..195062ce2 100644 --- a/examples/objc.rs +++ b/objc/examples/introspection.rs @@ -1,6 +1,6 @@ use objc::rc::StrongPtr; use objc::runtime::{Class, Object}; -use objc::{class, msg_send, Encode}; +use objc::{class, msg_send, sel, Encode}; fn main() { // Get a class diff --git a/objc/src/cache.rs b/objc/src/cache.rs index 372eacb77..4cfb1ae96 100644 --- a/objc/src/cache.rs +++ b/objc/src/cache.rs @@ -4,14 +4,14 @@ use core::sync::atomic::{AtomicPtr, Ordering}; use crate::runtime::{self, Class, Sel}; -/// Allows storing a `Sel` in a static and lazily loading it. +/// Allows storing a [`Sel`] in a static and lazily loading it. #[doc(hidden)] pub struct CachedSel { ptr: AtomicPtr, } impl CachedSel { - /// Constructs a new `CachedSel`. + /// Constructs a new [`CachedSel`]. pub const fn new() -> CachedSel { CachedSel { ptr: AtomicPtr::new(ptr::null_mut()), @@ -35,14 +35,14 @@ impl CachedSel { } } -/// Allows storing a `Class` reference in a static and lazily loading it. +/// Allows storing a [`Class`] reference in a static and lazily loading it. #[doc(hidden)] pub struct CachedClass { ptr: AtomicPtr, } impl CachedClass { - /// Constructs a new `CachedClass`. + /// Constructs a new [`CachedClass`]. pub const fn new() -> CachedClass { CachedClass { ptr: AtomicPtr::new(ptr::null_mut()), diff --git a/objc/src/declare.rs b/objc/src/declare.rs index 95c1d377b..099fb7519 100644 --- a/objc/src/declare.rs +++ b/objc/src/declare.rs @@ -1,7 +1,7 @@ /*! Functionality for declaring Objective-C classes. -Classes can be declared using the `ClassDecl` struct. Instance variables and +Classes can be declared using the [`ClassDecl`] struct. Instance variables and methods can then be added before the class is ultimately registered. # Example @@ -13,7 +13,6 @@ one ivar, a `u32` named `_number` and a `number` method that returns it: # use objc::{class, sel}; # use objc::declare::ClassDecl; # use objc::runtime::{Class, Object, Sel}; -# fn main() { let superclass = class!(NSObject); let mut decl = ClassDecl::new("MyNumber", superclass).unwrap(); @@ -30,7 +29,6 @@ unsafe { } decl.register(); -# } ``` */ @@ -52,7 +50,7 @@ pub trait MethodImplementation { /// The argument types of the method. type Args: EncodeArguments; - /// Returns self as an `Imp` of a method. + /// Returns self as an [`Imp`] of a method. fn imp(self) -> Imp; } @@ -129,20 +127,21 @@ impl ClassDecl { } } - /// Constructs a `ClassDecl` with the given name and superclass. - /// Returns `None` if the class couldn't be allocated. + /// Constructs a [`ClassDecl`] with the given name and superclass. + /// + /// Returns [`None`] if the class couldn't be allocated. pub fn new(name: &str, superclass: &Class) -> Option { ClassDecl::with_superclass(name, Some(superclass)) } /** - Constructs a `ClassDecl` declaring a new root class with the given name. - Returns `None` if the class couldn't be allocated. + Constructs a [`ClassDecl`] declaring a new root class with the given name. + Returns [`None`] if the class couldn't be allocated. An implementation for `+initialize` must also be given; the runtime calls this method for all classes, so it must be defined on root classes. - Note that implementing a root class is not a simple endeavor. + Note that implementing a root class is not a simple endeavor! For example, your class probably cannot be passed to Cocoa code unless the entire `NSObject` protocol is implemented. Functionality it expects, like implementations of `-retain` and `-release` @@ -158,9 +157,12 @@ impl ClassDecl { decl } - /// Adds a method with the given name and implementation to self. - /// Panics if the method wasn't sucessfully added - /// or if the selector and function take different numbers of arguments. + /// Adds a method with the given name and implementation. + /// + /// # Panics + /// + /// Panics if the method wasn't sucessfully added or if the selector and + /// function take different numbers of arguments. /// /// # Safety /// @@ -184,9 +186,12 @@ impl ClassDecl { assert!(success != NO, "Failed to add method {:?}", sel); } - /// Adds a class method with the given name and implementation to self. - /// Panics if the method wasn't sucessfully added - /// or if the selector and function take different numbers of arguments. + /// Adds a class method with the given name and implementation. + /// + /// # Panics + /// + /// Panics if the method wasn't sucessfully added or if the selector and + /// function take different numbers of arguments. /// /// # Safety /// @@ -211,12 +216,12 @@ impl ClassDecl { 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, - { + /// Adds an ivar with type `T` and the provided name. + /// + /// # Panics + /// + /// If the ivar wasn't successfully added. + pub fn add_ivar(&mut self, name: &str) { let c_name = CString::new(name).unwrap(); let encoding = CString::new(T::ENCODING.to_string()).unwrap(); let size = mem::size_of::(); @@ -227,15 +232,18 @@ impl ClassDecl { assert!(success != NO, "Failed to add ivar {}", name); } - /// Adds a protocol to self. Panics if the protocol wasn't successfully - /// added + /// Adds the given protocol to self. + /// + /// # Panics + /// + /// If the protocol wasn't successfully added. pub fn add_protocol(&mut self, proto: &Protocol) { let success = unsafe { runtime::class_addProtocol(self.cls, proto) }; assert!(success != NO, "Failed to add protocol {:?}", proto); } - /// Registers self, consuming it and returning a reference to the - /// newly registered `Class`. + /// Registers the [`ClassDecl`], consuming it, and returns a reference to + /// the newly registered [`Class`]. pub fn register(self) -> &'static Class { unsafe { let cls = self.cls; @@ -262,8 +270,9 @@ pub struct ProtocolDecl { } impl ProtocolDecl { - /// Constructs a `ProtocolDecl` with the given name. Returns `None` if the - /// protocol couldn't be allocated. + /// Constructs a [`ProtocolDecl`] with the given name. + /// + /// Returns [`None`] if the 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()) }; @@ -303,7 +312,7 @@ impl ProtocolDecl { } } - /// Adds an instance method declaration with a given description to self. + /// Adds an instance method declaration with a given description. pub fn add_method_description(&mut self, sel: Sel, is_required: bool) where Args: EncodeArguments, @@ -312,7 +321,7 @@ impl ProtocolDecl { self.add_method_description_common::(sel, is_required, true) } - /// Adds a class method declaration with a given description to self. + /// Adds a class method declaration with a given description. pub fn add_class_method_description(&mut self, sel: Sel, is_required: bool) where Args: EncodeArguments, @@ -328,8 +337,8 @@ impl ProtocolDecl { } } - /// Registers self, consuming it and returning a reference to the - /// newly registered `Protocol`. + /// Registers the [`ProtocolDecl`], consuming it and returning a reference + /// to the newly registered [`Protocol`]. pub fn register(self) -> &'static Protocol { unsafe { runtime::objc_registerProtocol(self.proto); diff --git a/objc/src/encode.rs b/objc/src/encode.rs index 2eee71cbe..1e9b21f9d 100644 --- a/objc/src/encode.rs +++ b/objc/src/encode.rs @@ -22,7 +22,7 @@ unsafe impl<'a> Encode for &'a mut Class { } /// Types that represent a group of arguments, where each has an Objective-C -/// type encoding. +/// type-encoding. pub trait EncodeArguments { /// The type as which the encodings for Self will be returned. const ENCODINGS: &'static [Encoding<'static>]; diff --git a/objc/src/exception.rs b/objc/src/exception.rs index f5dab0992..cc9335df3 100644 --- a/objc/src/exception.rs +++ b/objc/src/exception.rs @@ -1,5 +1,3 @@ -use objc_exception; - use crate::rc::StrongPtr; use crate::runtime::Object; @@ -14,11 +12,12 @@ use crate::runtime::Object; /// /// # Safety /// -/// This encourages unwinding through the closure from Objective-C, which is -/// not safe. -pub unsafe fn catch_exception(closure: F) -> Result -where - F: FnOnce() -> R, -{ +/// The given closure must not panic. +/// +/// Additionally, this unwinds through the closure from Objective-C, which is +/// undefined behaviour until `C-unwind` is stabilized, see [RFC-2945]. +/// +/// [RFC-2945]: https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html +pub unsafe fn catch_exception(closure: impl FnOnce() -> R) -> Result { objc_exception::r#try(closure).map_err(|exception| StrongPtr::new(exception as *mut Object)) } diff --git a/objc/src/lib.rs b/objc/src/lib.rs index 8515fcc1f..9cfaf408f 100644 --- a/objc/src/lib.rs +++ b/objc/src/lib.rs @@ -8,7 +8,6 @@ Objective-C objects can be messaged using the [`msg_send!`](macro.msg_send!.html ``` no_run # use objc::{class, msg_send}; # use objc::runtime::{BOOL, Class, Object}; -# fn main() { # unsafe { let cls = class!(NSObject); let obj: *mut Object = msg_send![cls, new]; @@ -17,7 +16,6 @@ let is_kind: BOOL = msg_send![obj, isKindOfClass:cls]; // Even void methods must have their return type annotated let _: () = msg_send![obj, release]; # } -# } ``` # Reference counting @@ -63,10 +61,20 @@ The bindings can be used on Linux or *BSD utilizing the #![no_std] #![warn(missing_docs)] #![allow(clippy::missing_safety_doc)] +// Update in Cargo.toml as well. +#![doc(html_root_url = "https://docs.rs/objc/0.2.7")] extern crate alloc; extern crate std; +#[cfg(doctest)] +#[doc = include_str!("../README.md")] +extern "C" {} + +#[cfg(doctest)] +#[doc = include_str!("../../README.md")] +extern "C" {} + pub use objc_encode::{Encode, Encoding}; pub use crate::encode::EncodeArguments; diff --git a/objc/src/macros.rs b/objc/src/macros.rs index 6321ede90..efb39810f 100644 --- a/objc/src/macros.rs +++ b/objc/src/macros.rs @@ -1,15 +1,20 @@ /** -Gets a reference to a `Class`. +Gets a reference to a [`Class`] from the given name. + +# Panics Panics if no class with the given name can be found. -To check for a class that may not exist, use `Class::get`. -# Example +To check for a class that may not exist, use [`Class::get`]. + +[`Class`]: crate::runtime::Class +[`Class::get`]: crate::runtime::Class::get + +# Examples + ``` no_run # use objc::class; -# fn main() { let cls = class!(NSObject); -# } ``` */ #[macro_export] @@ -27,15 +32,18 @@ macro_rules! class { } /** -Registers a selector, returning a `Sel`. +Registers a selector with the Objective-C runtime. + +Returns a [`Sel`]. + +[`Sel`]: crate::runtime::Sel + +# Examples -# Example ``` # use objc::sel; -# fn main() { let sel = sel!(description); let sel = sel!(setObject:forKey:); -# } ``` */ #[macro_export] @@ -58,22 +66,33 @@ macro_rules! sel { Sends a message to an object. The first argument can be any type that dereferences to a type that implements -`Message`, like a reference, pointer, or an `Id`. +[`Message`], like a reference, a pointer, or an `objc_id::Id` to an object. + The syntax is similar to the message syntax in Objective-C. + Variadic arguments are not currently supported. -# Example +[`Message`]: crate::Message + +# Panics + +Panics if the `exception` feature is enabled and the Objective-C method throws +an exception. + +And panics if the `verify_message` feature is enabled and the Objective-C +method's argument's encoding does not match the encoding of the given arguments. + +# Examples + ``` no_run # use objc::msg_send; # use objc::runtime::Object; -# fn main() { # unsafe { let obj: *mut Object; # let obj: *mut Object = 0 as *mut Object; let description: *const Object = msg_send![obj, description]; let _: () = msg_send![obj, setArg1:1 arg2:2]; # } -# } ``` */ #[macro_export] diff --git a/objc/src/message/mod.rs b/objc/src/message/mod.rs index d2691c43b..f23597abc 100644 --- a/objc/src/message/mod.rs +++ b/objc/src/message/mod.rs @@ -41,15 +41,28 @@ use self::verify::{verify_message_signature, VerificationError}; /// Specifies the superclass of an instance. #[repr(C)] -pub struct Super { +struct Super { /// Specifies an instance of a class. pub receiver: *mut Object, /// Specifies the particular superclass of the instance to message. pub superclass: *const Class, } -/// Types that may be sent Objective-C messages. -/// For example: objects, classes, and blocks. +/// This trait marks types that can be sent Objective-C messages. +/// +/// Examples include objects, classes, and blocks. +/// +/// The type should also implement [`Encode`] for `&Self` and `&mut Self`. +/// +/// # Safety +/// +/// A pointer to the type must be able to be the receiver of an Objective-C +/// message sent with [`objc_msgSend`] or similar. +/// +/// The type must also have a C-compatible `repr` (`repr(C)`, `repr(u8)`, +/// `repr(transparent)` where the inner types are C-compatible, and so on). +/// +/// [`objc_msgSend`]: https://developer.apple.com/documentation/objectivec/1456712-objc_msgsend pub unsafe trait Message { /** Sends a message to self with the given selector and arguments. @@ -87,7 +100,7 @@ pub unsafe trait Message { method for the given selector. This will look up the encoding of the method for the given selector, `sel`, - and return a `MessageError` if any encodings differ for the arguments `A` + and return a [`MessageError`] if any encodings differ for the arguments `A` and return type `R`. # Example @@ -95,14 +108,12 @@ pub unsafe trait Message { # use objc::{class, msg_send, sel}; # use objc::runtime::{BOOL, Class, Object}; # use objc::Message; - # fn main() { let obj: &Object; # obj = unsafe { msg_send![class!(NSObject), new] }; let sel = sel!(isKindOfClass:); // Verify isKindOfClass: takes one Class and returns a BOOL let result = obj.verify_message::<(&Class,), BOOL>(sel); assert!(result.is_ok()); - # } ``` */ fn verify_message(&self, sel: Sel) -> Result<(), MessageError> @@ -122,11 +133,11 @@ unsafe impl Message for Class {} /// Types that may be used as the arguments of an Objective-C message. pub trait MessageArguments: Sized { - /// Invoke an `Imp` with the given object, selector, and arguments. + /// Invoke an [`Imp`] with the given object, selector, and arguments. /// /// 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. + /// 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; diff --git a/objc/src/rc/mod.rs b/objc/src/rc/mod.rs index 4bb40b565..529776b88 100644 --- a/objc/src/rc/mod.rs +++ b/objc/src/rc/mod.rs @@ -18,7 +18,6 @@ For more information on Objective-C's reference counting, see Apple's documentat ``` no_run # use objc::{class, msg_send}; # use objc::rc::{autoreleasepool, StrongPtr}; -# fn main() { // StrongPtr will release the object when dropped let obj = unsafe { StrongPtr::new(msg_send![class!(NSObject), new]) @@ -36,7 +35,6 @@ autoreleasepool(|| { let weak = obj.weak(); drop(obj); assert!(weak.load().is_null()); -# } ``` */ diff --git a/objc/src/rc/strong.rs b/objc/src/rc/strong.rs index 2c13cbc58..67eca8824 100644 --- a/objc/src/rc/strong.rs +++ b/objc/src/rc/strong.rs @@ -9,7 +9,7 @@ use crate::runtime::{self, Object}; pub struct StrongPtr(*mut Object); impl StrongPtr { - /// Constructs a `StrongPtr` to a newly created object that already has a + /// Constructs a [`StrongPtr`] to a newly created object that already has a /// +1 retain count. This will not retain the object. /// When dropped, the object will be released. /// @@ -20,7 +20,7 @@ impl StrongPtr { StrongPtr(ptr) } - /// Retains the given object and constructs a `StrongPtr` to it. + /// Retains the given object and constructs a [`StrongPtr`] to it. /// When dropped, the object will be released. /// /// # Safety @@ -42,7 +42,7 @@ impl StrongPtr { ptr } - /// Returns a `WeakPtr` to self. + /// Returns a [`WeakPtr`] to self. pub fn weak(&self) -> WeakPtr { unsafe { WeakPtr::new(self.0) } } diff --git a/objc/src/rc/weak.rs b/objc/src/rc/weak.rs index 3ac31f477..da24cf02b 100644 --- a/objc/src/rc/weak.rs +++ b/objc/src/rc/weak.rs @@ -14,7 +14,7 @@ use crate::runtime::{self, Object}; pub struct WeakPtr(Box>); impl WeakPtr { - /// Constructs a `WeakPtr` to the given object. + /// Constructs a [`WeakPtr`] to the given object. /// /// # Safety /// @@ -25,7 +25,7 @@ impl WeakPtr { WeakPtr(ptr) } - /// Loads the object self points to, returning a `StrongPtr`. + /// Loads the object self points to, returning a [`StrongPtr`]. /// If the object has been deallocated, the returned pointer will be null. pub fn load(&self) -> StrongPtr { unsafe { diff --git a/objc/src/runtime.rs b/objc/src/runtime.rs index dd419f27b..608301392 100644 --- a/objc/src/runtime.rs +++ b/objc/src/runtime.rs @@ -15,13 +15,13 @@ use crate::Encode; /// The Objective-C `BOOL` type. /// -/// To convert an Objective-C `BOOL` into a Rust `bool`, compare it with `NO`. +/// To convert an Objective-C `BOOL` into a Rust [`bool`], compare it with [`NO`]. #[cfg(not(target_arch = "aarch64"))] pub type BOOL = ::std::os::raw::c_schar; -/// The equivalent of true for Objective-C's `BOOL` type. +/// The equivalent of true for Objective-C's [`BOOL`] type. #[cfg(not(target_arch = "aarch64"))] pub const YES: BOOL = 1; -/// The equivalent of false for Objective-C's `BOOL` type. +/// The equivalent of false for Objective-C's [`BOOL`] type. #[cfg(not(target_arch = "aarch64"))] pub const NO: BOOL = 0; @@ -176,13 +176,13 @@ impl Sel { str::from_utf8(name.to_bytes()).unwrap() } - /// Wraps a raw pointer to a selector into a `Sel` object. + /// Wraps a raw pointer to a selector into a [`Sel`] object. /// /// # Safety /// /// The pointer must a valid, registered selector. /// - /// This is almost never what you want; use `Sel::register()` instead. + /// This is almost never what you want; use [`Sel::register`] instead. #[inline] pub unsafe fn from_ptr(ptr: *const c_void) -> Sel { Sel { ptr } @@ -256,7 +256,7 @@ impl Method { } /// Returns the `Encoding` of a single parameter type of self, or - /// `None` if self has no parameter at the given index. + /// [`None`] if self has no parameter at the given index. pub fn argument_type(&self, index: usize) -> Option> { unsafe { let encoding = method_copyArgumentType(self, index as c_uint); @@ -280,7 +280,7 @@ impl Method { } impl Class { - /// Returns the class definition of a specified class, or `None` if the + /// Returns the class definition of a specified class, or [`None`] if the /// class is not registered with the Objective-C runtime. pub fn get(name: &str) -> Option<&'static Class> { let name = CString::new(name).unwrap(); @@ -308,13 +308,13 @@ impl Class { unsafe { objc_getClassList(ptr::null_mut(), 0) as usize } } - /// Returns the name of self. + /// Returns the name of the class. pub fn name(&self) -> &str { let name = unsafe { CStr::from_ptr(class_getName(self)) }; str::from_utf8(name.to_bytes()).unwrap() } - /// Returns the superclass of self, or `None` if self is a root class. + /// Returns the superclass of self, or [`None`] if self is a root class. pub fn superclass(&self) -> Option<&Class> { unsafe { let superclass = class_getSuperclass(self); @@ -339,9 +339,9 @@ impl Class { unsafe { class_getInstanceSize(self) as usize } } - /// Returns a specified instance method for self, or `None` if self and - /// its superclasses do not contain an instance method with the - /// specified selector. + /// Returns a specified instance method for self, or [`None`] if self and + /// its superclasses do not contain an instance method with the specified + /// selector. pub fn instance_method(&self, sel: Sel) -> Option<&Method> { unsafe { let method = class_getInstanceMethod(self, sel); @@ -353,8 +353,8 @@ impl Class { } } - /// Returns the ivar for a specified instance variable of self, or `None` - /// if self has no ivar with the given name. + /// Returns the ivar for a specified instance variable of self, or + /// [`None`] if self has no ivar with the given name. pub fn instance_variable(&self, name: &str) -> Option<&Ivar> { let name = CString::new(name).unwrap(); unsafe { @@ -417,8 +417,8 @@ impl fmt::Debug for Class { } impl Protocol { - /// Returns the protocol definition of a specified protocol, or `None` if the - /// protocol is not registered with the Objective-C runtime. + /// Returns the protocol definition of a specified protocol, or [`None`] + /// if the protocol is not registered with the Objective-C runtime. pub fn get(name: &str) -> Option<&'static Protocol> { let name = CString::new(name).unwrap(); unsafe { @@ -475,76 +475,65 @@ impl fmt::Debug for Protocol { } } +fn get_ivar_offset(cls: &Class, name: &str) -> isize { + match cls.instance_variable(name) { + Some(ivar) => { + assert!(ivar.type_encoding() == &T::ENCODING); + ivar.offset() + } + None => panic!("Ivar {} not found on class {:?}", name, cls), + } +} + impl Object { - /// Returns the class of self. + /// Returns the class of this object. pub fn class(&self) -> &Class { 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. + /// Returns a shared reference to the ivar with the given name. + /// + /// # Panics + /// + /// Panics if the object has no ivar with the given name, or the type + /// encoding of the ivar differs from the type encoding of `T`. /// /// # Safety /// /// The caller must ensure that the ivar is actually of type `T`. - pub unsafe fn get_ivar(&self, name: &str) -> &T - where - T: Encode, - { - let offset = { - let cls = self.class(); - match cls.instance_variable(name) { - Some(ivar) => { - assert!(ivar.type_encoding() == &T::ENCODING); - ivar.offset() - } - None => panic!("Ivar {} not found on class {:?}", name, cls), - } - }; - let ptr = { - let self_ptr: *const Object = self; - (self_ptr as *const u8).offset(offset) as *const T - }; + pub unsafe fn get_ivar(&self, name: &str) -> &T { + let offset = get_ivar_offset::(self.class(), name); + let ptr = (self as *const Self as *const u8).offset(offset) as *const T; &*ptr } - /// Returns a mutable reference to the ivar of self with the given name. - /// Panics if self has no ivar with the given name. + /// Returns a mutable reference to the ivar with the given name. + /// + /// # Panics + /// + /// Panics if the object has no ivar with the given name, or the type + /// encoding of the ivar differs from the type encoding of `T`. /// /// # Safety /// /// 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, - { - let offset = { - let cls = self.class(); - match cls.instance_variable(name) { - Some(ivar) => { - assert!(ivar.type_encoding() == &T::ENCODING); - ivar.offset() - } - None => panic!("Ivar {} not found on class {:?}", name, cls), - } - }; - let ptr = { - let self_ptr: *mut Object = self; - (self_ptr as *mut u8).offset(offset) as *mut T - }; + pub unsafe fn get_mut_ivar(&mut self, name: &str) -> &mut T { + let offset = get_ivar_offset::(self.class(), name); + let ptr = (self as *mut Self as *mut u8).offset(offset) as *mut T; &mut *ptr } - /// Sets the value of the ivar of self with the given name. - /// Panics if self has no ivar with the given name. + /// Sets the value of the ivar with the given name. + /// + /// # Panics + /// + /// Panics if the object has no ivar with the given name, or the type + /// encoding of the ivar differs from the type encoding of `T`. /// /// # Safety /// /// 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, - { + pub unsafe fn set_ivar(&mut self, name: &str, value: T) { *self.get_mut_ivar::(name) = value; } } diff --git a/objc_encode/Cargo.toml b/objc_encode/Cargo.toml index 102a502b6..5693bfc4c 100644 --- a/objc_encode/Cargo.toml +++ b/objc_encode/Cargo.toml @@ -1,17 +1,21 @@ [package] name = "objc-encode" -version = "1.1.0" -authors = ["Steven Sheldon"] +version = "1.1.0" # Remember to update html_root_url in lib.rs +authors = ["Steven Sheldon", "Mads Marquart "] edition = "2018" -description = "Objective-C type encoding creation and parsing in Rust." -keywords = ["objective-c", "osx", "ios", "cocoa", "uikit"] -categories = ["development-tools::ffi", "no-std"] +description = "Objective-C type encoding creation and parsing." +keywords = ["objective-c", "macos", "ios", "encode"] +categories = [ + "development-tools::ffi", + "encoding", + "no-std", + "os::macos-apis", +] readme = "README.md" -repository = "http://github.com/SSheldon/rust-objc-encode" -documentation = "http://ssheldon.github.io/rust-objc/objc_encode/" +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/objc-encode/" license = "MIT" -exclude = [ - ".gitignore", -] +[dev-dependencies] +objc = { path = "../objc", version = "0.2.7" } diff --git a/objc_encode/README.md b/objc_encode/README.md index 38ecd2b55..28aaa5cb9 100644 --- a/objc_encode/README.md +++ b/objc_encode/README.md @@ -1,38 +1,64 @@ +# `objc-encode` + +[![Latest version](https://badgen.net/crates/v/objc-encode)](https://crates.io/crates/objc-encode) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/objc-encode/badge.svg)](https://docs.rs/objc-encode/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) + Objective-C type encoding creation and parsing in Rust. The Objective-C compiler encodes types as strings for usage in the runtime. This crate aims to provide a strongly-typed (rather than stringly-typed) way to create and describe these type encodings without memory allocation in Rust. -# Implementing Encode + +## Implementing Encode This crate declares an `Encode` trait that can be implemented for types that the Objective-C compiler can encode. Implementing this trait looks like: -``` rust +```rust +use objc::{Encode, Encoding}; + +#[cfg(target_pointer_width = "32")] +type CGFloat = f32; + +#[cfg(target_pointer_width = "64")] +type CGFloat = f64; + +#[repr(C)] +struct CGPoint { + x: CGFloat, + y: CGFloat, +} + unsafe impl Encode for CGPoint { const ENCODING: Encoding<'static> = - Encoding::Struct("CGPoint", &[CGFloat::ENCODING, CGFLOAT::ENCODING]); + Encoding::Struct("CGPoint", &[CGFloat::ENCODING, CGFloat::ENCODING]); } ``` For an example of how this works with more complex types, like structs containing structs, see the `core_graphics` example. -# Comparing with encoding strings +## Comparing with encoding strings An `Encoding` can be compared with an encoding string from the Objective-C runtime: -``` rust +```rust +use objc::Encode; + assert!(&i32::ENCODING == "i"); ``` -# Generating encoding strings +## Generating encoding strings Every `Encoding` implements `Display` as its string representation. This can be generated conveniently through the `to_string` method: -``` rust +```rust +use objc::Encode; + assert_eq!(i32::ENCODING.to_string(), "i"); ``` diff --git a/objc_encode/examples/ns_string.rs b/objc_encode/examples/ns_string.rs new file mode 100644 index 000000000..85f51a828 --- /dev/null +++ b/objc_encode/examples/ns_string.rs @@ -0,0 +1,34 @@ +use objc_encode::{Encode, Encoding}; + +/// We don't know the size of NSString, so we can only hold pointers to it. +/// +/// TODO: Use [`extern type`][rfc-1861] when that gets stabilized. +/// +/// [rfc-1861]: https://rust-lang.github.io/rfcs/1861-extern-types.html +#[repr(C)] +struct NSString { + _priv: [u8; 0], +} + +/// Implement `Encode` for references. +/// +/// This also implements for `*mut NSString` and `Option<&mut NSString>`. +unsafe impl<'a> Encode for &'a NSString { + const ENCODING: Encoding<'static> = Encoding::Object; +} + +/// Implement `Encode` for mutable references. +/// +/// This also implements for `*mut NSString` and `Option<&mut NSString>`. +unsafe impl<'a> Encode for &'a mut NSString { + const ENCODING: Encoding<'static> = Encoding::Object; +} + +fn main() { + println!("{}", <*const NSString>::ENCODING); + println!("{}", <*mut NSString>::ENCODING); + println!("{}", <&NSString>::ENCODING); + println!("{}", <&mut NSString>::ENCODING); + println!("{}", Option::<&NSString>::ENCODING); + println!("{}", Option::<&mut NSString>::ENCODING); +} diff --git a/objc_encode/src/encode.rs b/objc_encode/src/encode.rs index 0ebac9b10..e8ede4a4d 100644 --- a/objc_encode/src/encode.rs +++ b/objc_encode/src/encode.rs @@ -2,13 +2,15 @@ use core::ffi::c_void; use crate::Encoding; -/// Types that have an Objective-C type encoding. +/// Types that have an Objective-C type-encoding. /// -/// Unsafe because Objective-C will make assumptions about the type (like its -/// size and alignment) from its encoding, so the implementer must verify that -/// the encoding is accurate. +/// # Safety +/// +/// Objective-C will make assumptions about the type (like its size and +/// alignment) from its encoding, so the implementer must verify that the +/// encoding is accurate. pub unsafe trait Encode { - /// Returns the Objective-C type encoding for Self. + /// The Objective-C type-encoding for this type. const ENCODING: Encoding<'static>; } diff --git a/objc_encode/src/encoding.rs b/objc_encode/src/encoding.rs index 3df447c87..f7ff8b43f 100644 --- a/objc_encode/src/encoding.rs +++ b/objc_encode/src/encoding.rs @@ -8,30 +8,65 @@ use crate::parse; /// #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Encoding<'a> { + /// A C `char`. Corresponds to the `c` code. Char, + /// A C `short`. Corresponds to the `s` code. Short, + /// A C `int`. Corresponds to the `i` code. Int, + /// A C `long`. Corresponds to the `l` code. Long, + /// A C `long long`. Corresponds to the `q` code. LongLong, + /// A C `unsigned char`. Corresponds to the `C` code. UChar, + /// A C `unsigned short`. Corresponds to the `S` code. UShort, + /// A C `unsigned int`. Corresponds to the `I` code. UInt, + /// A C `unsigned long`. Corresponds to the `L` code. ULong, + /// A C `unsigned long long`. Corresponds to the `Q` code. ULongLong, + /// A C `float`. Corresponds to the `f` code. Float, + /// A C `double`. Corresponds to the `d` code. Double, + /// A C++ `bool` / C99 `_Bool`. Corresponds to the `B` code. Bool, + /// A C `void`. Corresponds to the `v` code. Void, + /// A C `char *`. Corresponds to the `*` code. String, + /// An Objective-C object (`id`). Corresponds to the `@` code. Object, + /// An Objective-C block. Corresponds to the `@?` code. Block, + /// An Objective-C class (`Class`). Corresponds to the `#` code. Class, + /// An Objective-C selector (`SEL`). Corresponds to the `:` code. Sel, + /// An unknown type. Corresponds to the `?` code. Unknown, + /// A bitfield with the given number of bits. + /// + /// Corresponds to the `b`num code. BitField(u32), + /// A pointer to the given type. + /// + /// Corresponds to the `^`type code. Pointer(&'a Encoding<'a>), + /// An array with the given length and type. + /// + /// Corresponds to the `[len type]` code. Array(u32, &'a Encoding<'a>), + /// A struct with the given name and fields. + /// + /// Corresponds to the `{name=fields...}` code. Struct(&'a str, &'a [Encoding<'a>]), + /// A union with the given name and fields. + /// + /// Corresponds to the `(name=fields...)` code. Union(&'a str, &'a [Encoding<'a>]), } diff --git a/objc_encode/src/lib.rs b/objc_encode/src/lib.rs index a7ed5e40b..e1ff88f72 100644 --- a/objc_encode/src/lib.rs +++ b/objc_encode/src/lib.rs @@ -7,10 +7,10 @@ to create and describe these type encodings without memory allocation in Rust. # Implementing Encode -This crate declares an `Encode` trait that can be implemented for types that +This crate declares an [`Encode`] trait that can be implemented for types that the Objective-C compiler can encode. Implementing this trait looks like: -``` ignore +```ignore unsafe impl Encode for CGPoint { const ENCODING: Encoding<'static> = Encoding::Struct("CGPoint", &[CGFloat::ENCODING, CGFLOAT::ENCODING]); @@ -22,7 +22,7 @@ containing structs, see the `core_graphics` example. # Comparing with encoding strings -An `Encoding` can be compared with an encoding string from the Objective-C +An [`Encoding`] can be compared with an encoding string from the Objective-C runtime: ``` @@ -32,8 +32,9 @@ assert!(&i32::ENCODING == "i"); # Generating encoding strings -Every `Encoding` implements `Display` as its string representation. -This can be generated conveniently through the `to_string` method: +Every [`Encoding`] implements [`Display`][`core::fmt::Display`] as its string +representation. This can be generated conveniently through the +[`to_string`][`alloc::string::ToString::to_string`] method: ``` # use objc_encode::Encode; @@ -42,8 +43,15 @@ assert_eq!(i32::ENCODING.to_string(), "i"); */ #![no_std] +#![warn(missing_docs)] +// Update in Cargo.toml as well. +#![doc(html_root_url = "https://docs.rs/objc-encode/1.1.0")] -#[cfg(test)] +#[cfg(doctest)] +#[doc = include_str!("../README.md")] +extern "C" {} + +#[cfg(any(test, doc))] extern crate alloc; mod encode; diff --git a/objc_exception/Cargo.toml b/objc_exception/Cargo.toml index 599fdf393..eac9451fc 100644 --- a/objc_exception/Cargo.toml +++ b/objc_exception/Cargo.toml @@ -1,18 +1,22 @@ [package] name = "objc_exception" -version = "0.1.2" -authors = ["Steven Sheldon"] +version = "0.1.2" # Remember to update html_root_url in lib.rs +authors = ["Steven Sheldon", "Mads Marquart "] edition = "2018" -description = "Rust interface for Objective-C's throw and try/catch statements." -keywords = ["objective-c", "osx", "ios"] -categories = ["development-tools::ffi", "no-std"] -repository = "http://github.com/SSheldon/rust-objc-exception" -documentation = "http://ssheldon.github.io/rust-objc/objc_exception/" +description = "Objective-C's throw and try/catch statements." +keywords = ["objective-c", "macos", "ios", "try", "catch"] +categories = [ + "api-bindings", + "development-tools::ffi", + "no-std", + "os::macos-apis", +] +readme = "README.md" +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/objc_exception/" license = "MIT" -exclude = [".gitignore"] - build = "build.rs" [build-dependencies] diff --git a/objc_exception/README.md b/objc_exception/README.md new file mode 100644 index 000000000..d97e1a1e8 --- /dev/null +++ b/objc_exception/README.md @@ -0,0 +1,6 @@ +# `objc_exception` + +[![Latest version](https://badgen.net/crates/v/objc_exception)](https://crates.io/crates/objc_exception) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/objc_exception/badge.svg)](https://docs.rs/objc_exception/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) diff --git a/objc_exception/build.rs b/objc_exception/build.rs index e53b0b8c6..5ae4e8f20 100644 --- a/objc_exception/build.rs +++ b/objc_exception/build.rs @@ -2,5 +2,5 @@ fn main() { cc::Build::new() .file("extern/exception.m") .flag("-fobjc-exceptions") - .compile("libexception.a"); + .compile("librustobjcexception.a"); } diff --git a/objc_exception/extern/exception.m b/objc_exception/extern/exception.m index 6229b196a..3a3d6b170 100644 --- a/objc_exception/extern/exception.m +++ b/objc_exception/extern/exception.m @@ -1,11 +1,12 @@ -// Always available in Objective-C -// See https://clang.llvm.org/docs/AutomaticReferenceCounting.html#arc-runtime-objc-retain +/// This is always available when building Objective-C. +/// +/// See . id objc_retain(id value); // We return `unsigned char`, since it is guaranteed to be an `u8` on all platforms -unsigned char RustObjCExceptionTryCatch(void (*try)(void *), void *context, id *error) { +unsigned char RustObjCExceptionTryCatch(void (*f)(void *), void *context, id *error) { @try { - try(context); + f(context); if (error) { *error = (id)0; // nil } diff --git a/objc_exception/src/lib.rs b/objc_exception/src/lib.rs index 2b08b1b85..ac7391c09 100644 --- a/objc_exception/src/lib.rs +++ b/objc_exception/src/lib.rs @@ -1,10 +1,23 @@ //! Rust interface for Objective-C's `@throw` and `@try`/`@catch` statements. +//! +//! See the following links for more information: +//! - +//! - +//! - +//! - #![no_std] +#![warn(missing_docs)] +// Update in Cargo.toml as well. +#![doc(html_root_url = "https://docs.rs/objc_exception/0.1.2")] #[cfg(test)] extern crate alloc; +#[cfg(doctest)] +#[doc = include_str!("../README.md")] +extern "C" {} + use core::ffi::c_void; use core::mem; use core::ptr; @@ -22,7 +35,7 @@ extern "C" { extern "C" { fn RustObjCExceptionTryCatch( - r#try: extern "C" fn(*mut c_void), + f: extern "C" fn(*mut c_void), context: *mut c_void, error: *mut *mut c_void, ) -> u8; // std::os::raw::c_uchar @@ -43,6 +56,7 @@ pub struct Exception { } /// Throws an Objective-C exception. +/// /// The argument must be a pointer to an Objective-C object. /// /// # Safety @@ -59,14 +73,8 @@ pub unsafe fn throw(exception: *mut Exception) -> ! { objc_exception_throw(exception as *mut _) } -unsafe fn try_no_ret(closure: F) -> Result<(), *mut Exception> -where - F: FnOnce(), -{ - extern "C" fn try_objc_execute_closure(closure: &mut Option) - where - F: FnOnce(), - { +unsafe fn try_no_ret(closure: F) -> Result<(), *mut Exception> { + extern "C" fn try_objc_execute_closure(closure: &mut Option) { // This is always passed Some, so it's safe to unwrap let closure = closure.take().unwrap(); closure(); @@ -97,12 +105,13 @@ where /// /// # Safety /// -/// This encourages unwinding through the closure from -/// Objective-C, which is not safe. -pub unsafe fn r#try(closure: F) -> Result -where - F: FnOnce() -> R, -{ +/// The given closure must not panic. +/// +/// Additionally, this unwinds through the closure from Objective-C, which is +/// undefined behaviour until `C-unwind` is stabilized, see [RFC-2945]. +/// +/// [RFC-2945]: https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html +pub unsafe fn r#try(closure: impl FnOnce() -> R) -> Result { let mut value = None; let result = { let value_ref = &mut value; diff --git a/objc_foundation/Cargo.toml b/objc_foundation/Cargo.toml index faa8dcf7b..9b56aadda 100644 --- a/objc_foundation/Cargo.toml +++ b/objc_foundation/Cargo.toml @@ -1,17 +1,21 @@ [package] name = "objc-foundation" -version = "0.1.1" -authors = ["Steven Sheldon"] +version = "0.1.1" # Remember to update html_root_url in lib.rs +authors = ["Steven Sheldon", "Mads Marquart "] edition = "2018" -description = "Rust wrapper for Objective-C's Foundation framework." -keywords = ["objective-c", "osx", "ios", "cocoa", "uikit"] -repository = "http://github.com/SSheldon/rust-objc-foundation" -documentation = "http://ssheldon.github.io/rust-objc/objc_foundation/" +description = "Bindings to the Objective-C Foundation framework." +keywords = ["objective-c", "macos", "ios", "cocoa", "uikit"] +categories = [ + "api-bindings", + "development-tools::ffi", + "os::macos-apis", +] +readme = "README.md" +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/objc_foundation/" license = "MIT" -exclude = [".gitignore"] - [features] default = ["block"] diff --git a/objc_foundation/README.md b/objc_foundation/README.md new file mode 100644 index 000000000..c4b0b7c28 --- /dev/null +++ b/objc_foundation/README.md @@ -0,0 +1,6 @@ +# `objc_foundation` + +[![Latest version](https://badgen.net/crates/v/objc_foundation)](https://crates.io/crates/objc_foundation) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/objc_foundation/badge.svg)](https://docs.rs/objc_foundation/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) diff --git a/objc_foundation/derive/Cargo.toml b/objc_foundation/derive/Cargo.toml deleted file mode 100644 index 6b9b8cbe1..000000000 --- a/objc_foundation/derive/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "objc-foundation-derive" -version = "0.0.1" -authors = ["Steven Sheldon"] - -description = "Procedural macros for deriving traits from objc-foundation." -keywords = ["objective-c", "osx", "ios", "cocoa", "uikit"] -repository = "http://github.com/SSheldon/rust-objc-foundation" -documentation = "http://ssheldon.github.io/rust-objc/objc_foundation/" -license = "MIT" - -[lib] -proc-macro = true - -[dependencies] -syn = "0.10" -quote = "0.3.8" diff --git a/examples/foundation.rs b/objc_foundation/examples/basic_usage.rs similarity index 100% rename from examples/foundation.rs rename to objc_foundation/examples/basic_usage.rs diff --git a/examples/foundation_custom_class.rs b/objc_foundation/examples/custom_class.rs similarity index 95% rename from examples/foundation_custom_class.rs rename to objc_foundation/examples/custom_class.rs index 30dee30bd..9b988c2de 100644 --- a/examples/foundation_custom_class.rs +++ b/objc_foundation/examples/custom_class.rs @@ -1,9 +1,9 @@ -use std::sync::{Once, ONCE_INIT}; +use std::sync::Once; use objc::declare::ClassDecl; -use objc::msg_send; use objc::runtime::{Class, Object, Sel}; use objc::Message; +use objc::{msg_send, sel}; use objc_foundation::{INSObject, NSObject}; /// In the future this should be an `extern type`, if that gets stabilized, @@ -34,7 +34,7 @@ impl MYObject { unsafe impl Message for MYObject {} -static MYOBJECT_REGISTER_CLASS: Once = ONCE_INIT; +static MYOBJECT_REGISTER_CLASS: Once = Once::new(); impl INSObject for MYObject { fn class() -> &'static Class { diff --git a/objc_foundation/src/lib.rs b/objc_foundation/src/lib.rs index dfdd9c7d7..d25292177 100644 --- a/objc_foundation/src/lib.rs +++ b/objc_foundation/src/lib.rs @@ -1,9 +1,15 @@ #![no_std] #![crate_name = "objc_foundation"] +// Update in Cargo.toml as well. +#![doc(html_root_url = "https://docs.rs/objc-foundation/0.1.1")] extern crate alloc; extern crate std; +#[cfg(doctest)] +#[doc = include_str!("../README.md")] +extern "C" {} + pub use self::array::{ INSArray, INSMutableArray, NSArray, NSComparisonResult, NSMutableArray, NSMutableSharedArray, NSRange, NSSharedArray, diff --git a/objc_foundation_derive/Cargo.toml b/objc_foundation_derive/Cargo.toml new file mode 100644 index 000000000..47c27400c --- /dev/null +++ b/objc_foundation_derive/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "objc-foundation-derive" +version = "0.0.1" # Remember to update html_root_url in lib.rs +authors = ["Steven Sheldon", "Mads Marquart "] +edition = "2018" + +description = "Procedural macros for deriving traits from objc_foundation." +keywords = ["objective-c", "macos", "ios", "cocoa", "uikit"] +categories = [ + "api-bindings", + "development-tools::ffi", + "os::macos-apis", +] +readme = "README.md" +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/objc-foundation-derive/" +license = "MIT" + +[lib] +proc-macro = true + +[dependencies] +syn = "0.10" +quote = "0.3.8" diff --git a/objc_foundation_derive/README.md b/objc_foundation_derive/README.md new file mode 100644 index 000000000..e3c6343bc --- /dev/null +++ b/objc_foundation_derive/README.md @@ -0,0 +1,6 @@ +# `objc_foundation` + +[![Latest version](https://badgen.net/crates/v/objc_foundation_derive)](https://crates.io/crates/objc_foundation_derive) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/objc_foundation_derive/badge.svg)](https://docs.rs/objc_foundation_derive/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) diff --git a/objc_foundation/derive/src/lib.rs b/objc_foundation_derive/src/lib.rs similarity index 92% rename from objc_foundation/derive/src/lib.rs rename to objc_foundation_derive/src/lib.rs index ab55a0c6e..2e4c72ae4 100644 --- a/objc_foundation/derive/src/lib.rs +++ b/objc_foundation_derive/src/lib.rs @@ -1,3 +1,10 @@ +// Update in Cargo.toml as well. +#![doc(html_root_url = "https://docs.rs/objc-foundation-derive/0.0.1")] + +#[cfg(doctest)] +#[doc = include_str!("../README.md")] +extern "C" {} + extern crate proc_macro; #[macro_use] extern crate quote; diff --git a/objc_id/Cargo.toml b/objc_id/Cargo.toml index 71196c703..6d9ea88e0 100644 --- a/objc_id/Cargo.toml +++ b/objc_id/Cargo.toml @@ -1,17 +1,20 @@ [package] name = "objc_id" -version = "0.1.1" -authors = ["Steven Sheldon"] +version = "0.1.1" # Remember to update html_root_url in lib.rs +authors = ["Steven Sheldon", "Mads Marquart "] edition = "2018" -description = "Rust smart pointers for Objective-C reference counting." -keywords = ["objective-c", "osx", "ios"] +description = "Smart pointers for Objective-C reference counting." +keywords = ["objective-c", "macos", "ios", "retain", "release"] +categories = [ + "api-bindings", + "development-tools::ffi", + "os::macos-apis", +] readme = "README.md" -repository = "http://github.com/SSheldon/rust-objc-id" -documentation = "http://ssheldon.github.io/rust-objc/objc_id/" +repository = "https://github.com/madsmtm/objc" +documentation = "https://docs.rs/objc_id/" license = "MIT" -exclude = [".gitignore"] - [dependencies] -objc = { path = "../objc", version = "0.2.4" } +objc = { path = "../objc", version = "0.2.7" } diff --git a/objc_id/README.md b/objc_id/README.md index f1f362b84..501817116 100644 --- a/objc_id/README.md +++ b/objc_id/README.md @@ -1,3 +1,10 @@ +# `objc_id` + +[![Latest version](https://badgen.net/crates/v/objc_id)](https://crates.io/crates/objc_id) +[![License](https://badgen.net/badge/license/MIT/blue)](../LICENSE.txt) +[![Documentation](https://docs.rs/objc_id/badge.svg)](https://docs.rs/objc_id/) +[![CI Status](https://github.com/madsmtm/objc/workflows/CI/badge.svg)](https://github.com/madsmtm/objc/actions) + Rust smart pointers for Objective-C reference counting. To ensure that Objective-C objects are retained and released diff --git a/objc_id/src/id.rs b/objc_id/src/id.rs index 1185d12c5..1ab1b0f90 100644 --- a/objc_id/src/id.rs +++ b/objc_id/src/id.rs @@ -16,23 +16,25 @@ pub enum Owned {} pub enum Shared {} /// A type that marks what type of ownership a struct has over the object(s) -/// it contains; specifically, either `Owned` or `Shared`. +/// it contains; specifically, either [`Owned`] or [`Shared`]. pub trait Ownership: Any {} impl Ownership for Owned {} impl Ownership for Shared {} /// A pointer type for Objective-C's reference counted objects. /// -/// The object of an `Id` is retained and sent a `release` message when -/// the `Id` is dropped. +/// The object of an [`Id`] is retained and sent a `release` message when +/// the [`Id`] is dropped. /// -/// An `Id` may be either `Owned` or `Shared`, represented by the types `Id` -/// and `ShareId`, respectively. If owned, there are no other references to the -/// object and the `Id` can be mutably dereferenced. `ShareId`, however, can -/// only be immutably dereferenced because there may be other references to the -/// object, but a `ShareId` can be cloned to provide more references to the -/// object. An owned `Id` can be "downgraded" freely to a `ShareId`, but there -/// is no way to safely upgrade back. +/// An [`Id`] may be either [`Owned`] or [`Shared`], represented by the types +/// [`Id`] and [`ShareId`], respectively. +/// If owned, there are no other references to the object and the [`Id`] can +/// be mutably dereferenced. +/// [`ShareId`], however, can only be immutably dereferenced because there may +/// be other references to the object, but a [`ShareId`] can be cloned to +/// provide more references to the object. +/// An owned [`Id`] can be "downgraded" freely to a [`ShareId`], but there is +/// no way to safely upgrade back. pub struct Id { ptr: StrongPtr, item: PhantomData, @@ -52,8 +54,12 @@ where } } - /// Constructs an `Id` from a pointer to an unretained object and - /// retains it. Panics if the pointer is null. + /// Constructs an [`Id`] from a pointer to an unretained object and + /// retains it. + /// + /// # Panics + /// + /// Panics if the pointer is null. /// /// # Safety /// @@ -67,9 +73,13 @@ where Id::new(StrongPtr::retain(ptr as *mut Object)) } - /// Constructs an `Id` from a pointer to a retained object; this won't + /// Constructs an [`Id`] from a pointer to a retained object; this won't /// retain the pointer, so the caller must ensure the object has a +1 - /// retain count. Panics if the pointer is null. + /// retain count. + /// + /// # Panics + /// + /// Panics if the pointer is null. /// /// # Safety /// @@ -88,7 +98,7 @@ impl Id where T: Message, { - /// "Downgrade" an owned `Id` to a `ShareId`, allowing it to be cloned. + /// Downgrade an owned [`Id`] to a [`ShareId`], allowing it to be cloned. pub fn share(self) -> ShareId { let Id { ptr, .. } = self; unsafe { Id::new(ptr) } @@ -162,7 +172,7 @@ impl fmt::Pointer for Id { } } -/// A convenient alias for a shared `Id`. +/// A convenient alias for a shared [`Id`]. pub type ShareId = Id; /// A pointer type for a weak reference to an Objective-C reference counted @@ -176,7 +186,7 @@ impl WeakId where T: Message, { - /// Construct a new `WeakId` referencing the given `ShareId`. + /// Construct a new [`WeakId`] referencing the given [`ShareId`]. pub fn new(obj: &ShareId) -> WeakId { WeakId { ptr: obj.ptr.weak(), @@ -184,8 +194,9 @@ where } } - /// Load a `ShareId` from the `WeakId` if the object still exists. - /// Returns `None` if the object has been deallocated. + /// Load a [`ShareId`] from the [`WeakId`] if the object still exists. + /// + /// Returns [`None`] if the object has been deallocated. pub fn load(&self) -> Option> { let obj = self.ptr.load(); if obj.is_null() { diff --git a/objc_id/src/lib.rs b/objc_id/src/lib.rs index 99abae3bc..a905d0900 100644 --- a/objc_id/src/lib.rs +++ b/objc_id/src/lib.rs @@ -2,21 +2,20 @@ Rust smart pointers for Objective-C reference counting. To ensure that Objective-C objects are retained and released -at the proper times, we can use the [`Id`](struct.Id.html) struct. +at the proper times, we can use the [`Id`] struct. -To enforce aliasing rules, an `Id` can be either owned or shared; if it is -owned, meaning the `Id` is the only reference to the object, it can be mutably -dereferenced. An owned `Id` can be downgraded to a [`ShareId`](type.ShareId.html) -which can be cloned to allow multiple references. +To enforce aliasing rules, an [`Id`] can be either owned or shared; if it is +owned, meaning the [`Id`] is the only reference to the object, it can be +mutably dereferenced. An owned [`Id`] can be downgraded to a [`ShareId`] which +can be cloned to allow multiple references. -Weak references may be created using the [`WeakId`](struct.WeakId.html) struct. +Weak references may be created using the [`WeakId`] struct. ```no_run # use objc::msg_send; use objc::runtime::{Class, Object}; use objc_id::{Id, WeakId}; -# fn main() { let cls = Class::get("NSObject").unwrap(); let obj: Id = unsafe { Id::from_retained_ptr(msg_send![cls, new]) @@ -34,12 +33,13 @@ assert!(weak.load().is_some()); // After the object is deallocated, our weak pointer returns none drop(obj); assert!(weak.load().is_none()); -# } ``` */ // This crate is, but its dependencies are not #![no_std] +// Update in Cargo.toml as well. +#![doc(html_root_url = "https://docs.rs/objc_id/0.1.1")] pub use id::{Id, Owned, Ownership, ShareId, Shared, WeakId};