Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
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