Very impressive! This post demonstrates a great deal of understanding of the semantics of both languages, and the resultant interface looks both usable and thorough. I especially enjoyed the use of a Rust macro to emulate the syntax of Objective-C message passing, as well as the demonstration of the utility of "phantom" type parameters.
Just to bring up something I've been thinking about, Rust would have a lower impedance mismatch with Swift interfaces - memory safe APIs, with a more C-like method syntax, more strongly typed in general (optionals, generics...), more functional (although AFAIK there aren't currently many Swift-specific APIs, as opposed to Objective-C ports), and so on. Its binary module system also matches Rust somewhat better than Objective-C's basically #include based system. Unfortunately, Swift's runtime, aside from being more complicated than Objective-C's, is completely undocumented (and closed-source), so it would take a good bit of reverse engineering to create a bridge.
You can do this sort of thing with Objective C precisely because the layer between ObjC and C is so clean and concise. It's a strict superset of the C language; the C at its core is pure and entirely unmolested.
What makes interoperability possible is Rust's existing C interop.
Very cool – and oddly relevant to me since as well as taking an interest in Rust recently, I'm also writing an Objective-C bridge for Julia (which I'll write about soon).
Like the languages themselves the bridges are polar opposites, of course – static and safe vs. flexible and interactive, etc. It's great to see it (and learn from it) being done on the other side of those tradeoffs.
Strictly speaking, [string UTF8String] is equivalent to '((const char <star>(<star>)(id, SEL))objc_msgSend)(string, selector)'. Since objc_msgSend is vararg function, it will promote it's arguments, so for example method taking float will be called with double. Casting to a proper function type works around that.
Oh good point, I hadn't considered vararg promotion!
Do you know if casting to a function also make objc_msgSend_stret and objc_msgSend_fpret unnecessary? I haven't yet worked with any methods that return structs or floating point values, so I haven't had to deal with them yet.
As you discovered, _stret/_fpret remain necessary.
objc_msgSend()'s type is not expressible in C; the only time it is correct to call objc_msgSend without a cast is when calling a method IMP with the literal vararg type of id (*method) (id self, SEL sel, ...);
That's CoreFoundation, not Foundation. CoreFoundation is plain C and relatively small in feature set. Foundation is Objective-C and much larger.
It's a lot easier to work with the Foundation Objective-C API. They both manipulate the same data structures (or nearly the same with zero-cost bridging) but Foundation is far less verbose and a little more dynamic (no need for manual buffer allocations and configuring callback structures).
Great writeup. More interested though on how one can use Rust to write iOS, OS X and Android framework/library. This will make Rust replacing C++ for cross platform codes.