Skip to content

Commit

Permalink
Merge pull request #185 from madsmtm/static-class
Browse files Browse the repository at this point in the history
Add static classes
  • Loading branch information
madsmtm authored Jul 27, 2022
2 parents e4a53a7 + c26dcb3 commit 82837c1
Show file tree
Hide file tree
Showing 42 changed files with 1,584 additions and 122 deletions.
9 changes: 6 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,10 @@ jobs:
- name: Setup SDK environment
if: matrix.sdk
# This changes a variable, so is only set when a custom SDK is used
run: echo "SDKROOT=$HOME/extern/sdk" >> $GITHUB_ENV
run: |
echo "SDKROOT=$HOME/extern/sdk" >> $GITHUB_ENV
# Temporary
echo "RUSTFLAGS=$RUSTFLAGS --cfg=macos_10_7" >> $GITHUB_ENV
- name: Install Clang & Valgrind
if: contains(matrix.os, 'ubuntu')
Expand Down Expand Up @@ -395,12 +398,12 @@ jobs:
# Not using --all-features because that would enable e.g. gnustep
args: ${{ env.ARGS }} ${{ env.TESTARGS }} --features ${{ env.FEATURES }},${{ env.UNSTABLE_FEATURES }}

- name: Test static selectors
- name: Test static class and selectors
if: ${{ !matrix.dinghy && (matrix.runtime || 'apple') == 'apple' }}
uses: actions-rs/cargo@v1
with:
command: test
args: ${{ env.ARGS }} ${{ env.TESTARGS }} --features unstable-static-sel
args: ${{ env.ARGS }} ${{ env.TESTARGS }} --features unstable-static-sel,unstable-static-class

- name: Run assembly tests
if: ${{ !contains(matrix.runtime, 'compiler-rt') }}
Expand Down
2 changes: 1 addition & 1 deletion helper-scripts/test-local.fish
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ rm -d .cargo
export SDKROOT=(pwd)/ideas/MacOSX10.13.sdk
export CARGO_BUILD_TARGET=i686-apple-darwin
cargo +nightly test -Zbuild-std
cargo +nightly test -Zbuild-std --features malloc,block,exception,catch-all,verify_message
cargo +nightly test -Zbuild-std --features malloc,block,exception,catch-all,verify_message,unstable-static-class,unstable-static-sel
cargo +nightly test -Zbuild-std --release
11 changes: 11 additions & 0 deletions objc2-foundation/examples/declaration.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
#[cfg(all(feature = "apple", target_os = "macos"))]
use objc2::{
msg_send, msg_send_id,
rc::{Id, Shared},
runtime::{Bool, Object},
};
#[cfg(all(feature = "apple", target_os = "macos"))]
use objc2_foundation::{declare_class, extern_class, NSObject};

#[cfg(all(feature = "apple", target_os = "macos"))]
#[link(name = "AppKit", kind = "framework")]
extern "C" {}

#[cfg(all(feature = "apple", target_os = "macos"))]
extern_class! {
unsafe struct NSResponder: NSObject;
}

