-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bindgen
support
#85
Comments
Maybe bindgen is really only useful for |
Ideally the design of the bindings should make it easily possible to conform to our preferred design (that we haven't chosen yet, see #58). Idea: In the end we have something like this: pub struct NSBundle(ffi::NSBundle);
unsafe impl objc::Message for NSBundle {}
impl std::ops::Deref for NSBundle {
type Target = NSObject;
fn deref(&self) -> &Self::Target {
NSObject::from_raw(*self.0) // Uses ffi::NSBundle's Deref impl
}
}
impl NSBundle {
pub fn new_with_path(path: &Path) -> Id<Self, Owned> {
let nsstring = NSString::from(path);
// NSString into ffi::NSString
let obj = unsafe { ffi::NSBundle::alloc().initWithPath_(nsstring.into()) } as *mut NSBundle;
Id::new(NonNull::new(obj).unwrap())
}
// new_with_url
pub fn main() -> Option<&'static Self> { // Or Id or autorelease stuff
let obj = unsafe { ffi::NSBundle::mainBundle() } as *mut NSBundle;
unsafe { NonNull::new(obj).as_ref() }
}
pub fn path(&self) -> &NSString {
unsafe { NSString::from_raw(self.0.bundlePath()) }
}
} Which uses the automatically generated bindings. The difference is as follows: #[repr(transparent)]
-pub struct NSBundle(NSObject);
+pub struct NSBundle(ffi::NSBundle);
unsafe impl objc::Message for NSBundle {}
impl std::ops::Deref for NSBundle {
type Target = NSObject;
fn deref(&self) -> &Self::Target {
- self.0
+ NSObject::from_raw(*self.0) // Uses ffi::NSBundle's Deref impl
}
}
impl NSBundle {
pub fn new_with_path(path: &Path) -> Id<Self, Owned> {
let nsstring = NSString::from(path);
- let obj: *mut NSBundle = unsafe { msg_send![class!(NSBundle), alloc] };
- let obj: *mut NSBundle = unsafe { msg_send![obj, initWithPath: &nsstring] };
+ // NSString into ffi::NSString
+ let obj = unsafe { ffi::NSBundle::alloc().initWithPath_(nsstring.into()) } as *mut NSBundle;
Id::new(NonNull::new(obj).unwrap())
}
// new_with_url
pub fn main() -> Option<&'static Self> { // Or Id or autorelease stuff
- let obj: *mut NSBundle = unsafe { msg_send![class!(NSBundle), mainBundle] };
+ let obj = unsafe { ffi::NSBundle::mainBundle() } as *mut NSBundle;
unsafe { NonNull::new(obj).as_ref() }
}
pub fn path(&self) -> &NSString {
- unsafe { msg_send![self, bundlePath] }
+ unsafe { NSString::from_raw(self.0.bundlePath()) }
}
} The benefit here is that message sends would be properly typed, and hence can't go horribly wrong like they usually can; however, it also adds an extra layer of indirection, extra compile time and just extra stuff you have to know about. So I'm not sure it's worth it like this :/ |
I think a place where it could be really useful would be in helping with upholding the memory management rules; e.g. returning proper types for |
For example, the code above is probably wrong, because So if the bindings could have generated this (or however we do the autoreleasing) instead: pub unsafe fn bundlePath(&self, &'pool AutoreleasePool) -> &'pool NSString { ... } It would have done me a favor! |
But again, an alternative is just to use macros for most of this stuff, like |
Hey hey, just wanted to drop in and share some thoughts. Full disclosure... I've not really written much objective-c. Most of my knowledge of objective-c comes from adding the not-perfect-but-better-than-it-was objective-c support for
I never got around to finishing/merging rust-lang/rust-bindgen#1784 but this adds the hierarchy inheritance to the categories from the objective-c. The biggest issue with this PR is that it has to do a linear search on all the objects to find the ty which is a costly look up. I found it rather necessary for doing a lot of calls.
Yeah, this is how I felt about it. I spent a bunch of time doing my best to have the objective-c bindgen'd stuff be as ergonomic as I could without adding anything unsound or causing UB. I really like the
I tried to add Random thoughts:
|
Thanks for your input @simlay! I've also been looking at your
I think I've improved the situation in this crate, e.g. making it so that you don't accidentally pass Rough idea for how I would generate the bindings: pub struct UIView(Object); // Instead of `id`; this means you would use `*mut UIView` where `UIView` was previously expected.
// Would be defined in `objc`
pub struct Alloc<T>(NonNull<T>);
pub struct Retained<T>(NonNull<T>);
impl IUIView {
// Returns a type that can only be used after calling `init` on it.
pub unsafe fn alloc() -> Alloc<Self> { ... }
// Returns a reference-counting wrapper.
// Need to figure this out some more, see #87
pub unsafe fn init(s: Alloc<Self>) -> Retained<Self> { ... }
// Alternative:
// - self: *mut Self
// - view: *mut UIView
// - view: Retained<UIView> (if `addSubview:` took responsibility of releasing the object; in this case, it doesn't)
pub unsafe fn addSubview_(&self, view: &UIView) { ... }
}
Yeah, I can't figure that out either, I think they're bundled into the
I would also really like to improve this! Especially needed if we were to have e.g.
I would probably pre-generate the bindings using the latest SDKs, and try using the Another idea is to use cargo features, where enabling e.g. the
Yup, that would be reeeeally nice!
I'm not totally sure |
I think I found a way forward on the nullability, see rust-lang/rust-bindgen#1791 (comment)! |
Time has passed, things change, new ideas pop up: I recently migrated The main reason I've avoided
This could also be used to e.g. prevent creating Looking back, I'm glad I've up until now gone the route of "let the user do things themselves", since that has led to the invaluable So yeah, just a long speech to motivate myself to prioritize this damn |
Also of note: the |
Note: Ideally I'd like to parse directives like Note that I'd be fine with creating an internal tool, and then generating and publishing crates for bindings to all (or at least most) of Apple's official Objective-C frameworks using that (stated differently; if it's just changes to |
After an unreasonable amount of time, I managed to track down where the "Developer Documentation" is stored: Other links, in case I need them at some point: Apple's old documentation on "docsets": And the newer "DocC": |
This is pretty much why I got sucked into adding so much Objective-C support to Anyway, I like the idea having some generated Take for example the In this case, I'd suggest defaulting things to One thing I've noticed in the last 2 years or so is that the changes to |
I think a lot of it is autogenerated, yeah; we would have to do the
Definitely
Probably default to not mutating, but I'm not sure here either. EDIT: I've opened #265 to ponder this further.
See #264. |
#264 is done, so I'll close this. I may return to |
See rust-lang/rust-bindgen#109.
I would like to create a (temporary?) fork of
bindgen
that generates bindings targettingobjc2
. In particular,Encode
andRefEncode
impls, but theMessage
/MessageReceiver
stuff has also changed.In the end, what I really want is the ability to generate safe apis, but that's probably not gonna happen, it would at least require us to enrich every method with mutability information (
NSData -length
is immutable, whileNSMutableData -setLength:
is not), and we're never going to be able to generate a safe API for e.g.NSData -initWithBytesNoCopy:length:deallocator:
.The text was updated successfully, but these errors were encountered: