Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/objc/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"b75b0c2c69a1b22b3e8a554f94353c423aef7e3891a66eefdee0b3a0813debf7","Cargo.lock":"a133d68c72c3735526ec3dcae9cfcd8928d19de7532940488f4527d1946fb954","Cargo.toml":"d051e9534ddcac152d11d2c2b6e040136b22397fb5579867fd3de67c0c3b44f3","LICENSE.txt":"e353f37b12aefbb9f9b29490e837cfee05d9bda70804b3562839a3285c1df1e5","README.md":"2798cf78a640ea9fb83bdf27e2c82d98d9f8f7459196ab9db10372fb843c7a65","examples/example.rs":"df5fd939ffa46505b368e4e31aa0a0b144202fbceac72e5343bedb706313ef5e","src/declare.rs":"a4409a3b849413af55398b9b6a86ca482bdea94dd16ce818b39d420228426b54","src/encode.rs":"6e792c73f7cfced248f20cebe93dc038a39d25bdd9cbe1a115464b7baa02885b","src/exception.rs":"a641f9fdb9267e1d44f680b685d650faa2931d5d22949b621c8e2783ed534a4f","src/lib.rs":"1b03c53c792b0abe909d2958d7b692b2264ae0f25a109c15dacf57da2352f6f7","src/macros.rs":"b0d82088510fa6a14b1dfa240e91f85b0d13536bbf1a28d33a5dc932409b7279","src/message/apple/arm.rs":"3df72141b9fa48e7eab13b33acfa76c0eae730c2eedad0cc92ed7f89c51ca0da","src/message/apple/arm64.rs":"3efa598e34232c1e1c2171de864beac7f79e10f85807b23d10537335e0e84bd3","src/message/apple/mod.rs":"8aa9b9419084f92acc4468dae647b6bc3bd4570de0dbffe82dd8b6a18883345e","src/message/apple/x86.rs":"a268b01e54d0c7cbd9ae765815524fbd5f7c92c339f110f1f3d76877e5238597","src/message/apple/x86_64.rs":"bb64ad8de038b65cda61eaa55a46ce56795aeb36b574dc4dbbfd0d328aa23889","src/message/gnustep.rs":"15bbf9abc5aa0edc25b8b1d9622ebcacc33fd1103fe20a6a93ba9d82ca1b262d","src/message/mod.rs":"aa9da24db7d02ed7d827d78d53936c132fc9302e7fdc09380bdf7021ddd16ae6","src/message/verify.rs":"0047219354c49568a14f7aa7a5bb91edca16e5636a30c66c15a1533668759845","src/rc/autorelease.rs":"f56e26a5f866b5dbbe5c336289bbe21d5a5872928d504c5dfdfda3eeaedd5a3e","src/rc/mod.rs":"ce4b5206fa8273ad3931376d18c1b9aca6cef8172eb2ff8daf962fee710db9d7","src/rc/strong.rs":"f472889e5827cd67f6df62f50e55fdc2101bcdfeb59c7d39dacc5f30a0ed06bb","src/rc/weak.rs":"0b4f77abcd9f1eec1993b6cc6f3db564d90aafe3dbf15233a6f268ded48ef6cb","src/runtime.rs":"69b33722d727faef47e3fb14e68bb18b96a970930a1f9b244e2bb4e161d67874","src/test_utils.rs":"db73875ff5ae4761187d3691998829a689e3dfd26b9812bdebc1bcae0388f78b"},"package":"915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"}

117
vendor/objc/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,117 @@
## 0.2.7
### Fixed
* Uses of `msg_send!` will now correctly fail to compile if no return type
can be inferred, instead of relying on an edge case of the compiler
that will soon change and silently cause undefined behavior.
## 0.2.6
### Fixed
* Suppressed a deprecation warning in `sel!`, `msg_send!`, and `class!`.
## 0.2.5
### Added
* `autoreleasepool` returns the value returned by its body closure.
## 0.2.4
### Added
* Added an `rc` module with reference counting utilities:
`StrongPtr`, `WeakPtr`, and `autoreleasepool`.
* Added some reference counting ABI foreign functions to the `runtime` module.
### Fixed
* Messaging nil under GNUstep now correctly returns zeroed results for all
return types.
## 0.2.3
### Added
* Added a `class!` macro for getting statically-known classes. The result is
non-optional (avoiding a need to unwrap) and cached so each usage will only
look up the class once.
* Added caching to the `sel!` macro so that each usage will only register the
selector once.
### Fixed
* Fixed the implementation of `objc::runtime` structs so there can't be unsound
references to uninhabited types.
## 0.2.2
### Added
* Implemented `Sync` and `Send` for `Sel`.
## 0.2.1
### Added
* Added support for working with protocols with the `Protocol` struct.
The protocols a class conforms to can be examined with the new
`Class::adopted_protocols` and `Class::conforms_to` methods.
* Protocols can be declared using the new `ProtocolDecl` struct.
## 0.2.0
### Added
* Added verification for the types used when sending messages.
This can be enabled for all messages with the `"verify_message"` feature,
or you can test before sending specific messages with the
`Message::verify_message` method. Verification errors are reported using the
new `MessageError` struct.
* Added support for the GNUstep runtime!
Operating systems besides OSX and iOS will fall back to the GNUstep runtime.
* Root classes can be declared by using the `ClassDecl::root` constructor.
### Changed
* 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.
* Dynamic messaging was moved into the `Message` trait; instead of
`().send(obj, sel!(description))`, use
`obj.send_message(sel!(description), ())`.
* Rearranged the parameters to `ClassDecl::new` for consistency; instead of
`ClassDecl::new(superclass, "MyObject")`, use
`ClassDecl::new("MyObject", superclass)`.
* Overhauled the `MethodImplementation` trait. Encodings are now accessed
through the `MethodImplementation::Args` associated type. The `imp_for`
method was replaced with `imp` and no longer takes a selector or returns an
`UnequalArgsError`, although `ClassDecl::add_method` still validates the
number of arguments.
* Updated the definition of `Imp` to not use the old dispatch prototypes.
To invoke an `Imp`, it must first be transmuted to the correct type.
* Removed `objc_msgSend` functions from the `runtime` module; the availability
of these functions varies and they shouldn't be called without trasmuting,
so they are now hidden as an implementation detail of messaging.
### Fixed
* Corrected alignment of ivars in `ClassDecl`; declared classes may now have a
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
used, rather than from within the implementation of messaging.