#[cfg(all(feature = "apple", target_os = "macos"))]
declare_class! {
unsafe struct CustomAppDelegate: NSResponder, NSObject {
pub ivar: u8,
Expand Down Expand Up @@ -66,6 +70,7 @@ declare_class! {
}
}

#[cfg(all(feature = "apple", target_os = "macos"))]
impl CustomAppDelegate {
pub fn new(ivar: u8, another_ivar: bool) -> Id<Self, Shared> {
let cls = Self::class();
Expand All @@ -80,9 +85,15 @@ impl CustomAppDelegate {
}
}

#[cfg(all(feature = "apple", target_os = "macos"))]
fn main() {
let delegate = CustomAppDelegate::new(42, true);

println!("{}", delegate.ivar);
println!("{}", delegate.another_ivar.as_bool());
}

#[cfg(not(all(feature = "apple", target_os = "macos")))]
fn main() {
panic!("This example uses AppKit, which is only present on macOS");
}
11 changes: 9 additions & 2 deletions objc2-foundation/examples/nspasteboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::ops::{Deref, DerefMut};

use objc2::rc::{Id, Shared};
use objc2::runtime::{Class, Object};
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
use objc2::{msg_send, msg_send_bool, msg_send_id};
use objc2::{Encoding, Message, RefEncode};

use objc2_foundation::{NSArray, NSDictionary, NSInteger, NSObject, NSString};
Expand Down Expand Up @@ -59,7 +59,14 @@ impl DerefMut for NSPasteboard {
impl NSPasteboard {
/// Common convenience method.
pub fn class() -> &'static Class {
class!(NSPasteboard)
#[cfg(all(feature = "apple", target_os = "macos"))]
{
objc2::class!(NSPasteboard)
}
#[cfg(not(all(feature = "apple", target_os = "macos")))]
{
panic!("this example only works on macOS")
}
}

/// We return a `Shared` `Id` because `general` can easily be called
Expand Down
11 changes: 9 additions & 2 deletions objc2-foundation/examples/nsspeechsynthesizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::time::Duration;

use objc2::rc::{Id, Owned};
use objc2::runtime::Class;
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
use objc2::{msg_send, msg_send_bool, msg_send_id};
use objc2::{Encoding, Message, RefEncode};

use objc2_foundation::{NSObject, NSString};
Expand Down Expand Up @@ -47,7 +47,14 @@ impl DerefMut for NSSpeechSynthesizer {
// TODO: Unsure about when to use `&mut` here?
impl NSSpeechSynthesizer {
pub fn class() -> &'static Class {
class!(NSSpeechSynthesizer)
#[cfg(all(feature = "apple", target_os = "macos"))]
{
objc2::class!(NSSpeechSynthesizer)
}
#[cfg(not(all(feature = "apple", target_os = "macos")))]
{
panic!("this example only works on macOS")
}
}

// Uses default voice
Expand Down
5 changes: 3 additions & 2 deletions objc2-foundation/src/declare_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ macro_rules! declare_class {
use $crate::__std::sync::Once;

use $crate::objc2::declare::ClassBuilder;
use $crate::objc2::runtime::Protocol;
use $crate::objc2::runtime::{Class, Protocol};
static REGISTER_CLASS: Once = Once::new();

REGISTER_CLASS.call_once(|| {
Expand Down Expand Up @@ -555,7 +555,8 @@ macro_rules! declare_class {
let _cls = builder.register();
});

$crate::objc2::class!($name)
// We just registered the class, so it should be available
Class::get(stringify!($name)).unwrap()
}
}

Expand Down
4 changes: 4 additions & 0 deletions objc2-foundation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub use self::process_info::NSProcessInfo;
pub use self::range::NSRange;
pub use self::string::NSString;
pub use self::thread::{is_main_thread, is_multi_threaded, MainThreadMarker, NSThread};
#[cfg(not(macos_10_7))] // Temporary
pub use self::uuid::NSUUID;
pub use self::value::NSValue;
pub use self::zone::NSZone;
Expand Down Expand Up @@ -112,6 +113,8 @@ mod process_info;
mod range;
mod string;
mod thread;
// Temporarily disable testing UUID on macOS 10.7 until
#[cfg(not(macos_10_7))]
mod uuid;
mod value;
mod zone;
Expand Down Expand Up @@ -175,6 +178,7 @@ mod tests {
assert_auto_traits::<NSString>();
assert_unwindsafe::<MainThreadMarker>(); // Intentional
assert_auto_traits::<NSThread>();
#[cfg(not(macos_10_7))]
assert_auto_traits::<NSUUID>();
assert_auto_traits::<NSValue<i32>>();
assert_unwindsafe::<NSZone>(); // Intentional
Expand Down
2 changes: 2 additions & 0 deletions objc2-foundation/src/uuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ extern_class! {
/// Conversion methods to/from UUIDs from the `uuid` crate can be
/// enabled with the `uuid` crate feature.
///
/// macOS: This is only available on 10.8 and above.
///
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsuuid?language=objc).
#[derive(PartialEq, Eq, Hash)]
unsafe pub struct NSUUID: NSObject;
Expand Down
4 changes: 4 additions & 0 deletions objc2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## Unreleased - YYYY-MM-DD

### Added
* Added the `"unstable-static-class"` and `"unstable-static-class-inlined"`
feature flags to make the `class!` macro zero cost.


## 0.3.0-beta.1 - 2022-07-19

Expand Down
2 changes: 2 additions & 0 deletions objc2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ malloc = ["malloc_buf"]
# https://github.com/madsmtm/objc2/issues/new
unstable-static-sel = ["objc2-proc-macros"]
unstable-static-sel-inlined = ["unstable-static-sel"]
unstable-static-class = ["objc2-proc-macros"]
unstable-static-class-inlined = ["unstable-static-class"]

# Uses nightly features to make AutoreleasePool zero-cost even in debug mode
unstable-autoreleasesafe = []
Expand Down
4 changes: 4 additions & 0 deletions objc2/examples/introspection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ use objc2::{class, msg_send, msg_send_id};
#[cfg(feature = "malloc")]
use objc2::{sel, Encode};

#[cfg(feature = "apple")]
#[link(name = "Foundation", kind = "framework")]
extern "C" {}

fn main() {
// Get a class
let cls = class!(NSObject);
Expand Down
30 changes: 20 additions & 10 deletions objc2/examples/talk_to_me.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,29 @@
//! **Untested**!
//!
//! Works on macOS >= 10.15 or iOS > 7.0!
use objc2::ffi::NSUInteger;
use objc2::rc::{Id, Owned, Shared};
use objc2::runtime::Object;
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
use std::ffi::c_void;

#[cfg(feature = "apple")]
#[link(name = "AVFoundation", kind = "framework")]
extern "C" {}

const UTF8_ENCODING: NSUInteger = 4;
#[cfg(not(talk_to_me_example))]
fn main() {
panic!("pass the `--cfg talk_to_me_example` flag to run this example!");
}

#[cfg(talk_to_me_example)]
fn main() {
use objc2::ffi::NSUInteger;
use objc2::rc::{Id, Owned, Shared};
use objc2::runtime::Object;
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
use std::ffi::c_void;

#[cfg(feature = "apple")]
#[link(name = "AVFoundation", kind = "framework")]
extern "C" {}
#[cfg(feature = "apple")]
#[link(name = "Foundation", kind = "framework")]
extern "C" {}

const UTF8_ENCODING: NSUInteger = 4;

let text = "Hello from Rust!";

// Note: objc2-foundation has functionality to do this safely!
Expand Down
38 changes: 38 additions & 0 deletions objc2/src/__macro_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,35 @@ pub const fn in_selector_family(mut selector: &[u8], mut family: &[u8]) -> bool
}
}

/// Helper struct for emitting the module info that macOS 32-bit requires.
///
/// <https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/CodeGen/CGObjCMac.cpp#L5211-L5234>
#[repr(C)]
pub struct ModuleInfo {
version: usize,
size: usize,
name: *const u8,
symtab: *const (),
}

// SAFETY: ModuleInfo is immutable.
unsafe impl Sync for ModuleInfo {}

impl ModuleInfo {
/// This is hardcoded in clang as 7.
const VERSION: usize = 7;

pub const fn new(name: *const u8) -> Self {
Self {
version: Self::VERSION,
size: core::mem::size_of::<Self>(),
name,
// We don't expose any symbols
symtab: core::ptr::null(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -441,4 +470,13 @@ mod tests {
// to be different!
assert_eq!(ident1, ident2);
}

#[test]
#[cfg_attr(
not(all(feature = "apple", target_os = "macos", target_arch = "x86")),
ignore = "Only relevant on macOS 32-bit"
)]
fn ensure_size_of_module_info() {
assert_eq!(core::mem::size_of::<ModuleInfo>(), 16);
}
}
5 changes: 5 additions & 0 deletions objc2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ mod test_utils;
#[cfg(feature = "malloc")]
mod verify;

// Hack to make doctests work
#[cfg(all(feature = "apple", feature = "unstable-static-class"))]
#[link(name = "Foundation", kind = "framework")]
extern "C" {}

/// Hacky way to make GNUStep link properly to Foundation while testing.
///
/// This is a temporary solution to make our CI work for now!
Expand Down
Loading

0 comments on commit 82837c1

Please sign in to comment.