Objective-C in Rust
objc
family instead!
DISCLAIMER! These crates are work in progress, and should not be used in production environments. Use the battle-tested Anyway, thanks for being here, any help testing things out is highly appreciated!
The two crates you're interested in is probably icrate
, which provide a
mostly autogenerated interface for Apple's Objective-C frameworks (AppKit
,
Foundation
, Metal
, WebKit
, you name it), and objc2
, which contains
the "lower level" details for interop between Rust and Objective-C (and e.g.
support for declaring classes, which is needed to implement delegates, a
common operation in the aforementioned frameworks).
Goals
There are many conflicting priorities in an open-source project like this (performance, ergonomics, understandability, portability, ...), but the following two can be seen as the guiding principles for everything else in this project.
1. Complete Soundness
The non-negotiable goal of these crates is to be completely "sound", meaning it must not be possible for safe Rust to cause undefined behaviour!
As of January 2023, I (@madsmtm
) have yet to find a single Rust crate or
project calling Objective-C soundly. Issues I have found include:
- Wrong method calling ABI.
- Wrong memory management (in the best cases they just leak a lot).
- Incorrect usage of
&mut
. - Incorrect main-thread safety.
I don't state this to throw shade at these projects, it is very much understandable! Objective-C and Rust have vastly different semantics, so tackling these issues require vigilance and a focus that e.g. a system clipboard crate just doesn't have! Rather, I state it to provide reassurance: Rust's fearless concurrency can be won back! This project's approach to the issue works, and leaks, segfaults, race conditions and so on can be completely eliminated!
Needless to say, nothing is perfect, so if you think you've found a soundness
hole, please don't hesitate to report it on the issue tracker. Known
soundness holes (however theoretical) are tracked in the I-unsound
label.
2. Idiomatic Rust
Soundness would be easy to achieve if we just marked every API as unsafe
,
and called it a day (the precursor to this, objc
, is basically sound).
However, that just pushes the burden onto you, the user, and then we're not
much better off!
As such, we'll try to be as safe and idiomatic as possible; using references
instead of pointers to represent objects and their mutability, Option
instead of null
, doing memory management automatically instead of manually,
and so on (see again these notes on "Layered Safety"). These
abstractions should ideally be zero-cost, but this is of course a balancing
act against being ergonomic.
Some APIs in objc2
and block2
will still have to remain unsafe
, so these
contain thorough # Safety
sections, to let you know exactly which safety
guarantees you need to uphold.
icrate
is a bit difficult in this regard, since it is mostly autogenerated,
which means that almost nothing can be safe by default! However, we can still
try to mitigate this problem by marking manually audited functionality as
safe (which we need your help with).
Minimum Supported Rust Version (MSRV)
The currently minimum supported Rust version is 1.60
; this is not
defined by policy, though, so it may change in at any time in a patch release.
Help us define a policy over in #203.
objc
and family
Migrating from If size of your project is fairly small, it'll probably be easiest to just
jump straight into replacing everything with icrate
(when you do, don't
forget to mark unsafe
methods that you use as safe along the
way).
If your project is large, you can consider upgrading in small steps, following the changelog at each step of the way. For the most common cases, the changelogs will include a helpful example on how to upgrade.
As an example you'd start by using objc2
instead of objc
in your
Cargo.toml
:
[dependencies]
objc = { package = "objc2", version = "0.2.7" }
Afterwards, you can upgrade to the next release, in this case
v0.3.0-alpha.0
, and make the required changes to your code following the
changelog. And so on, with every following release.
License
This project is licensed under the MIT license, see LICENSE.txt
.
Work is in progress to make it dual-licensed under the Apache License (Version 2.0) as well, see this.
Acknowledgements / Prior art
This repository is a merge of the following projects, see reasoning for the fork here:
objc
- Renamed to
objc2
.
- Renamed to
objc-encode
- Renamed to
objc2-encode
.
- Renamed to
objc_exception
- Moved to
objc2::exception
.
- Moved to
objc_id
- Moved to
objc2::rc
.
- Moved to
objc-foundation
- Moved to
icrate::Foundation
.
- Moved to
block
- Renamed to
block2
.
- Renamed to
These were created almost solely by @SSheldon, so a huge thanks for their fantastic work on these crates!
This project also draws inspiration from:
apple-sys
cacao
- the
core-foundation-rs
project fruity
metal
objrs
objr
and familyrust-macios
uikit-sys
and@simlay
's Objective-C work onbindgen
Finally, this is by far not the only project that ever tried to interoperate with Objective-C; other languages have done so as well (to varying degrees of success):
- Swift: Built from the beginning for Objective-C interop, and is what
objc2
aspires to have feature-parity with (though will probably never reach). Truly beautifully designed language! - C#: Xamarin, Xamarin.Mac, a good source of inspiration for what "should" work.
- Python: PyObjC (previously?) official Apple project which works with "BridgeSupport",
objp
- Ruby: MacRuby, RubyCocoa
- Dart:
ffigen
- Nim: somewhat built-in support,
darwin
,objc
- D: somewhat built-in support,
derelict
- Java: Java-Objective-C-Bridge, Apple also has a very old official project
- Node.js: NodObjC,
objc
- Zig: zig-objcrt
- V: Not really existing, they just write and compile Objective-C code, and use manual C-bindings
- Go: MacDriver