Skip to content
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

Initial conversion to objc2 #30

Merged
merged 19 commits into from
Sep 11, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use &'static Class instead of *const Class
Safer and more ergonomic. Also required for `msg_send_id!` macro
madsmtm committed Sep 5, 2023
commit c7f219412733243dd5642c22fc6813fba9d2efe8
10 changes: 5 additions & 5 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -352,8 +352,8 @@ We'll step through an example (abridged) `View` bridge below, for macOS. You sho
For our basic `View` type, we want to just map to the corresponding class on the Objective-C side (in this case, `NSView`), and maybe do a bit of tweaking for sanity reasons.

``` rust
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
@@ -364,10 +364,10 @@ pub(crate) fn register_view_class() -> *const Class {

decl.add_ivar::<id>(BACKGROUND_COLOR);

VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
```

@@ -377,7 +377,7 @@ Objective-C method signatures, as well as provision space for variable storage (
For our _delegate_ types, we need a different class creation method - one that creates a subclass per-unique-type:

``` rust
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSView", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
decl.add_ivar::<id>(BACKGROUND_COLOR);
2 changes: 1 addition & 1 deletion src/appkit/app/class.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,6 @@ use objc::runtime::Class;
use crate::foundation::load_or_register_class;

/// Used for injecting a custom NSApplication. Currently does nothing.
pub(crate) fn register_app_class() -> *const Class {
pub(crate) fn register_app_class() -> &'static Class {
load_or_register_class("NSApplication", "RSTApplication", |decl| unsafe {})
}
2 changes: 1 addition & 1 deletion src/appkit/app/delegate.rs
Original file line number Diff line number Diff line change
@@ -291,7 +291,7 @@ extern "C" fn delegate_handles_key<T: AppDelegate>(this: &Object, _: Sel, _: id,

/// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have.
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *const Class {
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> &'static Class {
load_or_register_class("NSObject", "RSTAppDelegate", |decl| unsafe {
decl.add_ivar::<usize>(APP_PTR);

2 changes: 1 addition & 1 deletion src/appkit/menu/item.rs
Original file line number Diff line number Diff line change
@@ -314,7 +314,7 @@ extern "C" fn fire_block_action(this: &Object, _: Sel, _item: id) {
///
/// In general, we do not want to do more than we need to here - menus are one of the last areas
/// where Carbon still lurks, and subclassing things can get weird.
pub(crate) fn register_menu_item_class() -> *const Class {
pub(crate) fn register_menu_item_class() -> &'static Class {
load_or_register_class("NSMenuItem", "CacaoMenuItem", |decl| unsafe {
decl.add_ivar::<usize>(BLOCK_PTR);

2 changes: 1 addition & 1 deletion src/appkit/toolbar/class.rs
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@ extern "C" fn item_for_identifier<T: ToolbarDelegate>(this: &Object, _: Sel, _:

/// Registers a `NSToolbar` subclass, and configures it to hold some ivars for various things we need
/// to store. We use it as our delegate as well, just to cut down on moving pieces.
pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_toolbar_class<T: ToolbarDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSObject", instance.subclass_name(), |decl| unsafe {
// For callbacks
decl.add_ivar::<usize>(TOOLBAR_PTR);
2 changes: 1 addition & 1 deletion src/appkit/window/class.rs
Original file line number Diff line number Diff line change
@@ -227,7 +227,7 @@ extern "C" fn cancel<T: WindowDelegate>(this: &Object, _: Sel, _: id) {

/// Injects an `NSWindowDelegate` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_window_class_with_delegate<T: WindowDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_window_class_with_delegate<T: WindowDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSWindow", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR);

2 changes: 1 addition & 1 deletion src/appkit/window/controller/class.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ use crate::foundation::load_or_register_class;

/// Injects an `NSWindowController` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_window_controller_class<T: WindowDelegate>() -> *const Class {
pub(crate) fn register_window_controller_class<T: WindowDelegate>() -> &'static Class {
load_or_register_class("NSWindowController", "RSTWindowController", |decl| unsafe {
decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR);
})
2 changes: 1 addition & 1 deletion src/button/mod.rs
Original file line number Diff line number Diff line change
@@ -352,7 +352,7 @@ impl Drop for Button {

/// Registers an `NSButton` subclass, and configures it to hold some ivars
/// for various things we need to store.
fn register_class() -> *const Class {
fn register_class() -> &'static Class {
#[cfg(feature = "appkit")]
let super_class = "NSButton";
#[cfg(all(feature = "uikit", not(feature = "appkit")))]
2 changes: 1 addition & 1 deletion src/color/appkit_dynamic_color.rs
Original file line number Diff line number Diff line change
@@ -253,7 +253,7 @@ extern "C" fn color_with_system_effect(this: &Object, _: Sel, effect: NSInteger)
unsafe { msg_send![color, colorWithSystemEffect: effect] }
}

pub(crate) fn register_class() -> *const Class {
pub(crate) fn register_class() -> &'static Class {
load_or_register_class("NSColor", "CacaoDynamicColor", |decl| unsafe {
// These methods all need to be forwarded, so let's hook them up.
decl.add_method(sel!(colorSpace), color_space as extern "C" fn(_, _) -> _);
14 changes: 7 additions & 7 deletions src/foundation/class.rs
Original file line number Diff line number Diff line change
@@ -60,20 +60,20 @@ impl ClassMap {
}

/// A publicly accessible load method that just passes through our global singleton.
pub fn static_load(class_name: &'static str, superclass_name: Option<&'static str>) -> Option<*const Class> {
pub fn static_load(class_name: &'static str, superclass_name: Option<&'static str>) -> Option<&'static Class> {
CLASSES.load(class_name, superclass_name)
}

/// Attempts to load a previously registered class.
///
/// This checks our internal map first, and then calls out to the Objective-C runtime to ensure
/// we're not missing anything.
pub fn load(&self, class_name: &'static str, superclass_name: Option<&'static str>) -> Option<*const Class> {
pub fn load(&self, class_name: &'static str, superclass_name: Option<&'static str>) -> Option<&'static Class> {
{
let reader = self.0.read().unwrap();
if let Some(entry) = (*reader).get(&(class_name, superclass_name)) {
let ptr = &entry.ptr;
return Some(*ptr as *const Class);
return Some(unsafe { &*(*ptr as *const Class) });
}
}

@@ -102,7 +102,7 @@ impl ClassMap {
});
}

Some(class.cast())
Some(unsafe { class.cast::<Class>().as_ref() }.unwrap())
}

/// Store a newly created subclass type.
@@ -130,7 +130,7 @@ impl ClassMap {
/// > class name - but most cases do not need this and it would be a larger change to orchestrate at
/// > the moment.
#[inline(always)]
pub fn load_or_register_class<F>(superclass_name: &'static str, subclass_name: &'static str, config: F) -> *const Class
pub fn load_or_register_class<F>(superclass_name: &'static str, subclass_name: &'static str, config: F) -> &'static Class
where
F: Fn(&mut ClassDecl) + 'static
{
@@ -156,7 +156,7 @@ pub fn load_or_register_class_with_optional_generated_suffix<F>(
subclass_name: &'static str,
should_append_random_subclass_name_suffix: bool,
config: F
) -> *const Class
) -> &'static Class
where
F: Fn(&mut ClassDecl) + 'static
{
@@ -189,7 +189,7 @@ where
false => format!("{}_{}", subclass_name, superclass_name)
};

match ClassDecl::new(&objc_subclass_name, unsafe { &*superclass }) {
match ClassDecl::new(&objc_subclass_name, superclass) {
Some(mut decl) => {
config(&mut decl);

2 changes: 1 addition & 1 deletion src/image/appkit.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ use crate::foundation::load_or_register_class;
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_image_view_class() -> *const Class {
pub(crate) fn register_image_view_class() -> &'static Class {
load_or_register_class("NSImageView", "RSTImageView", |decl| unsafe {
//decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
})
2 changes: 1 addition & 1 deletion src/image/mod.rs
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ mod icons;
pub use icons::*;

/// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id {
fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe {
let view: id = msg_send![registration_fn(), new];

2 changes: 1 addition & 1 deletion src/image/uikit.rs
Original file line number Diff line number Diff line change
@@ -5,6 +5,6 @@ use crate::foundation::load_or_register_class;
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_image_view_class() -> *const Class {
pub(crate) fn register_image_view_class() -> &'static Class {
load_or_register_class("UIImageView", "RSTImageView", |decl| unsafe {})
}
4 changes: 2 additions & 2 deletions src/input/appkit.rs
Original file line number Diff line number Diff line change
@@ -46,13 +46,13 @@ extern "C" fn text_should_end_editing<T: TextFieldDelegate>(this: &Object, _: Se
/// Injects an `NSTextField` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("NSTextField", "RSTTextInputField", |decl| unsafe {})
}

/// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSTextField", instance.subclass_name(), |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
2 changes: 1 addition & 1 deletion src/input/mod.rs
Original file line number Diff line number Diff line change
@@ -78,7 +78,7 @@ pub use traits::TextFieldDelegate;
pub(crate) static TEXTFIELD_DELEGATE_PTR: &str = "rstTextFieldDelegatePtr";

/// A helper method for instantiating view classes and applying default settings to them.
fn common_init(class: *const Class) -> id {
fn common_init(class: &Class) -> id {
unsafe {
let view: id = msg_send![class, new];

10 changes: 5 additions & 5 deletions src/input/uikit.rs
Original file line number Diff line number Diff line change
@@ -50,22 +50,22 @@ extern "C" fn text_should_end_editing<T: TextFieldDelegate>(this: &Object, _: Se
/// Injects an `UITextField` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
let superclass = class!(UITextField);
let decl = ClassDecl::new("RSTTextInputField", superclass).unwrap();
VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}

/// Injects an `UITextField` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: TextFieldDelegate>(instance: &T) -> &'static Class {
load_or_register_class("UITextField", instance.subclass_name(), |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
2 changes: 1 addition & 1 deletion src/invoker.rs
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ extern "C" fn perform<F: Fn(*const Object) + 'static>(this: &mut Object, _: Sel,
/// The `NSButton` owns this object on instantiation, and will release it
/// on drop. We handle the heap copy on the Rust side, so setting the block
/// is just an ivar.
pub(crate) fn register_invoker_class<F: Fn(*const Object) + 'static>() -> *const Class {
pub(crate) fn register_invoker_class<F: Fn(*const Object) + 'static>() -> &'static Class {
load_or_register_class("NSObject", "RSTTargetActionHandler", |decl| unsafe {
decl.add_ivar::<usize>(ACTION_CALLBACK_PTR);
decl.add_method(sel!(perform:), perform::<F> as extern "C" fn(_, _, _));
4 changes: 2 additions & 2 deletions src/listview/appkit.rs
Original file line number Diff line number Diff line change
@@ -181,15 +181,15 @@ extern "C" fn dragging_exited<T: ListViewDelegate>(this: &mut Object, _: Sel, in
/// need to do. Note that we treat and constrain this as a one-column "list" view to match
/// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can
/// be added in.
pub(crate) fn register_listview_class() -> *const Class {
pub(crate) fn register_listview_class() -> &'static Class {
load_or_register_class("NSTableView", "RSTListView", |decl| unsafe {})
}

/// Injects an `NSTableView` subclass, with some callback and pointer ivars for what we
/// need to do. Note that we treat and constrain this as a one-column "list" view to match
/// `UITableView` semantics; if `NSTableView`'s multi column behavior is needed, then it can
/// be added in.
pub(crate) fn register_listview_class_with_delegate<T: ListViewDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_listview_class_with_delegate<T: ListViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSTableView", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(LISTVIEW_DELEGATE_PTR);

2 changes: 1 addition & 1 deletion src/listview/mod.rs
Original file line number Diff line number Diff line change
@@ -100,7 +100,7 @@ use std::cell::RefCell;
use std::rc::Rc;

/// A helper method for instantiating view classes and applying default settings to them.
fn common_init(class: *const Class) -> id {
fn common_init(class: &Class) -> id {
unsafe {
// Note: we do *not* enable AutoLayout here as we're by default placing this in a scroll
// view, and we want it to just do its thing.
4 changes: 2 additions & 2 deletions src/listview/row/appkit.rs
Original file line number Diff line number Diff line change
@@ -103,15 +103,15 @@ extern "C" fn dealloc<T: ViewDelegate>(this: &Object, _: Sel) {
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_listview_row_class() -> *const Class {
pub(crate) fn register_listview_row_class() -> &'static Class {
load_or_register_class("NSView", "RSTTableViewRow", |decl| unsafe {
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
})
}

/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_listview_row_class_with_delegate<T: ViewDelegate>() -> *const Class {
pub(crate) fn register_listview_row_class_with_delegate<T: ViewDelegate>() -> &'static Class {
load_or_register_class("NSView", "RSTableViewRowWithDelegate", |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
2 changes: 1 addition & 1 deletion src/listview/row/mod.rs
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ pub(crate) static BACKGROUND_COLOR: &str = "cacaoBackgroundColor";
pub(crate) static LISTVIEW_ROW_DELEGATE_PTR: &str = "cacaoListViewRowDelegatePtr";

/// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id {
fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe {
let view: id = msg_send![registration_fn(), new];

4 changes: 2 additions & 2 deletions src/listview/row/uikit.rs
Original file line number Diff line number Diff line change
@@ -11,13 +11,13 @@ use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR};
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("UIView", "RSTView", |decl| unsafe {})
}

/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>() -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>() -> &'static Class {
load_or_register_class("UIView", "RSTViewWithDelegate", |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
})
4 changes: 2 additions & 2 deletions src/scrollview/appkit.rs
Original file line number Diff line number Diff line change
@@ -73,13 +73,13 @@ extern "C" fn dragging_exited<T: ScrollViewDelegate>(this: &mut Object, _: Sel,
}

/// Injects an `NSScrollView` subclass.
pub(crate) fn register_scrollview_class() -> *const Class {
pub(crate) fn register_scrollview_class() -> &'static Class {
load_or_register_class("NSScrollView", "RSTScrollView", |decl| unsafe {})
}

/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> *const Class {
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> &'static Class {
load_or_register_class("NSScrollView", "RSTScrollViewWithDelegate", |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
2 changes: 1 addition & 1 deletion src/scrollview/mod.rs
Original file line number Diff line number Diff line change
@@ -75,7 +75,7 @@ pub use traits::ScrollViewDelegate;
pub(crate) static SCROLLVIEW_DELEGATE_PTR: &str = "rstScrollViewDelegatePtr";

/// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id {
fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe {
let view: id = msg_send![registration_fn(), new];

16 changes: 8 additions & 8 deletions src/scrollview/uikit.rs
Original file line number Diff line number Diff line change
@@ -78,23 +78,23 @@ extern "C" fn dragging_exited<T: ScrollViewDelegate>(this: &mut Object, _: Sel,
*/

/// Injects an `UIScrollView` subclass.
pub(crate) fn register_scrollview_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_scrollview_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
let superclass = class!(UIScrollView);
let decl = ClassDecl::new("RSTScrollView", superclass).unwrap();
VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}

/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
@@ -131,8 +131,8 @@ pub(crate) fn register_scrollview_class_with_delegate<T: ScrollViewDelegate>() -
);
*/

VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
2 changes: 1 addition & 1 deletion src/select/mod.rs
Original file line number Diff line number Diff line change
@@ -262,6 +262,6 @@ impl Drop for Select {

/// Registers an `NSSelect` subclass, and configures it to hold some ivars
/// for various things we need to store.
fn register_class() -> *const Class {
fn register_class() -> &'static Class {
load_or_register_class("NSPopUpButton", "CacaoSelect", |decl| unsafe {})
}
2 changes: 1 addition & 1 deletion src/switch.rs
Original file line number Diff line number Diff line change
@@ -172,6 +172,6 @@ impl Drop for Switch {

/// Registers an `NSButton` subclass, and configures it to hold some ivars
/// for various things we need to store.
fn register_class() -> *const Class {
fn register_class() -> &'static Class {
load_or_register_class("NSButton", "RSTSwitch", |decl| unsafe {})
}
4 changes: 2 additions & 2 deletions src/text/label/appkit.rs
Original file line number Diff line number Diff line change
@@ -15,13 +15,13 @@ use crate::text::label::{LabelDelegate, LABEL_DELEGATE_PTR};
/// Injects an `NSTextField` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("NSTextField", "RSTTextField", |decl| unsafe {})
}

/// Injects an `NSTextField` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> &'static Class {
load_or_register_class("NSView", "RSTTextFieldWithDelegate", |decl| unsafe {
// A pointer to the "view controller" on the Rust side. It's expected that this doesn't
// move.
2 changes: 1 addition & 1 deletion src/text/label/mod.rs
Original file line number Diff line number Diff line change
@@ -78,7 +78,7 @@ pub use traits::LabelDelegate;
pub(crate) static LABEL_DELEGATE_PTR: &str = "rstLabelDelegatePtr";

/// A helper method for instantiating view classes and applying default settings to them.
fn allocate_view(registration_fn: fn() -> *const Class) -> id {
fn allocate_view(registration_fn: fn() -> &'static Class) -> id {
unsafe {
#[cfg(feature = "appkit")]
let view: id = {
16 changes: 8 additions & 8 deletions src/text/label/uikit.rs
Original file line number Diff line number Diff line change
@@ -11,23 +11,23 @@ use crate::text::label::{LabelDelegate, LABEL_DELEGATE_PTR};
/// Injects an `UILabel` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
let superclass = class!(UILabel);
let decl = ClassDecl::new("RSTTextField", superclass).unwrap();
VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}

/// Injects an `UILabel` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
@@ -38,8 +38,8 @@ pub(crate) fn register_view_class_with_delegate<T: LabelDelegate>() -> *const Cl
// move.
decl.add_ivar::<usize>(LABEL_DELEGATE_PTR);

VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
2 changes: 1 addition & 1 deletion src/uikit/app/class.rs
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ use objc::runtime::Class;
use crate::foundation::load_or_register_class_with_optional_generated_suffix;

/// Used for injecting a custom UIApplication. Currently does nothing.
pub(crate) fn register_app_class() -> *const Class {
pub(crate) fn register_app_class() -> &'static Class {
let should_generate_suffix = false;

load_or_register_class_with_optional_generated_suffix("UIApplication", "RSTApplication", should_generate_suffix, |decl| {})
2 changes: 1 addition & 1 deletion src/uikit/app/delegate.rs
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ extern "C" fn configuration_for_scene_session<T: AppDelegate>(this: &Object, _:

/// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have.
pub(crate) fn register_app_delegate_class<T: AppDelegate>() -> *const Class {
pub(crate) fn register_app_delegate_class<T: AppDelegate>() -> &'static Class {
let should_generate_suffix = false;

load_or_register_class_with_optional_generated_suffix("NSObject", "RSTAppDelegate", should_generate_suffix, |decl| unsafe {
2 changes: 1 addition & 1 deletion src/uikit/scene/delegate.rs
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ extern "C" fn scene_will_connect_to_session_with_options<T: WindowSceneDelegate>

/// Registers an `NSObject` application delegate, and configures it for the various callbacks and
/// pointers we need to have.
pub(crate) fn register_window_scene_delegate_class<T: WindowSceneDelegate, F: Fn() -> Box<T>>() -> *const Class {
pub(crate) fn register_window_scene_delegate_class<T: WindowSceneDelegate, F: Fn() -> Box<T>>() -> &'static Class {
let should_generate_suffix = false;

load_or_register_class_with_optional_generated_suffix("UIResponder", "RSTWindowSceneDelegate", false, |decl| unsafe {
4 changes: 2 additions & 2 deletions src/view/appkit.rs
Original file line number Diff line number Diff line change
@@ -89,7 +89,7 @@ extern "C" fn update_layer(this: &Object, _: Sel) {
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("NSView", "RSTView", |decl| unsafe {
decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);
decl.add_method(sel!(updateLayer), update_layer as extern "C" fn(_, _));
@@ -101,7 +101,7 @@ pub(crate) fn register_view_class() -> *const Class {

/// Injects an `NSView` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSView", instance.subclass_name(), |decl| unsafe {
// A pointer to the ViewDelegate instance on the Rust side.
// It's expected that this doesn't move.
2 changes: 1 addition & 1 deletion src/view/controller/appkit.rs
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ extern "C" fn did_disappear<T: ViewDelegate>(this: &Object, _: Sel) {
}

/// Registers an `NSViewDelegate`.
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>(instance: &T) -> *const Class {
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>(instance: &T) -> &'static Class {
load_or_register_class("NSViewController", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);

2 changes: 1 addition & 1 deletion src/view/controller/uikit.rs
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ extern "C" fn did_disappear<T: ViewDelegate>(this: &Object, _: Sel, animated: BO
}

/// Registers an `NSViewDelegate`.
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>(instance: &T) -> *const Class {
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>(instance: &T) -> &'static Class {
load_or_register_class("UIViewController", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);

2 changes: 1 addition & 1 deletion src/view/splitviewcontroller/ios.rs
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@ extern "C" fn did_disappear<T: ViewDelegate>(this: &mut Object, _: Sel, animated
}

/// Registers an `NSViewDelegate`.
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>() -> *const Class {
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>() -> &'static Class {
load_or_register_class("UIViewController", "RSTViewController", |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);

2 changes: 1 addition & 1 deletion src/view/splitviewcontroller/macos.rs
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ extern "C" fn did_disappear<T: ViewDelegate>(this: &mut Object, _: Sel) {
}

/// Registers an `NSViewDelegate`.
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>(instance: &T) -> *const Class {
pub(crate) fn register_view_controller_class<T: ViewDelegate + 'static>(instance: &T) -> &'static Class {
load_or_register_class("NSViewController", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);

4 changes: 2 additions & 2 deletions src/view/uikit.rs
Original file line number Diff line number Diff line change
@@ -11,13 +11,13 @@ use crate::view::{ViewDelegate, VIEW_DELEGATE_PTR};
/// Injects an `NSView` subclass. This is used for the default views that don't use delegates - we
/// have separate classes here since we don't want to waste cycles on methods that will never be
/// used if there's no delegates.
pub(crate) fn register_view_class() -> *const Class {
pub(crate) fn register_view_class() -> &'static Class {
load_or_register_class("UIView", "RSTView", |decl| unsafe {})
}

/// Injects a `UIView` subclass, with some callback and pointer ivars for what we
/// need to do.
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> *const Class {
pub(crate) fn register_view_class_with_delegate<T: ViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("UIView", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(VIEW_DELEGATE_PTR);
})
4 changes: 2 additions & 2 deletions src/webview/class.rs
Original file line number Diff line number Diff line change
@@ -179,7 +179,7 @@ extern "C" fn accepts_first_mouse(_: &mut Object, _: Sel, _: id) -> BOOL {
/// Registers an `NSViewController` that we effectively turn into a `WebViewController`. Acts as
/// both a subclass of `NSViewController` and a delegate of the held `WKWebView` (for the various
/// varieties of delegates needed there).
pub fn register_webview_class() -> *const Class {
pub fn register_webview_class() -> &'static Class {
load_or_register_class("WKWebView", "CacaoWebView", |decl| unsafe {
decl.add_method(sel!(acceptsFirstMouse:), accepts_first_mouse as extern "C" fn(_, _, _) -> _);
})
@@ -188,7 +188,7 @@ pub fn register_webview_class() -> *const Class {
/// Registers an `NSViewController` that we effectively turn into a `WebViewController`. Acts as
/// both a subclass of `NSViewController` and a delegate of the held `WKWebView` (for the various
/// varieties of delegates needed there).
pub fn register_webview_delegate_class<T: WebViewDelegate>(instance: &T) -> *const Class {
pub fn register_webview_delegate_class<T: WebViewDelegate>(instance: &T) -> &'static Class {
load_or_register_class("NSObject", instance.subclass_name(), |decl| unsafe {
decl.add_ivar::<usize>(WEBVIEW_DELEGATE_PTR);