-
Notifications
You must be signed in to change notification settings - Fork 52
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
Improve #[derive(...)]
in declare_class!
#267
Comments
We also need to consider how things should work in
However I'm unsure how these implementations should actually work? In the case of types that inherit |
Maybe the actually useful thing in
unsafe impl MyObject {
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Id<Self>> {
let this = this.set_ivars(Self::Ivars::default()); // Require `Ivars: Default`
// SAFETY: Because of `Self::Super: IdDefault`, it is sound to call the `init` method on this
// `IdDefault` would need to be an `unsafe` trait, so that we can ensure the super class is `init`-able
unsafe { msg_send_id![super(this), init] }
}
}
// SAFETY: `init` is implemented and valid for this object
unsafe impl IdDefault for MyObject {}
unsafe impl NSCopying for MyObject {
#[method_id(copyWithZone:)]
fn copyWithZone(&self, zone: *const NSZone) -> Id<Self> {
// Implementation 1
// Require `T::Super: NSCopying`
let new = unsafe { msg_send_id![super(self), copyWithZone: zone] };
// Require `Self::Ivars: Clone`
new.set_ivars(self.ivars().clone())
// Implementation 2
// Require `Self::Ivars: Clone`
let new = Self::alloc().set_ivars(self.ivars().clone());
// Require `Self::Super: IdDefault`
unsafe { msg_send_id![super(self), init] }
}
} |
I think for unsafe impl NSObjectProtocol for MyObject {
#[method(isEqual:)]
#[cfg(Self implements PartialEq)]
fn isEqual(&self, other: &Self) -> bool {
<Self as PartialEq>::eq(self, other)
}
#[method(hash)]
#[cfg(Self implements Hash)]
fn hash(&self) -> NSUInteger {
let mut hasher = DefaultHasher::new();
<Self as Hash>::hash(self, &mut hasher);
hasher.finish() as NSUInteger
}
#[method_id(description)]
#[cfg(Self implements Debug)] // Maybe `Display`?
fn description(&self) -> Id<NSString> {
let s = format!("{self:?}");
NSString::from_str(&s)
}
#[method_id(debugDescription)]
#[cfg(Self implements Debug)]
fn debugDescription(&self) -> Id<NSString> {
let s = format!("{self:#?}"); // Note the `#:?` formatting
NSString::from_str(&s)
}
} |
The difficult part here is that in general, you could want two things when deriving So that's why making |
Debug
in extern_class!
#[derive(...)]
in extern_class!
#[derive(...)]
in extern_class!
#[derive(...)]
in extern_class!
and declare_class!
Swift's If the user wants anything else, they're supposed to override the Similarly for So maybe we should also just do referential equality by default? |
Previously, we used `CounterpartOrSelf`, which was a nice hack to work around Rust not having associated type defaults. Now, we use the user-facing `objc2_foundation::[Mutable]CopyingHelper`, which are intended to be implemented by the user alongside `NSCopying`. This is more verbose for the common case where the user just wants to say that something implements `NSCopying`, but is also better separation of concerns, and allows us to simplify `ClassType` further. We could consider a `#[derive(NSCopying)]` that does this, see: #267 Part of #563
Instead of specifying `impl ClassType for ...`, we instead parse the custom attributes `#[unsafe(super(...))]`, `#[thread_kind = ...]` and `#[name = ...]`. This is nice because: - It's more concise. - It more closely matches what we might end up with once it can become and attribute macro: rust-lang/rfcs#3697 - We need to parse the attributes anyhow to override derives: #267 (The extern_class! part of that issue is now resolved). - It makes it easier to change ClassType in the future without having to change the macro API as well. Additionally, this commit also adds incomplete support for generics, to avoid the framework crates depending on an internal macro, and it improves rust-analyzer support in extern_class! by having more relaxed parsing.
|
#[derive(...)]
in extern_class!
and declare_class!
#[derive(...)]
in declare_class!
0494d07 improves the I'm leaning towards exposing a |
Deriving
PartialEq
,Eq
andHash
automatically inextern_class!
works because it delegates to amsg_send!
call to the relevant selector.#[derive(Debug)]
, however, prints out the internal variable name as well as helpers that ensure that the type has the correct auto traits, which is really ugly, so we should use some macro hacks to extract and implement it ourselves as a direct delegation to the superclass'Debug
instead.The text was updated successfully, but these errors were encountered: