Skip to content

Commit 82837c1

Browse files
authored
Merge pull request #185 from madsmtm/static-class
Add static classes
2 parents e4a53a7 + c26dcb3 commit 82837c1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1584
-122
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,10 @@ jobs:
206206
- name: Setup SDK environment
207207
if: matrix.sdk
208208
# This changes a variable, so is only set when a custom SDK is used
209-
run: echo "SDKROOT=$HOME/extern/sdk" >> $GITHUB_ENV
209+
run: |
210+
echo "SDKROOT=$HOME/extern/sdk" >> $GITHUB_ENV
211+
# Temporary
212+
echo "RUSTFLAGS=$RUSTFLAGS --cfg=macos_10_7" >> $GITHUB_ENV
210213
211214
- name: Install Clang & Valgrind
212215
if: contains(matrix.os, 'ubuntu')
@@ -395,12 +398,12 @@ jobs:
395398
# Not using --all-features because that would enable e.g. gnustep
396399
args: ${{ env.ARGS }} ${{ env.TESTARGS }} --features ${{ env.FEATURES }},${{ env.UNSTABLE_FEATURES }}
397400

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

405408
- name: Run assembly tests
406409
if: ${{ !contains(matrix.runtime, 'compiler-rt') }}

helper-scripts/test-local.fish

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,5 @@ rm -d .cargo
3434
export SDKROOT=(pwd)/ideas/MacOSX10.13.sdk
3535
export CARGO_BUILD_TARGET=i686-apple-darwin
3636
cargo +nightly test -Zbuild-std
37-
cargo +nightly test -Zbuild-std --features malloc,block,exception,catch-all,verify_message
37+
cargo +nightly test -Zbuild-std --features malloc,block,exception,catch-all,verify_message,unstable-static-class,unstable-static-sel
3838
cargo +nightly test -Zbuild-std --release

objc2-foundation/examples/declaration.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1+
#[cfg(all(feature = "apple", target_os = "macos"))]
12
use objc2::{
23
msg_send, msg_send_id,
34
rc::{Id, Shared},
45
runtime::{Bool, Object},
56
};
7+
#[cfg(all(feature = "apple", target_os = "macos"))]
68
use objc2_foundation::{declare_class, extern_class, NSObject};
79

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

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

19+
#[cfg(all(feature = "apple", target_os = "macos"))]
1620
declare_class! {
1721
unsafe struct CustomAppDelegate: NSResponder, NSObject {
1822
pub ivar: u8,
@@ -66,6 +70,7 @@ declare_class! {
6670
}
6771
}
6872

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

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

8692
println!("{}", delegate.ivar);
8793
println!("{}", delegate.another_ivar.as_bool());
8894
}
95+
96+
#[cfg(not(all(feature = "apple", target_os = "macos")))]
97+
fn main() {
98+
panic!("This example uses AppKit, which is only present on macOS");
99+
}

objc2-foundation/examples/nspasteboard.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::ops::{Deref, DerefMut};
77

88
use objc2::rc::{Id, Shared};
99
use objc2::runtime::{Class, Object};
10-
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
10+
use objc2::{msg_send, msg_send_bool, msg_send_id};
1111
use objc2::{Encoding, Message, RefEncode};
1212