41
vendor/objc/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,41 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "gcc"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "objc"
version = "0.2.7"
dependencies = [
"malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "objc_exception"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
"checksum libc 0.2.57 (registry+https://github.com/rust-lang/crates.io-index)" = "a844cabbd5a77e60403a58af576f0a1baa83c3dd2670be63e615bd24fc58b82d"
"checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
"checksum objc_exception 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "098cd29a2fa3c230d3463ae069cecccc3fdfd64c0d2496ab5b96f82dab6a00dc"

33
vendor/objc/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,33 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
name = "objc"
version = "0.2.7"
authors = ["Steven Sheldon"]
exclude = [".gitignore", ".travis.yml", "doc.sh", "travis_install.sh", "travis_test.sh", "tests-ios/**"]
description = "Objective-C Runtime bindings and wrapper for Rust."
documentation = "http://ssheldon.github.io/rust-objc/objc/"
readme = "README.md"
keywords = ["objective-c", "osx", "ios", "cocoa", "uikit"]
license = "MIT"
repository = "http://github.com/SSheldon/rust-objc"
[dependencies.malloc_buf]
version = "0.0"
[dependencies.objc_exception]
version = "0.1"
optional = true
[features]
exception = ["objc_exception"]
verify_message = []

21
vendor/objc/LICENSE.txt vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Steven Sheldon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

99
vendor/objc/README.md vendored Normal file
View File

@@ -0,0 +1,99 @@
Objective-C Runtime bindings and wrapper for Rust.
* Documentation: http://ssheldon.github.io/rust-objc/objc/
* Crate: https://crates.io/crates/objc
## Messaging objects
Objective-C objects can be messaged using the `msg_send!` macro:
``` rust
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];
```
## Reference counting
The utilities of the `rc` module provide ARC-like semantics for working with
Objective-C's reference counted objects in Rust.
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
// StrongPtr will release the object when dropped
let obj = unsafe {
StrongPtr::new(msg_send![class!(NSObject), new])
};
// Cloning retains the object an additional time
let cloned = obj.clone();
autoreleasepool(|| {
// Autorelease consumes the StrongPtr, but won't
// actually release until the end of an autoreleasepool
cloned.autorelease();
});
// Weak references won't retain the object
let weak = obj.weak();
drop(obj);
assert!(weak.load().is_null());
```
## Declaring classes
Classes can be declared using the `ClassDecl` struct. Instance variables and
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
let superclass = class!(NSObject);
let mut decl = ClassDecl::new("MyNumber", superclass).unwrap();
// Add an instance variable
decl.add_ivar::<u32>("_number");
// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
unsafe { *this.get_ivar("_number") }
}
unsafe {
decl.add_method(sel!(number),
my_number_get as extern fn(&Object, Sel) -> u32);
}
decl.register();
```
## Exceptions
By default, if the `msg_send!` macro causes an exception to be thrown, this
will unwind into Rust resulting in unsafe, undefined behavior.
However, this crate has an `"exception"` feature which, when enabled, wraps
each `msg_send!` in a `@try`/`@catch` and panics if an exception is caught,
preventing Objective-C from unwinding into Rust.
## Message type verification
The Objective-C runtime includes encodings for each method that describe the
argument and return types. This crate can take advantage of these encodings to
verify that the types used in Rust match the types encoded for the method.
To use this functionality, enable the `"verify_message"` feature.
With this feature enabled, type checking is performed for every message send,
which also requires that all arguments and return values for all messages
implement `Encode`.
If this requirement is burdensome or you'd rather just verify specific messages,
you can call the `Message::verify_message` method for specific selectors.
## Support for other Operating Systems
The bindings can be used on Linux or *BSD utilizing the
[GNUstep Objective-C runtime](https://www.github.com/gnustep/libobjc2).

45
vendor/objc/examples/example.rs vendored Normal file
View File

@@ -0,0 +1,45 @@
#[macro_use]
extern crate objc;
use objc::Encode;
use objc::rc::StrongPtr;
use objc::runtime::{Class, Object};
fn main() {
// Get a class
let cls = class!(NSObject);
println!("NSObject size: {}", cls.instance_size());
// Inspect its ivars
println!("NSObject ivars:");
for ivar in cls.instance_variables().iter() {
println!("{}", ivar.name());
}
// Allocate an instance
let obj = unsafe {
let obj: *mut Object = msg_send![cls, alloc];
let obj: *mut Object = msg_send![obj, init];
StrongPtr::new(obj)
};
println!("NSObject address: {:p}", obj);
// Access an ivar of the object
let isa: *const Class = unsafe {
*(**obj).get_ivar("isa")
};
println!("NSObject isa: {:?}", isa);
// Inspect a method of the class
let hash_sel = sel!(hash);
let hash_method = cls.instance_method(hash_sel).unwrap();
let hash_return = hash_method.return_type();
println!("-[NSObject hash] return type: {:?}", hash_return);
assert!(hash_return == usize::encode());
// Invoke a method on the object
let hash: usize = unsafe {
msg_send![*obj, hash]
};
println!("NSObject hash: {}", hash);
}

340
vendor/objc/src/declare.rs vendored Normal file
View File

@@ -0,0 +1,340 @@
/*!
Functionality for declaring Objective-C classes.
Classes can be declared using the `ClassDecl` struct. Instance variables and
methods can then be added before the class is ultimately registered.
# Example
The following example demonstrates declaring a class named `MyNumber` that has
one ivar, a `u32` named `_number` and a `number` method that returns it:
``` no_run
# #[macro_use] extern crate objc;
# use objc::declare::ClassDecl;
# use objc::runtime::{Class, Object, Sel};
# fn main() {
let superclass = class!(NSObject);
let mut decl = ClassDecl::new("MyNumber", superclass).unwrap();
// Add an instance variable
decl.add_ivar::<u32>("_number");
// Add an ObjC method for getting the number
extern fn my_number_get(this: &Object, _cmd: Sel) -> u32 {
unsafe { *this.get_ivar("_number") }
}
unsafe {
decl.add_method(sel!(number),
my_number_get as extern fn(&Object, Sel) -> u32);
}
decl.register();
# }
```
*/
use std::ffi::CString;
use std::mem;
use std::ptr;
use runtime::{BOOL, Class, Imp, NO, Object, Protocol, Sel, self};
use {Encode, EncodeArguments, Encoding, Message};
/// Types that can be used as the implementation of an Objective-C method.
pub trait MethodImplementation {
/// The callee type of the method.
type Callee: Message;
/// The return type of the method.
type Ret: Encode;
/// The argument types of the method.
type Args: EncodeArguments;
/// Returns self as an `Imp` of a method.
fn imp(self) -> Imp;
}
macro_rules! method_decl_impl {
(-$s:ident, $r:ident, $f:ty, $($t:ident),*) => (
impl<$s, $r $(, $t)*> MethodImplementation for $f
where $s: Message, $r: Encode $(, $t: Encode)* {
type Callee = $s;
type Ret = $r;
type Args = ($($t,)*);
fn imp(self) -> Imp {
unsafe { mem::transmute(self) }
}
}
);
($($t:ident),*) => (
method_decl_impl!(-T, R, extern fn(&T, Sel $(, $t)*) -> R, $($t),*);
method_decl_impl!(-T, R, extern fn(&mut T, Sel $(, $t)*) -> R, $($t),*);
);
}
method_decl_impl!();
method_decl_impl!(A);
method_decl_impl!(A, B);
method_decl_impl!(A, B, C);
method_decl_impl!(A, B, C, D);
method_decl_impl!(A, B, C, D, E);
method_decl_impl!(A, B, C, D, E, F);
method_decl_impl!(A, B, C, D, E, F, G);
method_decl_impl!(A, B, C, D, E, F, G, H);
method_decl_impl!(A, B, C, D, E, F, G, H, I);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K);
method_decl_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
fn count_args(sel: Sel) -> usize {
sel.name().chars().filter(|&c| c == ':').count()
}
fn method_type_encoding(ret: &Encoding, args: &[Encoding]) -> CString {
let mut types = ret.as_str().to_owned();
// First two arguments are always self and the selector
types.push_str(<*mut Object>::encode().as_str());
types.push_str(Sel::encode().as_str());
types.extend(args.iter().map(|e| e.as_str()));
CString::new(types).unwrap()
}
fn log2_align_of<T>() -> u8 {
let align = mem::align_of::<T>();
// Alignments are required to be powers of 2
debug_assert!(align.count_ones() == 1);
// log2 of a power of 2 is the number of trailing zeros
align.trailing_zeros() as u8
}
/// A type for declaring a new class and adding new methods and ivars to it
/// before registering it.
pub struct ClassDecl {
cls: *mut Class,
}
impl ClassDecl {
fn with_superclass(name: &str, superclass: Option<&Class>)
-> Option<ClassDecl> {
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)
};
if cls.is_null() {
None
} else {
Some(ClassDecl { cls: cls })
}
}
/// 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.
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.
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`
used by ARC, will not be present otherwise.
*/
pub fn root(name: &str, intitialize_fn: extern fn(&Class, Sel))
-> Option<ClassDecl> {
let mut decl = ClassDecl::with_superclass(name, None);
if let Some(ref mut decl) = decl {
unsafe {
decl.add_class_method(sel!(initialize), intitialize_fn);
}
}
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.
/// 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<F>(&mut self, sel: Sel, func: F)
where F: MethodImplementation<Callee=Object> {
let encs = F::Args::encodings();
let encs = encs.as_ref();
let sel_args = count_args(sel);
assert!(sel_args == encs.len(),
"Selector accepts {} arguments, but function accepts {}",
sel_args, encs.len(),
);
let types = method_type_encoding(&F::Ret::encode(), encs);
let success = runtime::class_addMethod(self.cls, sel, func.imp(),
types.as_ptr());
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.
/// 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<F>(&mut self, sel: Sel, func: F)
where F: MethodImplementation<Callee=Class> {
let encs = F::Args::encodings();
let encs = encs.as_ref();
let sel_args = count_args(sel);
assert!(sel_args == encs.len(),
"Selector accepts {} arguments, but function accepts {}",
sel_args, encs.len(),
);
let types = method_type_encoding(&F::Ret::encode(), encs);
let metaclass = (*self.cls).metaclass() as *const _ as *mut _;
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<T>(&mut self, name: &str) where T: Encode {
let c_name = CString::new(name).unwrap();
let encoding = CString::new(T::encode().as_str()).unwrap();
let size = mem::size_of::<T>();
let align = log2_align_of::<T>();
let success = unsafe {
runtime::class_addIvar(self.cls, c_name.as_ptr(), size, align,
encoding.as_ptr())
};
assert!(success != NO, "Failed to add ivar {}", name);
}
/// Adds a 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`.
pub fn register(self) -> &'static Class {
unsafe {
let cls = self.cls;
runtime::objc_registerClassPair(cls);
// Forget self otherwise the class will be disposed in drop
mem::forget(self);
&*cls
}
}
}
impl Drop for ClassDecl {
fn drop(&mut self) {
unsafe {
runtime::objc_disposeClassPair(self.cls);
}
}
}
/// A type for declaring a new protocol and adding new methods to it
/// before registering it.
pub struct ProtocolDecl {
proto: *mut Protocol
}
impl ProtocolDecl {
/// 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())
};
if proto.is_null() {
None
} else {
Some(ProtocolDecl { proto: proto })
}
}
fn add_method_description_common<Args, Ret>(&mut self, sel: Sel, is_required: bool,
is_instance_method: bool)
where Args: EncodeArguments,
Ret: Encode {
let encs = Args::encodings();
let encs = encs.as_ref();
let sel_args = count_args(sel);
assert!(sel_args == encs.len(),
"Selector accepts {} arguments, but function accepts {}",
sel_args, encs.len(),
);
let types = method_type_encoding(&Ret::encode(), encs);
unsafe {
runtime::protocol_addMethodDescription(
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<Args, Ret>(&mut self, sel: Sel, is_required: bool)
where Args: EncodeArguments,
Ret: Encode {
self.add_method_description_common::<Args, Ret>(sel, is_required, true)
}
/// Adds a class method declaration with a given description to self.
pub fn add_class_method_description<Args, Ret>(&mut self, sel: Sel, is_required: bool)
where Args: EncodeArguments,
Ret: Encode {
self.add_method_description_common::<Args, Ret>(sel, is_required, false)
}
/// Adds a requirement on another protocol.
pub fn add_protocol(&mut self, proto: &Protocol) {
unsafe {
runtime::protocol_addProtocol(self.proto, proto);
}
}
/// Registers self, consuming it and returning a reference to the
/// newly registered `Protocol`.
pub fn register(self) -> &'static Protocol {
unsafe {
runtime::objc_registerProtocol(self.proto);
&*self.proto
}
}
}
#[cfg(test)]
mod tests {
use test_utils;
#[test]
fn test_custom_class() {
// Registering the custom class is in test_utils
let obj = test_utils::custom_object();
unsafe {
let _: () = msg_send![obj, setFoo:13u32];
let result: u32 = msg_send![obj, foo];
assert!(result == 13);
}
}
#[test]
fn test_class_method() {
let cls = test_utils::custom_class();
unsafe {
let result: u32 = msg_send![cls, classFoo];
assert!(result == 7);
}
}
}

279
vendor/objc/src/encode.rs vendored Normal file
View File

@@ -0,0 +1,279 @@
use std::ffi::CStr;
use std::fmt;
use std::os::raw::{c_char, c_void};
use std::str;
use malloc_buf::MallocBuffer;
use runtime::{Class, Object, Sel};
const QUALIFIERS: &'static [char] = &[
'r', // const
'n', // in
'N', // inout
'o', // out
'O', // bycopy
'R', // byref
'V', // oneway
];
#[cfg(target_pointer_width = "64")]
const CODE_INLINE_CAP: usize = 30;
#[cfg(target_pointer_width = "32")]
const CODE_INLINE_CAP: usize = 14;
enum Code {
Slice(&'static str),
Owned(String),
Inline(u8, [u8; CODE_INLINE_CAP]),
Malloc(MallocBuffer<u8>)
}
/// An Objective-C type encoding.
///
/// For more information, see Apple's documentation:
/// <https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html>
pub struct Encoding {
code: Code,
}
impl Encoding {
/// Constructs an `Encoding` from its string representation.
/// Unsafe because the caller must ensure the string is a valid encoding.
pub unsafe fn from_str(code: &str) -> Encoding {
from_str(code)
}
/// Returns self as a `str`.
pub fn as_str(&self) -> &str {
match self.code {
Code::Slice(code) => code,
Code::Owned(ref code) => code,
Code::Inline(len, ref bytes) => unsafe {
str::from_utf8_unchecked(&bytes[..len as usize])
},
Code::Malloc(ref buf) => unsafe {
str::from_utf8_unchecked(&buf[..buf.len() - 1])
},
}
}
}
impl Clone for Encoding {
fn clone(&self) -> Encoding {
if let Code::Slice(code) = self.code {
from_static_str(code)
} else {
from_str(self.as_str())
}
}
}
impl PartialEq for Encoding {
fn eq(&self, other: &Encoding) -> bool {
// strip qualifiers when comparing
let s = self.as_str().trim_left_matches(QUALIFIERS);
let o = other.as_str().trim_left_matches(QUALIFIERS);
s == o
}
}
impl fmt::Debug for Encoding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
pub fn from_static_str(code: &'static str) -> Encoding {
Encoding { code: Code::Slice(code) }
}
pub fn from_str(code: &str) -> Encoding {
if code.len() > CODE_INLINE_CAP {
Encoding { code: Code::Owned(code.to_owned()) }
} else {
let mut bytes = [0; CODE_INLINE_CAP];
for (dst, byte) in bytes.iter_mut().zip(code.bytes()) {
*dst = byte;
}
Encoding { code: Code::Inline(code.len() as u8, bytes) }
}
}
pub unsafe fn from_malloc_str(ptr: *mut c_char) -> Encoding {
let s = CStr::from_ptr(ptr);
let bytes = s.to_bytes_with_nul();
assert!(str::from_utf8(bytes).is_ok());
let buf = MallocBuffer::new(ptr as *mut u8, bytes.len()).unwrap();
Encoding { code: Code::Malloc(buf) }
}
/// 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.
pub unsafe trait Encode {
/// Returns the Objective-C type encoding for Self.
fn encode() -> Encoding;
}
macro_rules! encode_impls {
($($t:ty : $s:expr,)*) => ($(
unsafe impl Encode for $t {
fn encode() -> Encoding { from_static_str($s) }
}
)*);
}
encode_impls!(
i8: "c",
i16: "s",
i32: "i",
i64: "q",
u8: "C",
u16: "S",
u32: "I",
u64: "Q",
f32: "f",
f64: "d",
bool: "B",
(): "v",
*mut c_char: "*",
*const c_char: "r*",
*mut c_void: "^v",
*const c_void: "r^v",
Sel: ":",
);
unsafe impl Encode for isize {
#[cfg(target_pointer_width = "32")]
fn encode() -> Encoding { i32::encode() }
#[cfg(target_pointer_width = "64")]
fn encode() -> Encoding { i64::encode() }
}
unsafe impl Encode for usize {
#[cfg(target_pointer_width = "32")]
fn encode() -> Encoding { u32::encode() }
#[cfg(target_pointer_width = "64")]
fn encode() -> Encoding { u64::encode() }
}
macro_rules! encode_message_impl {
($code:expr, $name:ident) => (
encode_message_impl!($code, $name,);
);
($code:expr, $name:ident, $($t:ident),*) => (
unsafe impl<'a $(, $t)*> $crate::Encode for &'a $name<$($t),*> {
fn encode() -> Encoding { from_static_str($code) }
}
unsafe impl<'a $(, $t)*> $crate::Encode for &'a mut $name<$($t),*> {
fn encode() -> Encoding { from_static_str($code) }
}
unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a $name<$($t),*>> {
fn encode() -> Encoding { from_static_str($code) }
}
unsafe impl<'a $(, $t)*> $crate::Encode for Option<&'a mut $name<$($t),*>> {
fn encode() -> Encoding { from_static_str($code) }
}
unsafe impl<$($t),*> $crate::Encode for *const $name<$($t),*> {
fn encode() -> Encoding { from_static_str($code) }
}
unsafe impl<$($t),*> $crate::Encode for *mut $name<$($t),*> {
fn encode() -> Encoding { from_static_str($code) }
}
);
}
encode_message_impl!("@", Object);
encode_message_impl!("#", Class);
/// Types that represent a group of arguments, where each has an Objective-C
/// type encoding.
pub trait EncodeArguments {
/// The type as which the encodings for Self will be returned.
type Encs: AsRef<[Encoding]>;
/// Returns the Objective-C type encodings for Self.
fn encodings() -> Self::Encs;
}
macro_rules! count_idents {
() => (0);
($a:ident) => (1);
($a:ident, $($b:ident),+) => (1 + count_idents!($($b),*));
}
macro_rules! encode_args_impl {
($($t:ident),*) => (
impl<$($t: Encode),*> EncodeArguments for ($($t,)*) {
type Encs = [Encoding; count_idents!($($t),*)];
fn encodings() -> Self::Encs {
[
$($t::encode()),*
]
}
}
);
}
encode_args_impl!();
encode_args_impl!(A);
encode_args_impl!(A, B);
encode_args_impl!(A, B, C);
encode_args_impl!(A, B, C, D);
encode_args_impl!(A, B, C, D, E);
encode_args_impl!(A, B, C, D, E, F);
encode_args_impl!(A, B, C, D, E, F, G);
encode_args_impl!(A, B, C, D, E, F, G, H);
encode_args_impl!(A, B, C, D, E, F, G, H, I);
encode_args_impl!(A, B, C, D, E, F, G, H, I, J);
encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K);
encode_args_impl!(A, B, C, D, E, F, G, H, I, J, K, L);
#[cfg(test)]
mod tests {
use runtime::{Class, Object, Sel};
use super::{Encode, Encoding};
#[test]
fn test_encode() {
assert!(u32::encode().as_str() == "I");
assert!(<()>::encode().as_str() == "v");
assert!(<&Object>::encode().as_str() == "@");
assert!(<*mut Object>::encode().as_str() == "@");
assert!(<&Class>::encode().as_str() == "#");
assert!(Sel::encode().as_str() == ":");
}
#[test]
fn test_inline_encoding() {
let enc = unsafe { Encoding::from_str("C") };
assert!(enc.as_str() == "C");
let enc2 = enc.clone();
assert!(enc2 == enc);
assert!(enc2.as_str() == "C");
}
#[test]
fn test_owned_encoding() {
let s = "{Test=CCCCCCCCCCCCCCCCCCCCCCCCC}";
let enc = unsafe { Encoding::from_str(s) };
assert!(enc.as_str() == s);
let enc2 = enc.clone();
assert!(enc2 == enc);
assert!(enc2.as_str() == s);
}
}

