Skip to content

Commit

Permalink
Use &'static Class instead of *const Class
Browse files Browse the repository at this point in the history
Safer and more ergonomic. Also required for `msg_send_id!` macro
  • Loading branch information
madsmtm committed Aug 28, 2022
1 parent 9a34553 commit baf792f
Show file tree
Hide file tree
Showing 37 changed files with 140 additions and 142 deletions.
10 changes: 5 additions & 5 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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() }
}
```

Expand All @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions src/appkit/app/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use objc::declare::ClassDecl;
use objc::runtime::Class;

/// Used for injecting a custom NSApplication. Currently does nothing.
pub(crate) fn register_app_class() -> *const Class {
static mut APP_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_app_class() -> &'static Class {
static mut APP_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

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

unsafe { APP_CLASS }
unsafe { APP_CLASS.unwrap() }
}
8 changes: 4 additions & 4 deletions src/appkit/app/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ 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 {
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> &'static Class {
static mut DELEGATE_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand Down Expand Up @@ -453,8 +453,8 @@ pub(crate) fn register_app_delegate_class<T: AppDelegate + AppDelegate>() -> *co
delegate_handles_key::<T> as extern "C" fn(_, _, _, _) -> _
);

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

unsafe { DELEGATE_CLASS }
unsafe { DELEGATE_CLASS.unwrap() }
}
8 changes: 4 additions & 4 deletions src/appkit/menu/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ 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 {
static mut APP_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_menu_item_class() -> &'static Class {
static mut APP_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand All @@ -325,8 +325,8 @@ pub(crate) fn register_menu_item_class() -> *const Class {
decl.add_method(sel!(dealloc), dealloc_cacao_menuitem as extern "C" fn(_, _));
decl.add_method(sel!(fireBlockAction:), fire_block_action as extern "C" fn(_, _, _));

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

unsafe { APP_CLASS }
unsafe { APP_CLASS.unwrap() }
}
2 changes: 1 addition & 1 deletion src/appkit/toolbar/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/appkit/window/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 4 additions & 4 deletions src/appkit/window/controller/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ use crate::appkit::window::{WindowDelegate, WINDOW_DELEGATE_PTR};

/// 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 {
static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_window_controller_class<T: WindowDelegate>() -> &'static Class {
static mut DELEGATE_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
let superclass = class!(NSWindowController);
let mut decl = ClassDecl::new("RSTWindowController", superclass).unwrap();
decl.add_ivar::<usize>(WINDOW_DELEGATE_PTR);
DELEGATE_CLASS = decl.register();
DELEGATE_CLASS = Some(decl.register());
});

unsafe { DELEGATE_CLASS }
unsafe { DELEGATE_CLASS.unwrap() }
}
8 changes: 4 additions & 4 deletions src/button/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,15 +342,15 @@ 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 {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
fn register_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

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

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
8 changes: 4 additions & 4 deletions src/color/appkit_dynamic_color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,8 @@ 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 {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand Down Expand Up @@ -333,8 +333,8 @@ pub(crate) fn register_class() -> *const Class {
decl.add_ivar::<id>(AQUA_DARK_COLOR_NORMAL_CONTRAST);
decl.add_ivar::<id>(AQUA_DARK_COLOR_HIGH_CONTRAST);

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

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
8 changes: 4 additions & 4 deletions src/foundation/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ impl ClassMap {
}

/// Attempts to load a previously registered subclass.
pub fn load_subclass(&self, subclass_name: &'static str, superclass_name: &'static str) -> Option<*const Class> {
pub fn load_subclass(&self, subclass_name: &'static str, superclass_name: &'static str) -> Option<&'static Class> {
let reader = self.0.read().unwrap();

if let Some(inner) = (*reader).get(subclass_name) {
if let Some(class) = inner.get(superclass_name) {
return Some(*class as *const Class);
return Some(unsafe { (*class as *const Class).as_ref() }.unwrap());
}
}

Expand Down Expand Up @@ -103,7 +103,7 @@ impl ClassMap {
}
}

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

Expand All @@ -121,7 +121,7 @@ impl ClassMap {
///
/// There's definitely room to optimize here, but it works for now.
#[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
{
Expand Down
8 changes: 4 additions & 4 deletions src/image/appkit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ 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_image_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_image_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand All @@ -32,8 +32,8 @@ pub(crate) fn register_image_view_class() -> *const Class {

//decl.add_method(sel!(isFlipped), enforce_normalcy as extern "C" fn(_, _) -> _);

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

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
2 changes: 1 addition & 1 deletion src/image/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,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];

Expand Down
8 changes: 4 additions & 4 deletions src/image/uikit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ 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_image_view_class() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_image_view_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
let superclass = class!(UIImageView);
let mut decl = ClassDecl::new("RSTImageView", superclass).expect("Failed to get RSTVIEW");
VIEW_CLASS = decl.register();
VIEW_CLASS = Some(decl.register());
});

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
10 changes: 5 additions & 5 deletions src/input/appkit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,22 @@ extern "C" fn text_should_end_editing<T: TextFieldDelegate>(this: &mut Object, _
/// 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 {
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!(NSTextField);
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 `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.
Expand Down
2 changes: 1 addition & 1 deletion src/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down
8 changes: 4 additions & 4 deletions src/invoker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ extern "C" fn perform<F: Fn() + 'static>(this: &mut Object, _: Sel, _sender: id)
/// 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() + 'static>() -> *const Class {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_invoker_class<F: Fn() + 'static>() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

INIT.call_once(|| unsafe {
Expand All @@ -105,8 +105,8 @@ pub(crate) fn register_invoker_class<F: Fn() + 'static>() -> *const Class {
decl.add_ivar::<usize>(ACTION_CALLBACK_PTR);
decl.add_method(sel!(perform:), perform::<F> as extern "C" fn(_, _, _));

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

unsafe { VIEW_CLASS }
unsafe { VIEW_CLASS.unwrap() }
}
10 changes: 5 additions & 5 deletions src/listview/appkit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,24 +184,24 @@ 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 {
static mut VIEW_CLASS: *const Class = 0 as *const Class;
pub(crate) fn register_listview_class() -> &'static Class {
static mut VIEW_CLASS: Option<&'static Class> = None;
static INIT: Once = Once::new();

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

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

/// 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);

Expand Down
2 changes: 1 addition & 1 deletion src/listview/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit baf792f

Please sign in to comment.