Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation #13

Merged
merged 9 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"objc_encode",
"objc_exception",
"objc_foundation",
"objc_foundation_derive",
"objc_id",
]
exclude = ["objc/tests-ios"]
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)
19 changes: 11 additions & 8 deletions objc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 <mads@marquart.dk>"]
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/**",
]
Expand Down
38 changes: 27 additions & 11 deletions objc/README.md
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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])
Expand Down Expand Up @@ -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();

Expand Down
2 changes: 1 addition & 1 deletion examples/objc.rs → objc/examples/introspection.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
8 changes: 4 additions & 4 deletions objc/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<c_void>,
}

impl CachedSel {
/// Constructs a new `CachedSel`.
/// Constructs a new [`CachedSel`].
pub const fn new() -> CachedSel {
CachedSel {
ptr: AtomicPtr::new(ptr::null_mut()),
Expand All @@ -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<Class>,
}

impl CachedClass {
/// Constructs a new `CachedClass`.
/// Constructs a new [`CachedClass`].
pub const fn new() -> CachedClass {
CachedClass {
ptr: AtomicPtr::new(ptr::null_mut()),
Expand Down
71 changes: 40 additions & 31 deletions objc/src/declare.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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();

Expand All @@ -30,7 +29,6 @@ unsafe {
}

decl.register();
# }
```
*/

Expand All @@ -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;
}

Expand Down Expand Up @@ -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> {
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`
Expand All @@ -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
///
Expand All @@ -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
///
Expand All @@ -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<T>(&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<T: Encode>(&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::<T>();
Expand All @@ -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;
Expand All @@ -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<ProtocolDecl> {
let c_name = CString::new(name).unwrap();
let proto = unsafe { runtime::objc_allocateProtocol(c_name.as_ptr()) };
Expand Down Expand Up @@ -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<Args, Ret>(&mut self, sel: Sel, is_required: bool)
where
Args: EncodeArguments,
Expand All @@ -312,7 +321,7 @@ impl ProtocolDecl {
self.add_method_description_common::<Args, Ret>(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<Args, Ret>(&mut self, sel: Sel, is_required: bool)
where
Args: EncodeArguments,
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion objc/src/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>];
Expand Down
15 changes: 7 additions & 8 deletions objc/src/exception.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use objc_exception;

use crate::rc::StrongPtr;
use crate::runtime::Object;

Expand All @@ -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<F, R>(closure: F) -> Result<R, StrongPtr>
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<R>(closure: impl FnOnce() -> R) -> Result<R, StrongPtr> {
objc_exception::r#try(closure).map_err(|exception| StrongPtr::new(exception as *mut Object))
}
12 changes: 10 additions & 2 deletions objc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down
Loading