Description
Hey @waywardmonkeys, @jrmuizel, @mrobinson and @wusyong (and CC @tmandry and @simlay).
Over the past few years, I've been working on replacements for the crates in this repo in the objc2
project, see #513 and #628 for some previous discussion. To rehash the benefits of the objc2-*
crates:
- Code generation from headers, which means that basically every upstream API is available (only a few explicitly skipped APIs aren't), and this will remain true even as Apple releases new SDK versions over time (since we only need to rerun the generator).
- Automatic memory management, all objects are wrapped by the code generator in either
objc2::rc::Retained
orobjc2_core_foundation::CFRetained
, which will release the object onDrop
. The generator knows about the "create rule" and about opt-outs likeCF_RETURNS_NOT_RETAINED
etc. (so it will do this correctly with a much higher probability than if a human did it). - Type-safety, especially compared to
cocoa
andcocoa-foundation
where everything is just an extension trait on theid
pointer.
I'm motivated in bringing these benefits to the entirety of the Apple+Rust ecosystem, as I think the soundness, correctness and ergonomics improvements here are quite significant. To that end, I've been slowly migrating major Rust projects, see madsmtm/objc2#174.
A recent milestone is that I've released objc2-core-foundation v0.3.1
, which I believe now covers everything that core-foundation
does! I've also assessed every open issue and pull-request in this repo, and made sure that they're either resolved or tracked in the objc2
repo, see madsmtm/objc2#719. So at this point, I'd like to start discussing the future of this project, and how we can migrate Servo and other users to the objc2-*
crates (assuming you agree that's a goal, if not then I'd also like to discuss that!)
My ideal scenario would be that the crates in this repo were marked #![deprecated]
with re-exports of the objc2-*
variants, both to give users an easier migration path, and because in a way it'd "bless" the objc2
crates, but I can see other solutions, including any of the following variations:
- Only do this for
cocoa
andcocoa-foundation
(these are whereobjc2-*
would be the most valuable). - Soft-deprecate the crates in the README only, but without actually marking it
#![deprecated]
. - Publish an advisory to the RUSTSEC advisory database (my own preference would be not to, at least not yet).
A few drawbacks to consider:
- It is a fair amount of churn. I don't believe it to be unnecessary churn though, there really are a lot of bugs out there in Apple+Rust-related code, and a lot of them could be alleviated with the
objc2-*
crates. objc2-*
crates are a bit less stable thancore-foundation-rs
crates. I do tend to be conservative of breaking changes, and to plan ahead to allow spacing them out as much as possible.- It is my understanding that Firefox/Mozilla vets/audits every dependency, and that the
objc2-*
crates haven't been audited, so this might hurt them until that happens? CC @ErichDonGubler and @jimblandy maybe? - This could be seen as a supply-chain attack. Don't know how to alleviate that, other than having people review my code ;)
- Bus factor,
objc2
has fewer maintainers. I'd love to get others on board though, just say so if you want to! Or join the Matrix workspace to start with.
Crate status / comparison
Note that I'm not entirely done transitioning things here, see the below table for the current status (which is probably slightly incorrect, there's bound to be something I've missed):
Servo crate | objc2 crate |
Comparison |
---|---|---|
cocoa |
objc2-app-kit |
Fully superseded ✅ |
cocoa-foundation |
objc2-foundation |
Fully superseded ✅ |
core-foundation-sys |
objc2-core-foundation |
Fully superseded ✅ |
core-foundation |
objc2-core-foundation |
Fully superseded ✅ |
core-graphics-types |
objc2-core-foundation |
Fully superseded ✅ |
core-graphics |
objc2-core-graphics |
Missing CGDirectDisplayID wrapper and most functions are still unsafe |
core-text |
objc2-core-text |
Still a fair bit of work to do to make it as nice ❗️ |
io-surface |
objc2-io-surface |
Fully superseded ✅ |
But I do intend to resolve this, so I still feel it's valuable to start discussing migration now.
How objc2-core-foundation
differs from core-foundation
Just to get everyone up to speed, here's a quick overview of the differences.
The memory management strategy is as follows:
core-foundation |
objc2-core-foundation |
---|---|
CFString |
CFRetained<CFString> |
&CFString |
&CFRetained<CFString> |
CFStringRef |
*mut CFString |
__CFString |
CFString |
Not really possible | &CFString |
That is, objc2-core-foundation
only has a single type that represents CFString
, and memory management (CFRetain
/CFRelease
) is instead handled by a single generic wrapper type. This also meant that while I did initially consider building upon core-foundation
instead of creating a new crate, it wasn't really an option in the end, as the internals are just too different.
objc2-core-foundation
also avoids the *-sys
split, instead preferring to expose everything in the same crate (again, to avoid a proliferation of types). A few of my guiding principles API-wise:
- Expose all internals such that users never need to write
extern "C" { ... }
themselves. - Make everything as nice to use as possible when coming from Rust. Functions are exposed as associated functions/methods, conversions to/from common Rust types are provided.
- Be performance-minded when creating wrappers. For example, I wouldn't add a
CFURL -> String
conversion, since that requires at least two CoreFoundation functions to be called. Instead,CFURL -> CFString
is provided, and so isCFString -> String
.