Skip to content

Commit

Permalink
msg_send_id![super]
Browse files Browse the repository at this point in the history
  • Loading branch information
madsmtm committed Oct 3, 2023
1 parent 3d170b5 commit 7e46d29
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 94 deletions.
46 changes: 22 additions & 24 deletions crates/icrate/examples/browser.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![deny(unsafe_op_in_unsafe_fn)]
use core::{cell::OnceCell, ptr::NonNull};
use core::cell::OnceCell;

use icrate::{
AppKit::{
Expand All @@ -18,26 +18,23 @@ use icrate::{
WebKit::{WKNavigation, WKNavigationDelegate, WKWebView},
};
use objc2::{
declare::{Ivar, IvarDrop},
declare_class, msg_send, msg_send_id,
declare_class, msg_send_id,
mutability::MainThreadOnly,
rc::Id,
rc::{Allocated, Id},
runtime::{AnyObject, ProtocolObject, Sel},
sel, ClassType,
sel, ClassType, DeclaredClass,
};

type IdCell<T> = Box<OnceCell<Id<T>>>;

macro_rules! idcell {
($name:ident => $this:expr) => {
$this.$name.set($name).expect(&format!(
$this.ivars().$name.set($name).expect(&format!(
"ivar should not already be initialized: `{}`",
stringify!($name)
));
};
($name:ident <= $this:expr) => {
#[rustfmt::skip]
let Some($name) = $this.$name.get() else {
let Some($name) = $this.ivars().$name.get() else {
unreachable!(
"ivar should be initialized: `{}`",
stringify!($name)
Expand All @@ -46,30 +43,31 @@ macro_rules! idcell {
};
}

#[derive(Default)]
struct Ivars {
nav_url: OnceCell<Id<NSTextField>>,
web_view: OnceCell<Id<WKWebView>>,
window: OnceCell<Id<NSWindow>>,
}

declare_class!(
struct Delegate {
nav_url: IvarDrop<IdCell<NSTextField>, "_nav_url">,
web_view: IvarDrop<IdCell<WKWebView>, "_web_view">,
window: IvarDrop<IdCell<NSWindow>, "_window">,
}
mod ivars;
struct Delegate;

unsafe impl ClassType for Delegate {
type Super = NSObject;
type Mutability = MainThreadOnly;
const NAME: &'static str = "Delegate";
}

impl DeclaredClass for Delegate {
type Ivars = Ivars;
}

unsafe impl Delegate {
#[method(init)]
unsafe fn init(this: *mut Self) -> Option<NonNull<Self>> {
let this: Option<&mut Self> = msg_send![super(this), init];
this.map(|this| {
Ivar::write(&mut this.nav_url, IdCell::default());
Ivar::write(&mut this.web_view, IdCell::default());
Ivar::write(&mut this.window, IdCell::default());
NonNull::from(this)
})
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Id<Self>> {
let this = this.set_ivars(Ivars::default());
unsafe { msg_send_id![super(this), init] }
}
}

Expand Down
60 changes: 30 additions & 30 deletions crates/icrate/examples/delegate.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,52 @@
#![deny(unsafe_op_in_unsafe_fn)]
use std::ptr::NonNull;

use icrate::AppKit::{NSApplication, NSApplicationActivationPolicyRegular, NSApplicationDelegate};
use icrate::Foundation::{
ns_string, MainThreadMarker, NSCopying, NSNotification, NSObject, NSObjectProtocol, NSString,
};
use objc2::declare::{Ivar, IvarBool, IvarDrop, IvarEncode};
use objc2::rc::Id;
use objc2::rc::{Allocated, Id};
use objc2::runtime::ProtocolObject;
use objc2::{declare_class, msg_send, msg_send_id, mutability, ClassType};
use objc2::{declare_class, msg_send_id, mutability, ClassType, DeclaredClass};

#[derive(Debug)]
#[allow(unused)]
struct Ivars {
ivar: u8,
another_ivar: bool,
box_ivar: Box<i32>,
maybe_box_ivar: Option<Box<i32>>,
id_ivar: Id<NSString>,
maybe_id_ivar: Option<Id<NSString>>,
}

declare_class!(
#[derive(Debug)]
struct AppDelegate {
ivar: IvarEncode<u8, "_ivar">,
another_ivar: IvarBool<"_another_ivar">,
box_ivar: IvarDrop<Box<i32>, "_box_ivar">,
maybe_box_ivar: IvarDrop<Option<Box<i32>>, "_maybe_box_ivar">,
id_ivar: IvarDrop<Id<NSString>, "_id_ivar">,
maybe_id_ivar: IvarDrop<Option<Id<NSString>>, "_maybe_id_ivar">,
}

mod ivars;
struct AppDelegate;

unsafe impl ClassType for AppDelegate {
type Super = NSObject;
type Mutability = mutability::MainThreadOnly;
const NAME: &'static str = "MyAppDelegate";
}

impl DeclaredClass for AppDelegate {
type Ivars = Ivars;
}

unsafe impl AppDelegate {
#[method(initWith:another:)]
unsafe fn init_with(
this: *mut Self,
#[method_id(initWith:another:)]
fn init_with(
this: Allocated<Self>,
ivar: u8,
another_ivar: bool,
) -> Option<NonNull<Self>> {
let this: Option<&mut Self> = unsafe { msg_send![super(this), init] };

this.map(|this| {
Ivar::write(&mut this.ivar, ivar);
Ivar::write(&mut this.another_ivar, another_ivar);
Ivar::write(&mut this.maybe_box_ivar, None);
Ivar::write(&mut this.maybe_id_ivar, Some(ns_string!("def").copy()));
Ivar::write(&mut this.box_ivar, Box::new(2));
Ivar::write(&mut this.id_ivar, NSString::from_str("abc"));
NonNull::from(this)
})
) -> Option<Id<Self>> {
let this = this.set_ivars(Ivars {
ivar,another_ivar,
box_ivar: Box::new(2),
maybe_box_ivar: None,
id_ivar: NSString::from_str("abc"),
maybe_id_ivar: Some(ns_string!("def").copy()),
});
unsafe { msg_send_id![super(this), init] }
}
}

Expand Down
56 changes: 28 additions & 28 deletions crates/icrate/examples/metal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ use icrate::{
MetalKit::{MTKView, MTKViewDelegate},
};
use objc2::{
declare::{Ivar, IvarDrop},
declare_class, msg_send, msg_send_id,
declare_class, msg_send_id,
mutability::MainThreadOnly,
rc::Id,
rc::{Allocated, Id},
runtime::ProtocolObject,
ClassType,
ClassType, DeclaredClass,
};

#[rustfmt::skip]
Expand Down Expand Up @@ -101,18 +100,16 @@ pub struct Color {
pub b: f32,
}

type IdCell<T> = Box<OnceCell<Id<T>>>;

macro_rules! idcell {
($name:ident => $this:expr) => {
$this.$name.set($name).expect(&format!(
$this.ivars().$name.set($name).expect(&format!(
"ivar should not already be initialized: `{}`",
stringify!($name)
));
};
($name:ident <= $this:expr) => {
#[rustfmt::skip]
let Some($name) = $this.$name.get() else {
let Some($name) = $this.ivars().$name.get() else {
unreachable!(
"ivar should be initialized: `{}`",
stringify!($name)
Expand All @@ -121,17 +118,17 @@ macro_rules! idcell {
};
}

// declare the desired instance variables
struct Ivars {
start_date: Id<NSDate>,
command_queue: OnceCell<Id<ProtocolObject<dyn MTLCommandQueue>>>,
pipeline_state: OnceCell<Id<ProtocolObject<dyn MTLRenderPipelineState>>>,
window: OnceCell<Id<NSWindow>>,
}

// declare the Objective-C class machinery
declare_class!(
// declare the delegate class with our instance variables
#[rustfmt::skip] // FIXME: rustfmt breaks the macro parsing apparently
struct Delegate {
start_date: IvarDrop<Id<NSDate>, "_start_date">,
command_queue: IvarDrop<IdCell<ProtocolObject<dyn MTLCommandQueue>>, "_command_queue">,
pipeline_state: IvarDrop<IdCell<ProtocolObject<dyn MTLRenderPipelineState>>, "_pipeline_state">,
window: IvarDrop<IdCell<NSWindow>, "_window">,
}
mod ivars;
struct Delegate;

// declare the class type
unsafe impl ClassType for Delegate {
Expand All @@ -140,18 +137,21 @@ declare_class!(
const NAME: &'static str = "Delegate";
}

impl DeclaredClass for Delegate {
type Ivars = Ivars;
}

// define the Delegate methods (e.g., initializer)
unsafe impl Delegate {
#[method(init)]
unsafe fn init(this: *mut Self) -> Option<NonNull<Self>> {
let this: Option<&mut Self> = msg_send![super(this), init];
this.map(|this| {
Ivar::write(&mut this.start_date, unsafe { NSDate::now() });
Ivar::write(&mut this.command_queue, IdCell::default());
Ivar::write(&mut this.pipeline_state, IdCell::default());
Ivar::write(&mut this.window, IdCell::default());
NonNull::from(this)
})
#[method_id(init)]
fn init(this: Allocated<Self>) -> Option<Id<Self>> {
let this = this.set_ivars(Ivars {
start_date: unsafe { NSDate::now() },
command_queue: OnceCell::default(),
pipeline_state: OnceCell::default(),
window: OnceCell::default(),
});
unsafe { msg_send_id![super(this), init] }
}
}

Expand Down Expand Up @@ -277,7 +277,7 @@ declare_class!(

// compute the scene properties
let scene_properties_data = &SceneProperties {
time: unsafe { self.start_date.timeIntervalSinceNow() } as f32,
time: unsafe { self.ivars().start_date.timeIntervalSinceNow() } as f32,
};
// write the scene properties to the vertex shader argument buffer at index 0
let scene_properties_bytes = NonNull::from(scene_properties_data);
Expand Down
2 changes: 1 addition & 1 deletion crates/objc2/src/__macro_helpers/declare_class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl<T: ?Sized + DeclaredClass> ClassBuilderHelper<T> {
}

#[inline]
pub fn register(mut self) -> (&'static AnyClass, isize, isize) {
pub fn register(self) -> (&'static AnyClass, isize, isize) {
register_with_ivars::<T>(self.builder)
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/objc2/src/__macro_helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub use self::method_family::{
retain_semantics, Alloc, CopyOrMutCopy, Init, New, Other, RetainSemantics,
};
pub use self::msg_send::MsgSend;
pub use self::msg_send_id::{MaybeUnwrap, MsgSendId};
pub use self::msg_send_id::{MaybeUnwrap, MsgSendId, MsgSendSuperId};

/// Helper struct for emitting the module info that macOS 32-bit requires.
///
Expand Down
Loading

0 comments on commit 7e46d29

Please sign in to comment.