11
vendor/objc/src/exception.rs vendored Normal file
View File

@@ -0,0 +1,11 @@
use objc_exception;
use rc::StrongPtr;
use runtime::Object;
pub unsafe fn try<F, R>(closure: F) -> Result<R, StrongPtr>
where F: FnOnce() -> R {
objc_exception::try(closure).map_err(|exception| {
StrongPtr::new(exception as *mut Object)
})
}

90
vendor/objc/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
/*!
Objective-C Runtime bindings and wrapper for Rust.
# Messaging objects
Objective-C objects can be messaged using the [`msg_send!`](macro.msg_send!.html) macro:
``` no_run
# #[macro_use] extern crate objc;
# use objc::runtime::{BOOL, Class, Object};
# fn main() {
# unsafe {
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];
# }
# }
```
# Reference counting
Utilities for reference counting Objective-C objects are provided in the
[`rc`](rc/index.html) module.
# Declaring classes
Objective-C classes can even be declared from Rust using the functionality of
the [`declare`](declare/index.html) module.
# Exceptions
By default, if the `msg_send!` macro causes an exception to be thrown, this
will unwind into Rust resulting in unsafe, undefined behavior.
However, this crate has an `"exception"` feature which, when enabled, wraps
each `msg_send!` in a `@try`/`@catch` and panics if an exception is caught,
preventing Objective-C from unwinding into Rust.
# Message type verification
The Objective-C runtime includes encodings for each method that describe the
argument and return types. This crate can take advantage of these encodings to
verify that the types used in Rust match the types encoded for the method.
To use this functionality, enable the `"verify_message"` feature.
With this feature enabled, type checking is performed for every message send,
which also requires that all arguments and return values for all messages
implement `Encode`.
If this requirement is burdensome or you'd rather
just verify specific messages, you can call the
[`Message::verify_message`](trait.Message.html#method.verify_message) method
for specific selectors.
# Support for other Operating Systems
The bindings can be used on Linux or *BSD utilizing the
[GNUstep Objective-C runtime](https://www.github.com/gnustep/libobjc2).
*/
#![crate_name = "objc"]
#![crate_type = "lib"]
#![warn(missing_docs)]
extern crate malloc_buf;
#[cfg(feature = "exception")]
extern crate objc_exception;
pub use encode::{Encode, EncodeArguments, Encoding};
pub use message::{Message, MessageArguments, MessageError};
pub use message::send_message as __send_message;
pub use message::send_super_message as __send_super_message;
#[macro_use]
mod macros;
pub mod runtime;
pub mod declare;
pub mod rc;
mod encode;
#[cfg(feature = "exception")]
mod exception;
mod message;
#[cfg(test)]
mod test_utils;