1313
use objc2_foundation::{NSArray, NSDictionary, NSInteger, NSObject, NSString};
@@ -59,7 +59,14 @@ impl DerefMut for NSPasteboard {
5959
impl NSPasteboard {
6060
/// Common convenience method.
6161
pub fn class() -> &'static Class {
62-
class!(NSPasteboard)
62+
#[cfg(all(feature = "apple", target_os = "macos"))]
63+
{
64+
objc2::class!(NSPasteboard)
65+
}
66+
#[cfg(not(all(feature = "apple", target_os = "macos")))]
67+
{
68+
panic!("this example only works on macOS")
69+
}
6370
}
6471

6572
/// We return a `Shared` `Id` because `general` can easily be called

objc2-foundation/examples/nsspeechsynthesizer.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::time::Duration;
88

99
use objc2::rc::{Id, Owned};
1010
use objc2::runtime::Class;
11-
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
11+
use objc2::{msg_send, msg_send_bool, msg_send_id};
1212
use objc2::{Encoding, Message, RefEncode};
1313

1414
use objc2_foundation::{NSObject, NSString};
@@ -47,7 +47,14 @@ impl DerefMut for NSSpeechSynthesizer {
4747
// TODO: Unsure about when to use `&mut` here?
4848
impl NSSpeechSynthesizer {
4949
pub fn class() -> &'static Class {
50-
class!(NSSpeechSynthesizer)
50+
#[cfg(all(feature = "apple", target_os = "macos"))]
51+
{
52+
objc2::class!(NSSpeechSynthesizer)
53+
}
54+
#[cfg(not(all(feature = "apple", target_os = "macos")))]
55+
{
56+
panic!("this example only works on macOS")
57+
}
5158
}
5259

5360
// Uses default voice

objc2-foundation/src/declare_macro.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ macro_rules! declare_class {
515515
use $crate::__std::sync::Once;
516516

517517
use $crate::objc2::declare::ClassBuilder;
518-
use $crate::objc2::runtime::Protocol;
518+
use $crate::objc2::runtime::{Class, Protocol};
519519
static REGISTER_CLASS: Once = Once::new();
520520

521521
REGISTER_CLASS.call_once(|| {
@@ -555,7 +555,8 @@ macro_rules! declare_class {
555555
let _cls = builder.register();
556556
});
557557

558-
$crate::objc2::class!($name)
558+
// We just registered the class, so it should be available
559+
Class::get(stringify!($name)).unwrap()
559560
}
560561
}
561562

objc2-foundation/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub use self::process_info::NSProcessInfo;
6666
pub use self::range::NSRange;
6767
pub use self::string::NSString;
6868
pub use self::thread::{is_main_thread, is_multi_threaded, MainThreadMarker, NSThread};
69+
#[cfg(not(macos_10_7))] // Temporary
6970
pub use self::uuid::NSUUID;
7071
pub use self::value::NSValue;
7172
pub use self::zone::NSZone;
@@ -112,6 +113,8 @@ mod process_info;
112113
mod range;
113114
mod string;
114115
mod thread;
116+
// Temporarily disable testing UUID on macOS 10.7 until
117+
#[cfg(not(macos_10_7))]
115118
mod uuid;
116119
mod value;
117120
mod zone;
@@ -175,6 +178,7 @@ mod tests {
175178
assert_auto_traits::<NSString>();
176179
assert_unwindsafe::<MainThreadMarker>(); // Intentional
177180
assert_auto_traits::<NSThread>();
181+
#[cfg(not(macos_10_7))]
178182
assert_auto_traits::<NSUUID>();
179183
assert_auto_traits::<NSValue<i32>>();
180184
assert_unwindsafe::<NSZone>(); // Intentional

objc2-foundation/src/uuid.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ extern_class! {
1515
/// Conversion methods to/from UUIDs from the `uuid` crate can be
1616
/// enabled with the `uuid` crate feature.
1717
///
18+
/// macOS: This is only available on 10.8 and above.
19+
///
1820
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsuuid?language=objc).
1921
#[derive(PartialEq, Eq, Hash)]
2022
unsafe pub struct NSUUID: NSObject;

objc2/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## Unreleased - YYYY-MM-DD
88

9+
### Added
10+
* Added the `"unstable-static-class"` and `"unstable-static-class-inlined"`
11+
feature flags to make the `class!` macro zero cost.
12+
913

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

objc2/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ malloc = ["malloc_buf"]
5151
# https://github.com/madsmtm/objc2/issues/new
5252
unstable-static-sel = ["objc2-proc-macros"]
5353
unstable-static-sel-inlined = ["unstable-static-sel"]
54+
unstable-static-class = ["objc2-proc-macros"]
55+
unstable-static-class-inlined = ["unstable-static-class"]
5456

5557
# Uses nightly features to make AutoreleasePool zero-cost even in debug mode
5658
unstable-autoreleasesafe = []

objc2/examples/introspection.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ use objc2::{class, msg_send, msg_send_id};
44
#[cfg(feature = "malloc")]
55
use objc2::{sel, Encode};
66

7+
#[cfg(feature = "apple")]
8+
#[link(name = "Foundation", kind = "framework")]
9+
extern "C" {}
10+
711
fn main() {
812
// Get a class
913
let cls = class!(NSObject);

objc2/examples/talk_to_me.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,29 @@
33
//! **Untested**!
44
//!
55
//! Works on macOS >= 10.15 or iOS > 7.0!
6-
use objc2::ffi::NSUInteger;
7-
use objc2::rc::{Id, Owned, Shared};
8-
use objc2::runtime::Object;
9-
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
10-
use std::ffi::c_void;
116
12-
#[cfg(feature = "apple")]
13-
#[link(name = "AVFoundation", kind = "framework")]
14-
extern "C" {}
15-
16-
const UTF8_ENCODING: NSUInteger = 4;
7+
#[cfg(not(talk_to_me_example))]
8+
fn main() {
9+
panic!("pass the `--cfg talk_to_me_example` flag to run this example!");
10+
}
1711

12+
#[cfg(talk_to_me_example)]
1813
fn main() {
14+
use objc2::ffi::NSUInteger;
15+
use objc2::rc::{Id, Owned, Shared};
16+
use objc2::runtime::Object;
17+
use objc2::{class, msg_send, msg_send_bool, msg_send_id};
18+
use std::ffi::c_void;
19+
20+
#[cfg(feature = "apple")]
21+
#[link(name = "AVFoundation", kind = "framework")]
22+
extern "C" {}
23+
#[cfg(feature = "apple")]
24+
#[link(name = "Foundation", kind = "framework")]
25+
extern "C" {}
26+
27+
const UTF8_ENCODING: NSUInteger = 4;
28+
1929
let text = "Hello from Rust!";
2030

2131
// Note: objc2-foundation has functionality to do this safely!

objc2/src/__macro_helpers.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,35 @@ pub const fn in_selector_family(mut selector: &[u8], mut family: &[u8]) -> bool
211211
}
212212
}
213213

214+
/// Helper struct for emitting the module info that macOS 32-bit requires.
215+
///
216+
/// <https://github.com/llvm/llvm-project/blob/release/13.x/clang/lib/CodeGen/CGObjCMac.cpp#L5211-L5234>
217+
#[repr(C)]
218+
pub struct ModuleInfo {
219+
version: usize,
220+
size: usize,
221+
name: *const u8,
222+
symtab: *const (),
223+
}
224+
225+
// SAFETY: ModuleInfo is immutable.
226+
unsafe impl Sync for ModuleInfo {}
227+
228+
impl ModuleInfo {
229+
/// This is hardcoded in clang as 7.
230+
const VERSION: usize = 7;
231+
232+
pub const fn new(name: *const u8) -> Self {
233+
Self {
234+
version: Self::VERSION,
235+
size: core::mem::size_of::<Self>(),
236+
name,
237+
// We don't expose any symbols
238+
symtab: core::ptr::null(),
239+
}
240+
}
241+
}
242+
214243
#[cfg(test)]
215244
mod tests {
216245
use super::*;
@@ -441,4 +470,13 @@ mod tests {
441470
// to be different!
442471
assert_eq!(ident1, ident2);
443472
}
473+
474+
#[test]
475+
#[cfg_attr(
476+
not(all(feature = "apple", target_os = "macos", target_arch = "x86")),
477+
ignore = "Only relevant on macOS 32-bit"
478+
)]
479+
fn ensure_size_of_module_info() {
480+
assert_eq!(core::mem::size_of::<ModuleInfo>(), 16);
481+
}
444482
}

objc2/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ mod test_utils;
218218
#[cfg(feature = "malloc")]
219219
mod verify;
220220

221+
// Hack to make doctests work
222+
#[cfg(all(feature = "apple", feature = "unstable-static-class"))]
223+
#[link(name = "Foundation", kind = "framework")]
224+
extern "C" {}
225+
221226
/// Hacky way to make GNUStep link properly to Foundation while testing.
222227
///
223228
/// This is a temporary solution to make our CI work for now!

0 commit comments

Comments
 (0)