Skip to content

Commit 7c745c2

Browse files
committed
Fix NSObjectProtocol ProtocolType implementation
1 parent ed7eb95 commit 7c745c2

File tree

9 files changed

+110
-39
lines changed

9 files changed

+110
-39
lines changed

crates/icrate/examples/browser.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ declare_class!(
7373
}
7474
}
7575

76+
unsafe impl NSObjectProtocol for Delegate {}
77+
7678
unsafe impl NSApplicationDelegate for Delegate {
7779
#[method(applicationDidFinishLaunching:)]
7880
#[allow(non_snake_case)]
@@ -293,8 +295,6 @@ impl Delegate {
293295
}
294296
}
295297

296-
unsafe impl NSObjectProtocol for Delegate {}
297-
298298
fn main() {
299299
let mtm = MainThreadMarker::new().unwrap();
300300
let app = NSApplication::sharedApplication(mtm);

crates/icrate/examples/delegate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ declare_class!(
5050
}
5151
}
5252

53+
unsafe impl NSObjectProtocol for AppDelegate {}
54+
5355
unsafe impl NSApplicationDelegate for AppDelegate {
5456
#[method(applicationDidFinishLaunching:)]
5557
fn did_finish_launching(&self, notification: &NSNotification) {
@@ -65,8 +67,6 @@ declare_class!(
6567
}
6668
);
6769

68-
unsafe impl NSObjectProtocol for AppDelegate {}
69-
7070
impl AppDelegate {
7171
pub fn new(ivar: u8, another_ivar: bool, mtm: MainThreadMarker) -> Id<Self> {
7272
unsafe { msg_send_id![mtm.alloc(), initWith: ivar, another: another_ivar] }

crates/icrate/examples/metal.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,21 @@ use objc2::{
3131
#[rustfmt::skip]
3232
const SHADERS: &str = r#"
3333
#include <metal_stdlib>
34-
34+
3535
struct SceneProperties {
3636
float time;
37-
};
38-
37+
};
38+
3939
struct VertexInput {
4040
metal::packed_float3 position;
4141
metal::packed_float3 color;
4242
};
43-
43+
4444
struct VertexOutput {
4545
metal::float4 position [[position]];
4646
metal::float4 color;
4747
};
48-
48+
4949
vertex VertexOutput vertex_main(
5050
device const SceneProperties& properties [[buffer(0)]],
5151
device const VertexInput* vertices [[buffer(1)]],
@@ -64,7 +64,7 @@ const SHADERS: &str = r#"
6464
out.color = metal::float4(in.color, 1);
6565
return out;
6666
}
67-
67+
6868
fragment metal::float4 fragment_main(VertexOutput in [[stage_in]]) {
6969
return in.color;
7070
}
@@ -155,6 +155,8 @@ declare_class!(
155155
}
156156
}
157157

158+
unsafe impl NSObjectProtocol for Delegate {}
159+
158160
// define the delegate methods for the `NSApplicationDelegate` protocol
159161
unsafe impl NSApplicationDelegate for Delegate {
160162
#[method(applicationDidFinishLaunching:)]
@@ -356,8 +358,6 @@ declare_class!(
356358
}
357359
);
358360

359-
unsafe impl NSObjectProtocol for Delegate {}
360-
361361
impl Delegate {
362362
pub fn new(mtm: MainThreadMarker) -> Id<Self> {
363363
unsafe { msg_send_id![mtm.alloc(), init] }

crates/objc2/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4343
];
4444
```
4545

46+
### Fixed
47+
* Fixed the name of the protocol that `NSObjectProtocol` references.
48+
4649

4750
## 0.4.1 - 2023-07-31
4851

crates/objc2/src/__macro_helpers/mod.rs

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -580,32 +580,56 @@ impl ClassProtocolMethodsBuilder<'_, '_> {
580580
}
581581
}
582582

583-
#[inline]
583+
#[cfg(all(debug_assertions, feature = "verify"))]
584584
pub fn __finish(self) {
585-
#[cfg(all(debug_assertions, feature = "verify"))]
585+
let superclass = self.builder.superclass();
586+
586587
if let Some(protocol) = self.protocol {
587588
for desc in &self.required_instance_methods {
588-
if !self.registered_instance_methods.contains(&desc.sel) {
589-
panic!(
590-
"must implement required protocol method -[{protocol} {}]",
591-
desc.sel
592-
)
589+
if self.registered_instance_methods.contains(&desc.sel) {
590+
continue;
591+
}
592+
593+
// TODO: Don't do this when `NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION`
594+
if superclass
595+
.and_then(|superclass| superclass.instance_method(desc.sel))
596+
.is_some()
597+
{
598+
continue;
593599
}
600+
601+
panic!(
602+
"must implement required protocol method -[{protocol} {}]",
603+
desc.sel
604+
)
594605
}
595606
}
596607

597-
#[cfg(all(debug_assertions, feature = "verify"))]
598608
if let Some(protocol) = self.protocol {
599609
for desc in &self.required_class_methods {
600-
if !self.registered_class_methods.contains(&desc.sel) {
601-
panic!(
602-
"must implement required protocol method +[{protocol} {}]",
603-
desc.sel
604-
)
610+
if self.registered_class_methods.contains(&desc.sel) {
611+
continue;
612+
}
613+
614+
// TODO: Don't do this when `NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION`
615+
if superclass
616+
.and_then(|superclass| superclass.class_method(desc.sel))
617+
.is_some()
618+
{
619+
continue;
605620
}
621+
622+
panic!(
623+
"must implement required protocol method +[{protocol} {}]",
624+
desc.sel
625+
);
606626
}
607627
}
608628
}
629+
630+
#[inline]
631+
#[cfg(not(all(debug_assertions, feature = "verify")))]
632+
pub fn __finish(self) {}
609633
}
610634

611635
#[cfg(test)]

crates/objc2/src/declare/mod.rs

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ impl ClassBuilder {
356356
}
357357

358358
#[allow(unused)]
359-
fn superclass(&self) -> Option<&AnyClass> {
359+
pub(crate) fn superclass(&self) -> Option<&AnyClass> {
360360
// SAFETY: Though the class is not finalized, `class_getSuperclass` is
361361
// still safe to call.
362362
unsafe { AnyClass::superclass_raw(self.cls.as_ptr()) }
@@ -612,7 +612,9 @@ impl ClassBuilder {
612612
pub fn add_protocol(&mut self, proto: &AnyProtocol) {
613613
let success = unsafe { ffi::class_addProtocol(self.as_mut_ptr(), proto.as_ptr()) };
614614
let success = Bool::from_raw(success).as_bool();
615-
assert!(success, "failed to add protocol {proto}");
615+
if cfg!(not(feature = "gnustep-1-7")) {
616+
assert!(success, "failed to add protocol {proto}");
617+
}
616618
}
617619

618620
// fn add_property(&self, name: &str, attributes: &[ffi::objc_property_attribute_t]);
@@ -770,7 +772,7 @@ mod tests {
770772
use crate::mutability::Immutable;
771773
use crate::rc::Id;
772774
use crate::runtime::{NSObject, NSObjectProtocol};
773-
use crate::{declare_class, extern_methods, msg_send, test_utils, ClassType};
775+
use crate::{declare_class, extern_methods, msg_send, test_utils, ClassType, ProtocolType};
774776

775777
#[test]
776778
fn test_alignment() {
@@ -900,7 +902,43 @@ mod tests {
900902
}
901903

902904
#[test]
903-
#[should_panic = "failed to add protocol NSObject"]
905+
fn inheriting_does_not_implement_protocols() {
906+
let builder = ClassBuilder::new(
907+
"TestClassBuilderInheritingDoesNotImplementProtocols",
908+
NSObject::class(),
909+
)
910+
.unwrap();
911+
912+
let cls = builder.register();
913+
let conforms = cls.conforms_to(<dyn NSObjectProtocol>::protocol().unwrap());
914+
if cfg!(feature = "gnustep-1-7") {
915+
// FIXME: GNUStep works differently here!
916+
assert!(conforms);
917+
} else {
918+
assert!(!conforms);
919+
}
920+
}
921+
922+
#[test]
923+
fn inherit_nsobject_add_protocol() {
924+
let mut builder = ClassBuilder::new(
925+
"TestClassBuilderInheritNSObjectAddProtocol",
926+
NSObject::class(),
927+
)
928+
.unwrap();
929+
930+
let protocol = <dyn NSObjectProtocol>::protocol().unwrap();
931+
932+
builder.add_protocol(protocol);
933+
let cls = builder.register();
934+
assert!(cls.conforms_to(protocol));
935+
}
936+
937+
#[test]
938+
#[cfg_attr(
939+
not(feature = "gnustep-1-7"),
940+
should_panic = "failed to add protocol NSObject"
941+
)]
904942
fn duplicate_protocol() {
905943
let cls = test_utils::custom_class();
906944
let mut builder = ClassBuilder::new("TestClassBuilderDuplicateProtocol", cls).unwrap();

crates/objc2/src/macros/declare_class.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@
259259
/// # }
260260
/// }
261261
///
262+
/// unsafe impl NSObjectProtocol for MyCustomObject {}
263+
///
262264
/// # #[cfg(available_in_icrate)]
263265
/// unsafe impl NSCopying for MyCustomObject {
264266
/// #[method_id(copyWithZone:)]
@@ -274,9 +276,6 @@
274276
/// }
275277
/// );
276278
///
277-
/// // TODO: Allow moving this inside `declare_class!`
278-
/// unsafe impl NSObjectProtocol for MyCustomObject {}
279-
///
280279
/// impl MyCustomObject {
281280
/// pub fn new(foo: u8) -> Id<Self> {
282281
/// unsafe { msg_send_id![Self::alloc(), initWithFoo: foo] }

crates/objc2/src/runtime/nsobject.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ crate::__inner_extern_protocol!(
165165
()
166166
(NSObjectProtocol)
167167
(dyn NSObjectProtocol)
168-
("NSCopying")
168+
("NSObject")
169169
);
170170

171171
unsafe impl NSObjectProtocol for NSObject {}
@@ -372,4 +372,10 @@ mod tests {
372372

373373
assert_eq!(ptr1, ptr2);
374374
}
375+
376+
#[test]
377+
fn conforms_to_nsobjectprotocol() {
378+
let protocol = <dyn NSObjectProtocol>::protocol().unwrap();
379+
assert!(NSObject::class().conforms_to(protocol));
380+
}
375381
}

crates/objc2/src/runtime/protocol_object.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -253,21 +253,22 @@ mod tests {
253253
type Mutability = Mutable;
254254
const NAME: &'static str = "ProtocolTestsDummyClass";
255255
}
256+
257+
unsafe impl NSObjectProtocol for DummyClass {}
256258
);
257259

260+
unsafe impl Foo for DummyClass {}
261+
unsafe impl Bar for DummyClass {}
262+
unsafe impl FooBar for DummyClass {}
263+
// unsafe impl FooFooBar for DummyClass {}
264+
258265
extern_methods!(
259266
unsafe impl DummyClass {
260267
#[method_id(new)]
261268
fn new() -> Id<Self>;
262269
}
263270
);
264271

265-
unsafe impl NSObjectProtocol for DummyClass {}
266-
unsafe impl Foo for DummyClass {}
267-
unsafe impl Bar for DummyClass {}
268-
unsafe impl FooBar for DummyClass {}
269-
// unsafe impl FooFooBar for DummyClass {}
270-
271272
#[test]
272273
fn impl_traits() {
273274
assert_impl_all!(NSObject: NSObjectProtocol);

0 commit comments

Comments
 (0)