148
vendor/objc/src/macros.rs vendored Normal file
View File

@@ -0,0 +1,148 @@
/**
Gets a reference to a `Class`.
Panics if no class with the given name can be found.
To check for a class that may not exist, use `Class::get`.
# Example
``` no_run
# #[macro_use] extern crate objc;
# fn main() {
let cls = class!(NSObject);
# }
```
*/
#[macro_export]
macro_rules! class {
($name:ident) => ({
#[allow(deprecated)]
#[inline(always)]
fn get_class(name: &str) -> Option<&'static $crate::runtime::Class> {
unsafe {
#[cfg_attr(feature = "cargo-clippy", allow(replace_consts))]
static CLASS: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT;
// `Relaxed` should be fine since `objc_getClass` is thread-safe.
let ptr = CLASS.load(::std::sync::atomic::Ordering::Relaxed) as *const $crate::runtime::Class;
if ptr.is_null() {
let cls = $crate::runtime::objc_getClass(name.as_ptr() as *const _);
CLASS.store(cls as usize, ::std::sync::atomic::Ordering::Relaxed);
if cls.is_null() { None } else { Some(&*cls) }
} else {
Some(&*ptr)
}
}
}
match get_class(concat!(stringify!($name), '\0')) {
Some(cls) => cls,
None => panic!("Class with name {} could not be found", stringify!($name)),
}
})
}
#[doc(hidden)]
#[macro_export]
macro_rules! sel_impl {
// Declare a function to hide unsafety, otherwise we can trigger the
// unused_unsafe lint; see rust-lang/rust#8472
($name:expr) => ({
#[allow(deprecated)]
#[inline(always)]
fn register_sel(name: &str) -> $crate::runtime::Sel {
unsafe {
#[cfg_attr(feature = "cargo-clippy", allow(replace_consts))]
static SEL: ::std::sync::atomic::AtomicUsize = ::std::sync::atomic::ATOMIC_USIZE_INIT;
let ptr = SEL.load(::std::sync::atomic::Ordering::Relaxed) as *const ::std::os::raw::c_void;
// It should be fine to use `Relaxed` ordering here because `sel_registerName` is
// thread-safe.
if ptr.is_null() {
let sel = $crate::runtime::sel_registerName(name.as_ptr() as *const _);
SEL.store(sel.as_ptr() as usize, ::std::sync::atomic::Ordering::Relaxed);
sel
} else {
$crate::runtime::Sel::from_ptr(ptr)
}
}
}
register_sel($name)
})
}
/**
Registers a selector, returning a `Sel`.
# Example
```
# #[macro_use] extern crate objc;
# fn main() {
let sel = sel!(description);
let sel = sel!(setObject:forKey:);
# }
```
*/
#[macro_export]
macro_rules! sel {
($name:ident) => ({sel_impl!(concat!(stringify!($name), '\0'))});
($($name:ident :)+) => ({sel_impl!(concat!($(stringify!($name), ':'),+, '\0'))});
}
/**
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`.
The syntax is similar to the message syntax in Objective-C.
Variadic arguments are not currently supported.
# Example
``` no_run
# #[macro_use] extern crate objc;
# 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]
macro_rules! msg_send {
(super($obj:expr, $superclass:expr), $name:ident) => ({
let sel = sel!($name);
let result;
match $crate::__send_super_message(&*$obj, $superclass, sel, ()) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
(super($obj:expr, $superclass:expr), $($name:ident : $arg:expr)+) => ({
let sel = sel!($($name:)+);
let result;
match $crate::__send_super_message(&*$obj, $superclass, sel, ($($arg,)*)) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
($obj:expr, $name:ident) => ({
let sel = sel!($name);
let result;
match $crate::__send_message(&*$obj, sel, ()) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
($obj:expr, $($name:ident : $arg:expr)+) => ({
let sel = sel!($($name:)+);
let result;
match $crate::__send_message(&*$obj, sel, ($($arg,)*)) {
Err(s) => panic!("{}", s),
Ok(r) => result = r,
}
result
});
}

40
vendor/objc/src/message/apple/arm.rs vendored Normal file
View File

@@ -0,0 +1,40 @@
use std::any::{Any, TypeId};
use std::mem;
use runtime::Imp;
extern {
fn objc_msgSend();
fn objc_msgSend_stret();
fn objc_msgSendSuper();
fn objc_msgSendSuper_stret();
}
pub fn msg_send_fn<R: Any>() -> Imp {
// Double-word sized fundamental data types don't use stret,
// but any composite type larger than 4 bytes does.
// <http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf>
let type_id = TypeId::of::<R>();
if mem::size_of::<R>() <= 4 ||
type_id == TypeId::of::<i64>() ||
type_id == TypeId::of::<u64>() ||
type_id == TypeId::of::<f64>() {
objc_msgSend
} else {
objc_msgSend_stret
}
}
pub fn msg_send_super_fn<R: Any>() -> Imp {
let type_id = TypeId::of::<R>();
if mem::size_of::<R>() <= 4 ||
type_id == TypeId::of::<i64>() ||
type_id == TypeId::of::<u64>() ||
type_id == TypeId::of::<f64>() {
objc_msgSendSuper
} else {
objc_msgSendSuper_stret
}
}

18
vendor/objc/src/message/apple/arm64.rs vendored Normal file
View File

@@ -0,0 +1,18 @@
use runtime::Imp;
extern {
fn objc_msgSend();
fn objc_msgSendSuper();
}
pub fn msg_send_fn<R>() -> Imp {
// stret is not even available in arm64.
// <https://twitter.com/gparker/status/378079715824660480>
objc_msgSend
}
pub fn msg_send_super_fn<R>() -> Imp {
objc_msgSendSuper
}

40
vendor/objc/src/message/apple/mod.rs vendored Normal file
View File

@@ -0,0 +1,40 @@
use std::any::Any;
use runtime::{Class, Object, Sel};
use super::{Message, MessageArguments, MessageError, Super};
#[cfg(target_arch = "x86")]
#[path = "x86.rs"]
mod arch;
#[cfg(target_arch = "x86_64")]
#[path = "x86_64.rs"]
mod arch;
#[cfg(target_arch = "arm")]
#[path = "arm.rs"]
mod arch;
#[cfg(target_arch = "aarch64")]
#[path = "arm64.rs"]
mod arch;
use self::arch::{msg_send_fn, msg_send_super_fn};
pub unsafe fn send_unverified<T, A, R>(obj: *const T, sel: Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
let receiver = obj as *mut T as *mut Object;
let msg_send_fn = msg_send_fn::<R>();
objc_try!({
A::invoke(msg_send_fn, receiver, sel, args)
})
}
pub unsafe fn send_super_unverified<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
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::<R>();
objc_try!({
A::invoke(msg_send_fn, receiver, sel, args)
})
}

40
vendor/objc/src/message/apple/x86.rs vendored Normal file
View File

@@ -0,0 +1,40 @@
use std::any::{Any, TypeId};
use std::mem;
use runtime::Imp;
extern {
fn objc_msgSend();
fn objc_msgSend_fpret();
fn objc_msgSend_stret();
fn objc_msgSendSuper();
fn objc_msgSendSuper_stret();
}
pub fn msg_send_fn<R: Any>() -> 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.
// <https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html>
let type_id = TypeId::of::<R>();
let size = mem::size_of::<R>();
if type_id == TypeId::of::<f32>() ||
type_id == TypeId::of::<f64>() {
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<R: Any>() -> Imp {
let size = mem::size_of::<R>();
if size == 0 || size == 1 || size == 2 || size == 4 || size == 8 {
objc_msgSendSuper
} else {
objc_msgSendSuper_stret
}
}

32
vendor/objc/src/message/apple/x86_64.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
use std::mem;
use runtime::Imp;
extern {
fn objc_msgSend();
fn objc_msgSend_stret();
fn objc_msgSendSuper();
fn objc_msgSendSuper_stret();
}
pub fn msg_send_fn<R>() -> 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.
// <http://people.freebsd.org/~obrien/amd64-elf-abi.pdf>
if mem::size_of::<R>() <= 16 {
objc_msgSend
} else {
objc_msgSend_stret
}
}
pub fn msg_send_super_fn<R>() -> Imp {
if mem::size_of::<R>() <= 16 {
objc_msgSendSuper
} else {
objc_msgSendSuper_stret
}
}

35
vendor/objc/src/message/gnustep.rs vendored Normal file
View File

@@ -0,0 +1,35 @@
use std::any::Any;
use std::mem;
use runtime::{Class, Object, Imp, Sel};
use super::{Message, MessageArguments, MessageError, Super};
extern {
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<T, A, R>(obj: *const T, sel: Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
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)
})
}
pub unsafe fn send_super_unverified<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
let receiver = obj as *mut T as *mut Object;
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)
})
}

296
vendor/objc/src/message/mod.rs vendored Normal file
View File

@@ -0,0 +1,296 @@
use std::any::Any;
use std::error::Error;
use std::fmt;
use std::mem;
use runtime::{Class, Imp, Object, Sel};
use {Encode, EncodeArguments};
#[cfg(feature = "exception")]
macro_rules! objc_try {
($b:block) => (
$crate::exception::try(|| $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))
}
mod verify;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[path = "apple/mod.rs"]
mod platform;
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
#[path = "gnustep.rs"]
mod platform;
use self::platform::{send_unverified, send_super_unverified};
use self::verify::verify_message_signature;
/// Specifies the superclass of an instance.
#[repr(C)]
pub 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.
pub unsafe trait Message {
/**
Sends a message to self with the given selector and arguments.
The correct version of `objc_msgSend` will be chosen based on the
return type. For more information, see Apple's documentation:
<https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778>
If the selector is known at compile-time, it is recommended to use the
`msg_send!` macro rather than this method.
*/
#[cfg(not(feature = "verify_message"))]
unsafe fn send_message<A, R>(&self, sel: Sel, args: A)
-> Result<R, MessageError>
where Self: Sized, A: MessageArguments, R: Any {
send_message(self, sel, args)
}
#[cfg(feature = "verify_message")]
unsafe fn send_message<A, R>(&self, sel: Sel, args: A)
-> Result<R, MessageError>
where Self: Sized, A: MessageArguments + EncodeArguments,
R: Any + Encode {
send_message(self, sel, args)
}
/**
Verifies that the argument and return types match the encoding of the
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 type `R`.
# Example
``` no_run
# #[macro_use] extern crate objc;
# 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<A, R>(&self, sel: Sel) -> Result<(), MessageError>
where Self: Sized, A: EncodeArguments, R: Encode {
let obj = unsafe { &*(self as *const _ as *const Object) };
verify_message_signature::<A, R>(obj.class(), sel)
}
}
unsafe impl Message for Object { }
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.
///
/// 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<R>(imp: Imp, obj: *mut Object, sel: Sel, args: Self) -> R
where R: Any;
}
macro_rules! message_args_impl {
($($a:ident : $t:ident),*) => (
impl<$($t),*> MessageArguments for ($($t,)*) {
unsafe fn invoke<R>(imp: Imp, obj: *mut Object, sel: Sel, ($($a,)*): Self) -> R
where R: Any {
let imp: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
mem::transmute(imp);
imp(obj, sel $(, $a)*)
}
}
);
}
message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);
/**
An error encountered while attempting to send a message.
Currently, an error may be returned in two cases:
* an Objective-C exception is thrown and the `exception` feature is enabled
* the encodings of the arguments do not match the encoding of the method
and the `verify_message` feature is enabled
*/
#[derive(Debug)]
pub struct MessageError(String);
impl fmt::Display for MessageError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl Error for MessageError {
fn description(&self) -> &str {
&self.0
}
}
#[doc(hidden)]
#[inline(always)]
#[cfg(not(feature = "verify_message"))]
pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
send_unverified(obj, sel, args)
}
#[doc(hidden)]
#[inline(always)]
#[cfg(feature = "verify_message")]
pub unsafe fn send_message<T, A, R>(obj: *const T, sel: Sel, args: A)
-> Result<R, MessageError>
where T: Message, A: MessageArguments + EncodeArguments,
R: Any + Encode {
let cls = if obj.is_null() {
return Err(MessageError(format!("Messaging {:?} to nil", sel)));
} else {
(*(obj as *const Object)).class()
};
verify_message_signature::<A, R>(cls, sel).and_then(|_| {
send_unverified(obj, sel, args)
})
}
#[doc(hidden)]
#[inline(always)]
#[cfg(not(feature = "verify_message"))]
pub unsafe fn send_super_message<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments, R: Any {
send_super_unverified(obj, superclass, sel, args)
}
#[doc(hidden)]
#[inline(always)]
#[cfg(feature = "verify_message")]
pub unsafe fn send_super_message<T, A, R>(obj: *const T, superclass: &Class,
sel: Sel, args: A) -> Result<R, MessageError>
where T: Message, A: MessageArguments + EncodeArguments,
R: Any + Encode {
if obj.is_null() {
return Err(MessageError(format!("Messaging {:?} to nil", sel)));
}
verify_message_signature::<A, R>(superclass, sel).and_then(|_| {
send_super_unverified(obj, superclass, sel, args)
})
}
#[cfg(test)]
mod tests {
use test_utils;
use runtime::Object;
use super::Message;
#[test]
fn test_send_message() {
let obj = test_utils::custom_object();
let result: u32 = unsafe {
let _: () = msg_send![obj, setFoo:4u32];
msg_send![obj, foo]
};
assert!(result == 4);
}
#[test]
fn test_send_message_stret() {
let obj = test_utils::custom_object();
let result: test_utils::CustomStruct = unsafe {
msg_send![obj, customStruct]
};
let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
assert!(result == expected);
}
#[cfg(not(feature = "verify_message"))]
#[test]
fn test_send_message_nil() {
let nil: *mut Object = ::std::ptr::null_mut();
let result: usize = unsafe {
msg_send![nil, hash]
};
assert!(result == 0);
let result: *mut Object = unsafe {
msg_send![nil, description]
};
assert!(result.is_null());
let result: f64 = unsafe {
msg_send![nil, doubleValue]
};
assert!(result == 0.0);
}
#[test]
fn test_send_message_super() {
let obj = test_utils::custom_subclass_object();
let superclass = test_utils::custom_class();
unsafe {
let _: () = msg_send![obj, setFoo:4u32];
let foo: u32 = msg_send![super(obj, superclass), foo];
assert!(foo == 4);
// The subclass is overriden to return foo + 2
let foo: u32 = msg_send![obj, foo];
assert!(foo == 6);
}
}
#[test]
fn test_verify_message() {
let obj = test_utils::custom_object();
assert!(obj.verify_message::<(), u32>(sel!(foo)).is_ok());
assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo:)).is_ok());
// Incorrect types
assert!(obj.verify_message::<(), u64>(sel!(setFoo:)).is_err());
// Unimplemented selector
assert!(obj.verify_message::<(u32,), ()>(sel!(setFoo)).is_err());
}
}

