Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/objc/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/objc/.cargo-checksum.json
vendored
Normal 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
third-party/vendor/objc/CHANGELOG.md
vendored
Normal file
117
third-party/vendor/objc/CHANGELOG.md
vendored
Normal 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
third-party/vendor/objc/Cargo.lock
generated
vendored
Normal file
41
third-party/vendor/objc/Cargo.lock
generated
vendored
Normal 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
third-party/vendor/objc/Cargo.toml
vendored
Normal file
33
third-party/vendor/objc/Cargo.toml
vendored
Normal 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
third-party/vendor/objc/LICENSE.txt
vendored
Normal file
21
third-party/vendor/objc/LICENSE.txt
vendored
Normal 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
third-party/vendor/objc/README.md
vendored
Normal file
99
third-party/vendor/objc/README.md
vendored
Normal 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
third-party/vendor/objc/examples/example.rs
vendored
Normal file
45
third-party/vendor/objc/examples/example.rs
vendored
Normal 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
third-party/vendor/objc/src/declare.rs
vendored
Normal file
340
third-party/vendor/objc/src/declare.rs
vendored
Normal 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
third-party/vendor/objc/src/encode.rs
vendored
Normal file
279
third-party/vendor/objc/src/encode.rs
vendored
Normal 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
third-party/vendor/objc/src/exception.rs
vendored
Normal file
11
third-party/vendor/objc/src/exception.rs
vendored
Normal 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
third-party/vendor/objc/src/lib.rs
vendored
Normal file
90
third-party/vendor/objc/src/lib.rs
vendored
Normal 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
third-party/vendor/objc/src/macros.rs
vendored
Normal file
148
third-party/vendor/objc/src/macros.rs
vendored
Normal 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
third-party/vendor/objc/src/message/apple/arm.rs
vendored
Normal file
40
third-party/vendor/objc/src/message/apple/arm.rs
vendored
Normal 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
third-party/vendor/objc/src/message/apple/arm64.rs
vendored
Normal file
18
third-party/vendor/objc/src/message/apple/arm64.rs
vendored
Normal 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
third-party/vendor/objc/src/message/apple/mod.rs
vendored
Normal file
40
third-party/vendor/objc/src/message/apple/mod.rs
vendored
Normal 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
third-party/vendor/objc/src/message/apple/x86.rs
vendored
Normal file
40
third-party/vendor/objc/src/message/apple/x86.rs
vendored
Normal 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
third-party/vendor/objc/src/message/apple/x86_64.rs
vendored
Normal file
32
third-party/vendor/objc/src/message/apple/x86_64.rs
vendored
Normal 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
third-party/vendor/objc/src/message/gnustep.rs
vendored
Normal file
35
third-party/vendor/objc/src/message/gnustep.rs
vendored
Normal 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
third-party/vendor/objc/src/message/mod.rs
vendored
Normal file
296
third-party/vendor/objc/src/message/mod.rs
vendored
Normal 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
third-party/vendor/objc/src/message/verify.rs
vendored
Normal file
49
third-party/vendor/objc/src/message/verify.rs
vendored
Normal 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
third-party/vendor/objc/src/rc/autorelease.rs
vendored
Normal file
30
third-party/vendor/objc/src/rc/autorelease.rs
vendored
Normal 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
third-party/vendor/objc/src/rc/mod.rs
vendored
Normal file
123
third-party/vendor/objc/src/rc/mod.rs
vendored
Normal 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
third-party/vendor/objc/src/rc/strong.rs
vendored
Normal file
73
third-party/vendor/objc/src/rc/strong.rs
vendored
Normal 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
third-party/vendor/objc/src/rc/weak.rs
vendored
Normal file
50
third-party/vendor/objc/src/rc/weak.rs
vendored
Normal 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
third-party/vendor/objc/src/runtime.rs
vendored
Normal file
632
third-party/vendor/objc/src/runtime.rs
vendored
Normal 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
third-party/vendor/objc/src/test_utils.rs
vendored
Normal file
187
third-party/vendor/objc/src/test_utils.rs
vendored
Normal 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())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue