-
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
Define methods in extern_class!
macro
#161
Conversation
API idea (doesn't have to actually parse the derives yet, just ensure that they're there - makes it possible to extend the macro in the future): object! {
#[derive(Debug, PartialEq, Eq, Hash, AsRef, AsMut, Deref, DerefMut, Borrow, BorrowMut)]
unsafe pub struct NSArray<T, O: Ownership>: NSObject {
item: PhantomData<Id<T, O>>,
}
} Alternative: object! {
unsafe pub struct NSArray<T, O: Ownership>: NSObject {
item: PhantomData<Id<T, O>>,
}
// Deref, DerefMut, AsRef, AsMut, Borrow and BorrowMut are implied
impl Debug;
impl PartialEq;
impl Eq;
impl Hash;
// Possibility:
unsafe impl Default;
// Some way to say "we add inherent `class` method as well"?
} |
Maybe rename to |
Idea: object! {
// Struct declaration as above
unsafe impl NSSomeObject {
// Class method.
// Selector could probably be inferred from the function name a lot of the time, but let's not worry about that just yet!
#[selector = "new"]
pub fn new() -> Option<Id<Self, Owned>>;
// Instance method.
#[selector = "abc:defGhi:"]
pub fn abc_def_ghi(&self, arg1: &Object, arg2: i32);
// Private function, allows user to create a safe wrapper.
#[selector = "returnsPointer"]
fn pointer_param_impl(&self) -> *const c_void;
// Unsafe function, user has to ensure validity of pointer.
#[selector = "setPointerParam:"]
pub unsafe fn set_pointer_param(&mut self, param: *const c_void);
}
}
// Would generate:
impl NSSomeObject {
#[doc(alias = "new")]
pub fn new() -> Option<Id<Self, Owned>> {
// Infer `msg_send_id` from return type
// Infer `Self::class()` from it being a class method (no `&self/&mut self`)
unsafe { msg_send_id![Self::class(), new] }
}
#[doc(alias = "abc:defGhi:")]
pub fn abc_def_ghi(&self, arg1: &Object, arg2: bool) {
// Assume `Bool` is desired!
unsafe { msg_send![self, abc: arg1, defGhi: Bool::from(arg2)] }
}
#[doc(alias = "returnsPointer")]
fn pointer_param_impl(&self) -> *const c_void {
unsafe { msg_send![self, returnsPointer] }
}
#[doc(alias = "setPointerParam:")]
pub unsafe fn set_pointer_param(&mut self, param: *const c_void) {
unsafe { msg_send![self, setPointerParam: param] }
}
}
#[test]
fn test_encoding() {
let cls = NSSomeObject::class();
assert_eq!(verify_message::<(), *const Self>(cls.superclass(), sel!(new)));
assert_eq!(verify_message::<(&Object, i32), ()>(cls, sel!(abc:defGhi:)));
assert_eq!(verify_message::<(), *const c_void>(cls, sel!(returnsPointer)));
assert_eq!(verify_message::<(*const c_void,), ()>(cls, sel!(setPointerParam:)));
} This is close to the macro ideas from #30, but still distinctly different in that this only helps with accessing the class (we really need both)! It could even restrict things like returning |
Unsure of how much of this belongs in |
I do believe it should just stay in
I really like this definition overall 👍 Another thing: How would this translate for properties? I have been working a bit on some UIKit stuffs in the past weeks and this is what i came up in general (while basing it on some stuffs from objc2): create_objc_object!(UIColor, NSObject);
impl_objc_properties!(
UIColor,
static blackColor: UIColor,
static darkGrayColor: UIColor,
static lightGrayColor: UIColor,
static whiteColor: UIColor,
static grayColor: UIColor,
static redColor: UIColor,
static greenColor: UIColor,
static blueColor: UIColor,
static cyanColor: UIColor,
static yellowColor: UIColor,
static magentaColor: UIColor,
static orangeColor: UIColor,
static purpleColor: UIColor,
static brownColor: UIColor,
static clearColor: UIColor,
);
create_objc_object!(UIResponder, NSObject);
// TODO: UIResponder definition
create_objc_object!(UIView, UIResponder);
// UIViewRendering
impl_objc_properties!(
UIView,
mut clipsToBounds setClipsToBounds: value<bool>,
mut backgroundColor setBackgroundColor: UIColor,
mut isOpaque setOpaque: value<bool>,
mut clearsContextBeforeDrawing setClearsContextBeforeDrawing: value<bool>,
mut isHidden setHidden: value<bool>,
mut contentMode setContentMode: value<UIViewContentMode>,
// contentStretch (deprecated)
mut alpha setAlpha: value<CGFloat>,
// Since iOS 8.0
mut maskView setMaskView: UIView,
// TODO: null_resettable
// Since iOS 7.0
mut tintColor setTintColor: UIColor,
// Since iOS 7.0
mut tintAdjustmentMode setTintAdjustmentMode: value<UIViewTintAdjustmentMode>,
); macro implementation is here if you are interested |
I've managed to create a working prototype of the idea presented in #161 (comment), but I'm not really happy with how brittle it is in detecting I took parts of this PR that I'm content with out (looking at it now, essentially the same as your
A (declarative) macro would have quite a hard time reliably inspecting whether there is a
Honestly haven't thought about properties yet at all... Your macros look nice though, I would probably go for a more "native"-looking syntax (at least in one sense of the word "native") than you have, and use
Cool to see that someone is already starting to use it! |
Awesome, I will try to handle the transition when I get time 👍
That seems fair. The real problem is that currently a lot of crate using objc interactions just wrap around calls to objc_msgSend and call it day without taking into account the safety of those APIs. I guess people just need to be better educated 😅
I was kind of thinking doing that at first, but it is quite hard to handle especially if you have multiple attributes passed in the @Property.
Thanks ^^ |
Yeah that sounds like it might be a problem.
Agree (in particular because I know declarative macros fairly well by now, while I'm really terrible at writing proc macros...)
Cool, do let me know when/if you have something to show! Relatedly, at some point I'll integrate |
Will make sure to let you know 👍
Never heard about Cacao but after a quick look, it seems enough for all my UIKit needs so thanks for the info ^^ |
Working on this a bit more: Currently the syntax is unsafe impl {
#[unrelated_attribute]
#sel!(new)
pub fn new() -> Option<Id<Self, Owned>>;
#sel!(abc:defGhi:)
pub fn abc_def_ghi(&self, arg1: &Object, arg2: i32);
} Because I couldn't find a good way to extract the More importantly, |
I managed to find a way so that you can use normal attribute syntax, e.g. Instead of combining "type declaration" and "method declaration" into one macro, I've chosen to split it out into two separate macros:
This makes it much easier to see and document what's happening, and |
Part of #67.
Something that will greatly help consumers create their own Objective-C classes. For example, I'd like to use this in
winit
to define safe abstractions overNSApplication
,NSWindow
,NSView
,NSResponer
and so on.TODO:
extern_class!
macro #188