49
vendor/objc/src/message/verify.rs vendored Normal file
View File

@@ -0,0 +1,49 @@
use runtime::{Class, Object, Sel};
use {Encode, EncodeArguments};
use super::MessageError;
pub fn verify_message_signature<A, R>(cls: &Class, sel: Sel)
-> Result<(), MessageError>
where A: EncodeArguments, R: Encode {
let method = match cls.instance_method(sel) {
Some(method) => method,
None => return Err(MessageError(
format!("Method {:?} not found on class {:?}",
sel, cls)
)),
};
let ret = R::encode();
let expected_ret = method.return_type();
if ret != expected_ret {
return Err(MessageError(
format!("Return type code {:?} does not match expected {:?} for method {:?}",
ret, expected_ret, method.name())
));
}
let self_and_cmd = [<*mut Object>::encode(), Sel::encode()];
let args = A::encodings();
let args = args.as_ref();
let count = self_and_cmd.len() + args.len();
let expected_count = method.arguments_count();
if count != expected_count {
return Err(MessageError(
format!("Method {:?} accepts {} arguments, but {} were given",
method.name(), expected_count, count)
));
}
for (i, arg) in self_and_cmd.iter().chain(args).enumerate() {
let expected = method.argument_type(i).unwrap();
if *arg != expected {
return Err(MessageError(
format!("Method {:?} expected argument at index {} with type code {:?} but was given {:?}",
method.name(), i, expected, arg)
));
}
}
Ok(())
}

30
vendor/objc/src/rc/autorelease.rs vendored Normal file
View File

@@ -0,0 +1,30 @@
use std::os::raw::c_void;
use runtime::{objc_autoreleasePoolPush, objc_autoreleasePoolPop};
// we use a struct to ensure that objc_autoreleasePoolPop during unwinding.
struct AutoReleaseHelper {
context: *mut c_void,
}
impl AutoReleaseHelper {
unsafe fn new() -> Self {
AutoReleaseHelper { context: objc_autoreleasePoolPush() }
}
}
impl Drop for AutoReleaseHelper {
fn drop(&mut self) {
unsafe { objc_autoreleasePoolPop(self.context) }
}
}
/**
Execute `f` in the context of a new autorelease pool. The pool is drained
after the execution of `f` completes.
This corresponds to `@autoreleasepool` blocks in Objective-C and Swift.
*/
pub fn autoreleasepool<T, F: FnOnce() -> T>(f: F) -> T {
let _context = unsafe { AutoReleaseHelper::new() };
f()
}

123
vendor/objc/src/rc/mod.rs vendored Normal file
View File

@@ -0,0 +1,123 @@
/*!
Utilities for reference counting Objective-C objects.
The utilities of the `rc` module provide ARC-like semantics for working with
Objective-C's reference counted objects in Rust.
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.
These utilities are not intended to provide a fully safe interface, but can be
useful when writing higher-level Rust wrappers for Objective-C code.
For more information on Objective-C's reference counting, see Apple's documentation:
<https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html>
# Example
``` no_run
# #[macro_use] extern crate objc;
# use objc::rc::{autoreleasepool, StrongPtr};
# fn main() {
// StrongPtr will release the object when dropped
let obj = unsafe {
StrongPtr::new(msg_send![class!(NSObject), new])
};
// Cloning retains the object an additional time
let cloned = obj.clone();
autoreleasepool(|| {
// Autorelease consumes the StrongPtr, but won't
// actually release until the end of an autoreleasepool
cloned.autorelease();
});
// Weak references won't retain the object
let weak = obj.weak();
drop(obj);
assert!(weak.load().is_null());
# }
```
*/
mod strong;
mod weak;
mod autorelease;
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 runtime::Object;
use super::StrongPtr;
use super::autoreleasepool;
#[test]
fn test_strong_clone() {
fn retain_count(obj: *mut Object) -> usize {
unsafe { msg_send![obj, retainCount] }
}
let obj = unsafe {
StrongPtr::new(msg_send![class!(NSObject), new])
};
assert!(retain_count(*obj) == 1);
let cloned = obj.clone();
assert!(retain_count(*cloned) == 2);
assert!(retain_count(*obj) == 2);
drop(obj);
assert!(retain_count(*cloned) == 1);
}
#[test]
fn test_weak() {
let obj = unsafe {
StrongPtr::new(msg_send![class!(NSObject), new])
};
let weak = obj.weak();
let strong = weak.load();
assert!(*strong == *obj);
drop(strong);
drop(obj);
assert!(weak.load().is_null());
}
#[test]
fn test_weak_copy() {
let obj = unsafe {
StrongPtr::new(msg_send![class!(NSObject), new])
};
let weak = obj.weak();
let weak2 = weak.clone();
let strong = weak2.load();
assert!(*strong == *obj);
}
#[test]
fn test_autorelease() {
let obj = unsafe {
StrongPtr::new(msg_send![class!(NSObject), new])
};
fn retain_count(obj: *mut Object) -> usize {
unsafe { msg_send![obj, retainCount] }
}
let cloned = obj.clone();
autoreleasepool(|| {
obj.autorelease();
assert!(retain_count(*cloned) == 2);
});
// make sure that the autoreleased value has been released
assert!(retain_count(*cloned) == 1);
}
}

73
vendor/objc/src/rc/strong.rs vendored Normal file
View File

@@ -0,0 +1,73 @@
use std::fmt;
use std::mem;
use std::ops::Deref;
use runtime::{Object, self};
use super::WeakPtr;
/// A pointer that strongly references an object, ensuring it won't be deallocated.
pub struct StrongPtr(*mut Object);
impl StrongPtr {
/// 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.
/// Unsafe because the caller must ensure the given object pointer is valid.
pub unsafe fn new(ptr: *mut Object) -> Self {
StrongPtr(ptr)
}
/// Retains the given object and constructs a `StrongPtr` to it.
/// When dropped, the object will be released.
/// Unsafe because the caller must ensure the given object pointer is valid.
pub unsafe fn retain(ptr: *mut Object) -> Self {
StrongPtr(runtime::objc_retain(ptr))
}
/// Autoreleases self, meaning that the object is not immediately released,
/// but will be when the autorelease pool is drained. A pointer to the
/// object is returned, but its validity is no longer ensured.
pub fn autorelease(self) -> *mut Object {
let ptr = self.0;
mem::forget(self);
unsafe {
runtime::objc_autorelease(ptr);
}
ptr
}
/// Returns a `WeakPtr` to self.
pub fn weak(&self) -> WeakPtr {
unsafe { WeakPtr::new(self.0) }
}
}
impl Drop for StrongPtr {
fn drop(&mut self) {
unsafe {
runtime::objc_release(self.0);
}
}
}
impl Clone for StrongPtr {
fn clone(&self) -> StrongPtr {
unsafe {
StrongPtr::retain(self.0)
}
}
}
impl Deref for StrongPtr {
type Target = *mut Object;
fn deref(&self) -> &*mut Object {
&self.0
}
}
impl fmt::Pointer for StrongPtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.0, f)
}
}

50
vendor/objc/src/rc/weak.rs vendored Normal file
View File

@@ -0,0 +1,50 @@
use std::cell::UnsafeCell;
use std::ptr;
use runtime::{Object, self};
use super::StrongPtr;
// 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,
// so we must use an UnsafeCell to get a *mut without self being mutable.
/// A pointer that weakly references an object, allowing to safely check
/// whether it has been deallocated.
pub struct WeakPtr(Box<UnsafeCell<*mut Object>>);
impl WeakPtr {
/// Constructs a `WeakPtr` to the given object.
/// Unsafe because the caller must ensure the given object pointer is valid.
pub unsafe fn new(obj: *mut Object) -> Self {
let ptr = Box::new(UnsafeCell::new(ptr::null_mut()));
runtime::objc_initWeak(ptr.get(), obj);
WeakPtr(ptr)
}
/// 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 {
let ptr = runtime::objc_loadWeakRetained(self.0.get());
StrongPtr::new(ptr)
}
}
}
impl Drop for WeakPtr {
fn drop(&mut self) {
unsafe {
runtime::objc_destroyWeak(self.0.get());
}
}
}
impl Clone for WeakPtr {
fn clone(&self) -> Self {
let ptr = Box::new(UnsafeCell::new(ptr::null_mut()));
unsafe {
runtime::objc_copyWeak(ptr.get(), self.0.get());
}
WeakPtr(ptr)
}
}

632
vendor/objc/src/runtime.rs vendored Normal file
View File

@@ -0,0 +1,632 @@
//! A Rust interface for the functionality of the Objective-C runtime.
//!
//! For more information on foreign functions, see Apple's documentation:
//! <https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html>
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::MallocBuffer;
use encode;
use {Encode, Encoding};
/// The Objective-C `BOOL` type.
///
/// 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.
#[cfg(not(target_arch = "aarch64"))]
pub const YES: BOOL = 1;
/// The equivalent of false for Objective-C's `BOOL` type.
#[cfg(not(target_arch = "aarch64"))]
pub const NO: BOOL = 0;
#[cfg(target_arch = "aarch64")]
pub type BOOL = bool;
#[cfg(target_arch = "aarch64")]
pub const YES: BOOL = true;
#[cfg(target_arch = "aarch64")]
pub const NO: BOOL = false;
/// A type that represents a method selector.
#[repr(C)]
pub struct Sel {
ptr: *const c_void,
}
/// A marker type to be embedded into other types just so that they cannot be
/// constructed externally.
type PrivateMarker = [u8; 0];
/// A type that represents an instance variable.
#[repr(C)]
pub struct Ivar {
_priv: PrivateMarker,
}
/// A type that represents a method in a class definition.
#[repr(C)]
pub struct Method {
_priv: PrivateMarker,
}
/// A type that represents an Objective-C class.
#[repr(C)]
pub struct Class {
_priv: PrivateMarker,
}
/// A type that represents an Objective-C protocol.
#[repr(C)]
pub struct Protocol {
_priv: PrivateMarker
}
/// A type that represents an instance of a class.
#[repr(C)]
pub struct Object {
_priv: PrivateMarker,
}
/// A pointer to the start of a method implementation.
pub type Imp = unsafe extern fn();
#[link(name = "objc", kind = "dylib")]
extern {
pub fn sel_registerName(name: *const c_char) -> Sel;
pub fn sel_getName(sel: Sel) -> *const c_char;
pub fn class_getName(cls: *const Class) -> *const c_char;
pub fn class_getSuperclass(cls: *const Class) -> *const Class;
pub fn class_getInstanceSize(cls: *const Class) -> usize;
pub fn class_getInstanceMethod(cls: *const Class, sel: Sel) -> *const Method;
pub fn class_getInstanceVariable(cls: *const Class, name: *const c_char) -> *const Ivar;
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_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 objc_disposeClassPair(cls: *mut Class);
pub fn objc_registerClassPair(cls: *mut Class);
pub fn class_createInstance(cls: *const Class, extraBytes: usize) -> *mut Object;
pub fn object_dispose(obj: *mut Object) -> *mut Object;
pub fn object_getClass(obj: *const Object) -> *const Class;
pub fn objc_getClassList(buffer: *mut *const Class, bufferLen: c_int) -> c_int;
pub fn objc_copyClassList(outCount: *mut c_uint) -> *mut *const Class;
pub fn objc_getClass(name: *const c_char) -> *const Class;
pub fn objc_getProtocol(name: *const c_char) -> *const Protocol;
pub fn objc_copyProtocolList(outCount: *mut c_uint) -> *mut *const Protocol;
pub fn objc_allocateProtocol(name: *const c_char) -> *mut Protocol;
pub fn objc_registerProtocol(proto: *mut Protocol);
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_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_conformsToProtocol(proto: *const Protocol, other: *const Protocol) -> BOOL;
pub fn ivar_getName(ivar: *const Ivar) -> *const c_char;
pub fn ivar_getOffset(ivar: *const Ivar) -> isize;
pub fn ivar_getTypeEncoding(ivar: *const Ivar) -> *const c_char;
pub fn method_getName(method: *const Method) -> Sel;
pub fn method_getImplementation(method: *const Method) -> Imp;
pub fn method_copyReturnType(method: *const Method) -> *mut c_char;
pub fn method_copyArgumentType(method: *const Method, index: c_uint) -> *mut c_char;
pub fn method_getNumberOfArguments(method: *const Method) -> c_uint;
pub fn method_setImplementation(method: *mut Method, imp: Imp) -> Imp;
pub fn method_exchangeImplementations(m1: *mut Method, m2: *mut Method);
pub fn objc_retain(obj: *mut Object) -> *mut Object;
pub fn objc_release(obj: *mut Object);
pub fn objc_autorelease(obj: *mut Object);
pub fn objc_loadWeakRetained(location: *mut *mut Object) -> *mut Object;
pub fn objc_initWeak(location: *mut *mut Object, obj: *mut Object) -> *mut Object;
pub fn objc_destroyWeak(location: *mut *mut Object);
pub fn objc_copyWeak(to: *mut *mut Object, from: *mut *mut Object);
}
impl Sel {
/// Registers a method with the Objective-C runtime system,
/// 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())
}
}
/// Returns the name of the method specified by self.
pub fn name(&self) -> &str {
let name = unsafe {
CStr::from_ptr(sel_getName(*self))
};
str::from_utf8(name.to_bytes()).unwrap()
}
/// Wraps a raw pointer to a selector into a `Sel` object.
///
/// 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,
}
}
/// Returns a pointer to the raw selector.
#[inline]
pub fn as_ptr(&self) -> *const c_void {
self.ptr
}
}
impl PartialEq for Sel {
fn eq(&self, other: &Sel) -> bool {
self.ptr == other.ptr
}
}
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 { }
impl Copy for Sel { }
impl Clone for Sel {
fn clone(&self) -> Sel { *self }
}
impl fmt::Debug for Sel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl Ivar {
/// Returns the name of self.
pub fn name(&self) -> &str {
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)
};
offset as isize
}
/// Returns the `Encoding` of self.
pub fn type_encoding(&self) -> Encoding {
let encoding = unsafe {
CStr::from_ptr(ivar_getTypeEncoding(self))
};
let s = str::from_utf8(encoding.to_bytes()).unwrap();
encode::from_str(s)
}
}
impl Method {
/// Returns the name of self.
pub fn name(&self) -> Sel {
unsafe {
method_getName(self)
}
}
/// Returns the `Encoding` of self's return type.
pub fn return_type(&self) -> Encoding {
unsafe {
let encoding = method_copyReturnType(self);
encode::from_malloc_str(encoding)
}
}
/// Returns the `Encoding` of a single parameter type of self, or
/// `None` if self has no parameter at the given index.
pub fn argument_type(&self, index: usize) -> Option<Encoding> {
unsafe {
let encoding = method_copyArgumentType(self, index as c_uint);
if encoding.is_null() {
None
} else {
Some(encode::from_malloc_str(encoding))
}
}
}
/// Returns the number of arguments accepted by self.
pub fn arguments_count(&self) -> usize {
unsafe {
method_getNumberOfArguments(self) as usize
}
}
/// Returns the implementation of self.
pub fn implementation(&self) -> Imp {
unsafe {
method_getImplementation(self)
}
}
}
impl Class {
/// 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();
unsafe {
let cls = objc_getClass(name.as_ptr());
if cls.is_null() { None } else { Some(&*cls) }
}
}
/// Obtains the list of registered class definitions.
pub fn classes() -> MallocBuffer<&'static Class> {
unsafe {
let mut count: c_uint = 0;
let classes = objc_copyClassList(&mut count);
MallocBuffer::new(classes as *mut _, count as usize).unwrap()
}
}
/// Returns the total number of registered classes.
pub fn classes_count() -> 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))
};
str::from_utf8(name.to_bytes()).unwrap()
}
/// 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);
if superclass.is_null() { None } else { Some(&*superclass) }
}
}
/// Returns the metaclass of self.
pub fn metaclass(&self) -> &Class {
unsafe {
let self_ptr: *const Class = self;
&*object_getClass(self_ptr as *const Object)
}
}
/// Returns the size of instances of self.
pub fn instance_size(&self) -> usize {
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.
pub fn instance_method(&self, sel: Sel) -> Option<&Method> {
unsafe {
let method = class_getInstanceMethod(self, sel);
if method.is_null() { None } else { Some(&*method) }
}
}
/// 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 {
let ivar = class_getInstanceVariable(self, name.as_ptr());
if ivar.is_null() { None } else { Some(&*ivar) }
}
}
/// Describes the instance methods implemented by self.
pub fn instance_methods(&self) -> MallocBuffer<&Method> {
unsafe {
let mut count: c_uint = 0;
let methods = class_copyMethodList(self, &mut count);
MallocBuffer::new(methods as *mut _, count as usize).unwrap()
}
}
/// Checks whether this class conforms to the specified protocol.
pub fn conforms_to(&self, proto: &Protocol) -> bool {
unsafe { class_conformsToProtocol(self, proto) == YES }
}
/// Get a list of the protocols to which this class conforms.
pub fn adopted_protocols(&self) -> MallocBuffer<&Protocol> {
unsafe {
let mut count: c_uint = 0;
let protos = class_copyProtocolList(self, &mut count);
MallocBuffer::new(protos as *mut _, count as usize).unwrap()
}
}
/// Describes the instance variables declared by self.
pub fn instance_variables(&self) -> MallocBuffer<&Ivar> {
unsafe {
let mut count: c_uint = 0;
let ivars = class_copyIvarList(self, &mut count);
MallocBuffer::new(ivars as *mut _, count as usize).unwrap()
}
}
}
impl PartialEq for Class {
fn eq(&self, other: &Class) -> bool {
let self_ptr: *const Class = self;
let other_ptr: *const Class = other;
self_ptr == other_ptr
}
}
impl Eq for Class { }
impl fmt::Debug for Class {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl Protocol {
/// 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 {
let proto = objc_getProtocol(name.as_ptr());
if proto.is_null() { None } else { Some(&*proto) }
}
}
/// Obtains the list of registered protocol definitions.
pub fn protocols() -> MallocBuffer<&'static Protocol> {
unsafe {
let mut count: c_uint = 0;
let protocols = objc_copyProtocolList(&mut count);
MallocBuffer::new(protocols as *mut _, count as usize).unwrap()
}
}
/// Get a list of the protocols to which this protocol conforms.
pub fn adopted_protocols(&self) -> MallocBuffer<&Protocol> {
unsafe {
let mut count: c_uint = 0;
let protocols = protocol_copyProtocolList(self, &mut count);
MallocBuffer::new(protocols as *mut _, count as usize).unwrap()
}
}
/// Checks whether this protocol conforms to the specified protocol.
pub fn conforms_to(&self, proto: &Protocol) -> bool {
unsafe { protocol_conformsToProtocol(self, proto) == YES }
}
/// Returns the name of self.
pub fn name(&self) -> &str {
let name = unsafe {
CStr::from_ptr(protocol_getName(self))
};
str::from_utf8(name.to_bytes()).unwrap()
}
}
impl PartialEq for Protocol {
fn eq(&self, other: &Protocol) -> bool {
unsafe { protocol_isEqual(self, other) == YES }
}
}
impl Eq for Protocol { }
impl fmt::Debug for Protocol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl Object {
/// Returns the class of self.
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.
/// Unsafe because the caller must ensure that the ivar is actually
/// of type `T`.
pub unsafe fn get_ivar<T>(&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::encode());
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
};
&*ptr
}
/// Returns a mutable 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_mut_ivar<T>(&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::encode());
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
};
&mut *ptr
}
/// Sets the value of 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 set_ivar<T>(&mut self, name: &str, value: T)
where T: Encode {
*self.get_mut_ivar::<T>(name) = value;
}
}
impl fmt::Debug for Object {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<{:?}: {:p}>", self.class(), self)
}
}
#[cfg(test)]
mod tests {
use test_utils;
use Encode;
use super::{Class, Protocol, Sel};
#[test]
fn test_ivar() {
let cls = test_utils::custom_class();
let ivar = cls.instance_variable("_foo").unwrap();
assert!(ivar.name() == "_foo");
assert!(ivar.type_encoding() == <u32>::encode());
assert!(ivar.offset() > 0);
let ivars = cls.instance_variables();
assert!(ivars.len() > 0);
}
#[test]
fn test_method() {
let cls = test_utils::custom_class();
let sel = Sel::register("foo");
let method = cls.instance_method(sel).unwrap();
assert!(method.name().name() == "foo");
assert!(method.arguments_count() == 2);
assert!(method.return_type() == <u32>::encode());
assert!(method.argument_type(1).unwrap() == Sel::encode());
let methods = cls.instance_methods();
assert!(methods.len() > 0);
}
#[test]
fn test_class() {
let cls = test_utils::custom_class();
assert!(cls.name() == "CustomObject");
assert!(cls.instance_size() > 0);
assert!(cls.superclass().is_none());
assert!(Class::get(cls.name()) == Some(cls));
let metaclass = cls.metaclass();
// The metaclass of a root class is a subclass of the root class
assert!(metaclass.superclass().unwrap() == cls);
let subclass = test_utils::custom_subclass();
assert!(subclass.superclass().unwrap() == cls);
}
#[test]
fn test_classes() {
assert!(Class::classes_count() > 0);
let classes = Class::classes();
assert!(classes.len() > 0);
}
#[test]
fn test_protocol() {
let proto = test_utils::custom_protocol();
assert!(proto.name() == "CustomProtocol");
let class = test_utils::custom_class();
assert!(class.conforms_to(proto));
let class_protocols = class.adopted_protocols();
assert!(class_protocols.len() > 0);
}
#[test]
fn test_protocol_method() {
let class = test_utils::custom_class();
let result: i32 = unsafe {
msg_send![class, addNumber:1 toNumber:2]
};
assert_eq!(result, 3);
}
#[test]
fn test_subprotocols() {
let sub_proto = test_utils::custom_subprotocol();
let super_proto = test_utils::custom_protocol();
assert!(sub_proto.conforms_to(super_proto));
let adopted_protocols = sub_proto.adopted_protocols();
assert_eq!(adopted_protocols[0], super_proto);
}
#[test]
fn test_protocols() {
// Ensure that a protocol has been registered on linux
let _ = test_utils::custom_protocol();
let protocols = Protocol::protocols();
assert!(protocols.len() > 0);
}
#[test]
fn test_object() {
let mut obj = test_utils::custom_object();
assert!(obj.class() == test_utils::custom_class());
let result: u32 = unsafe {
obj.set_ivar("_foo", 4u32);
*obj.get_ivar("_foo")
};
assert!(result == 4);
}
}

187
vendor/objc/src/test_utils.rs vendored Normal file
View File

@@ -0,0 +1,187 @@
use std::ops::{Deref, DerefMut};
use std::os::raw::c_char;
use std::sync::{Once, ONCE_INIT};
use declare::{ClassDecl, ProtocolDecl};
use runtime::{Class, Object, Protocol, Sel, self};
use {Encode, Encoding};
pub struct CustomObject {
obj: *mut Object,
}
impl CustomObject {
fn new(class: &Class) -> Self {
let obj = unsafe {
runtime::class_createInstance(class, 0)
};
CustomObject { obj: obj }
}
}
impl Deref for CustomObject {
type Target = Object;
fn deref(&self) -> &Object {
unsafe { &*self.obj }
}
}
impl DerefMut for CustomObject {
fn deref_mut(&mut self) -> &mut Object {
unsafe { &mut *self.obj }
}
}
impl Drop for CustomObject {
fn drop(&mut self) {
unsafe {
runtime::object_dispose(self.obj);
}
}
}
#[derive(Eq, PartialEq)]
pub struct CustomStruct {
pub a: u64,
pub b: u64,
pub c: u64,
pub d: u64,
}
unsafe impl Encode for CustomStruct {
fn encode() -> Encoding {
let mut code = "{CustomStruct=".to_owned();
for _ in 0..4 {
code.push_str(u64::encode().as_str());
}
code.push_str("}");
unsafe {
Encoding::from_str(&code)
}
}
}
pub fn custom_class() -> &'static Class {
static REGISTER_CUSTOM_CLASS: Once = ONCE_INIT;
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) { }
let mut decl = ClassDecl::root("CustomObject", custom_obj_class_initialize).unwrap();
let proto = custom_protocol();
decl.add_protocol(proto);
decl.add_ivar::<u32>("_foo");
extern fn custom_obj_set_foo(this: &mut Object, _cmd: Sel, foo: u32) {
unsafe { this.set_ivar::<u32>("_foo", foo); }
}
extern fn custom_obj_get_foo(this: &Object, _cmd: Sel) -> u32 {
unsafe { *this.get_ivar::<u32>("_foo") }
}
extern 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 {
7
}
extern fn custom_obj_set_bar(this: &mut Object, _cmd: Sel, bar: u32) {
unsafe { this.set_ivar::<u32>("_foo", bar) ;}
}
extern 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;
decl.add_method(sel!(setFoo:), set_foo);
let get_foo: extern 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;
decl.add_method(sel!(customStruct), get_struct);
let class_method: extern 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;
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;
decl.add_class_method(sel!(addNumber:toNumber:), protocol_class_method);
}
decl.register();
});
class!(CustomObject)
}
pub fn custom_protocol() -> &'static Protocol {
static REGISTER_CUSTOM_PROTOCOL: Once = ONCE_INIT;
REGISTER_CUSTOM_PROTOCOL.call_once(|| {
let mut decl = ProtocolDecl::new("CustomProtocol").unwrap();
decl.add_method_description::<(i32,), ()>(sel!(setBar:), true);
decl.add_method_description::<(), *const c_char>(sel!(getName), false);
decl.add_class_method_description::<(i32, i32), i32>(sel!(addNumber:toNumber:), true);
decl.register();
});
Protocol::get("CustomProtocol").unwrap()
}
pub fn custom_subprotocol() -> &'static Protocol {
static REGISTER_CUSTOM_SUBPROTOCOL: Once = ONCE_INIT;
REGISTER_CUSTOM_SUBPROTOCOL.call_once(|| {
let super_proto = custom_protocol();
let mut decl = ProtocolDecl::new("CustomSubProtocol").unwrap();
decl.add_protocol(super_proto);
decl.add_method_description::<(u32,), u32>(sel!(calculateFoo:), true);
decl.register();
});
Protocol::get("CustomSubProtocol").unwrap()
}
pub fn custom_object() -> CustomObject {
CustomObject::new(custom_class())
}
pub fn custom_subclass() -> &'static Class {
static REGISTER_CUSTOM_SUBCLASS: Once = ONCE_INIT;
REGISTER_CUSTOM_SUBCLASS.call_once(|| {
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]
};
foo + 2
}
unsafe {
let get_foo: extern fn(&Object, Sel) -> u32 = custom_subclass_get_foo;
decl.add_method(sel!(foo), get_foo);
}
decl.register();
});
class!(CustomSubclassObject)
}
pub fn custom_subclass_object() -> CustomObject {
CustomObject::new(custom_subclass())
}