1
1
/// Gets a reference to a [`Class`] from the given name.
2
2
///
3
+ /// [`Class`]: crate::runtime::Class
4
+ ///
5
+ ///
3
6
/// # Panics
4
7
///
5
8
/// Panics if no class with the given name can be found.
6
9
///
7
10
/// To check for a class that may not exist, use [`Class::get`].
8
11
///
9
- /// [`Class`]: crate::runtime::Class
10
12
/// [`Class::get`]: crate::runtime::Class::get
11
13
///
14
+ ///
15
+ /// # Features
16
+ ///
17
+ /// If the experimental `"unstable-static-class"` feature is enabled, this
18
+ /// will emit special statics that will be replaced by dyld when the program
19
+ /// starts up.
20
+ ///
21
+ /// Errors that were previously runtime panics may now turn into linker errors
22
+ /// if you try to use a class which is not available. Additionally, you may
23
+ /// have to call `msg_send![cls, class]` on the result if you want to use it
24
+ /// in a dynamic context (e.g. dynamically declaring classes).
25
+ ///
26
+ /// See the [corresponding section][sel#features] in the [`sel!`] macro for
27
+ /// more details on the limitations of this. The
28
+ /// `"unstable-static-class-inlined"` corresponds to the
29
+ /// `"unstable-static-sel-inlined"` feature here.
30
+ ///
31
+ /// [sel#features]: crate::sel#features
32
+ ///
12
33
/// # Examples
13
34
///
14
35
/// ```no_run
17
38
/// ```
18
39
#[ macro_export]
19
40
macro_rules! class {
41
+ ( $name: ident) => { {
42
+ $crate:: __class_inner!( $name)
43
+ } } ;
44
+ }
45
+
46
+ #[ doc( hidden) ]
47
+ #[ macro_export]
48
+ #[ cfg( not( feature = "unstable-static-class" ) ) ]
49
+ macro_rules! __class_inner {
20
50
( $name: ident) => { {
21
51
use $crate:: __macro_helpers:: { concat, panic, stringify, CachedClass , None , Some } ;
22
52
static CACHED_CLASS : CachedClass = CachedClass :: new( ) ;
@@ -177,18 +207,12 @@ macro_rules! __sel_inner {
177
207
178
208
#[ doc( hidden) ]
179
209
#[ macro_export]
180
- macro_rules! __sel_inner_statics_apple_generic {
210
+ macro_rules! __inner_statics_apple_generic {
181
211
{
212
+ @image_info;
182
213
$image_info_section: literal;
183
- $var_name_section: literal;
184
- $selector_ref_section: literal;
185
- $data: expr,
186
214
$( $idents: ident) +
187
215
} => {
188
- use $crate:: __macro_helpers:: { u8 , UnsafeCell } ;
189
- use $crate:: ffi:: __ImageInfo;
190
- use $crate:: runtime:: Sel ;
191
-
192
216
/// We always emit the image info tag, since we need it to:
193
217
/// - End up in the same codegen unit as the other statics below.
194
218
/// - End up in the final binary so it can be read by dyld.
@@ -202,7 +226,17 @@ macro_rules! __sel_inner_statics_apple_generic {
202
226
$crate:: __macro_helpers:: __hash_idents!( $( $idents) +) ,
203
227
) ]
204
228
#[ used] // Make sure this reaches the linker
205
- static _IMAGE_INFO: __ImageInfo = __ImageInfo:: system( ) ;
229
+ static _IMAGE_INFO: $crate:: ffi:: __ImageInfo = $crate:: ffi:: __ImageInfo:: system( ) ;
230
+ } ;
231
+ {
232
+ @sel;
233
+ $var_name_section: literal;
234
+ $selector_ref_section: literal;
235
+ $data: expr,
236
+ $( $idents: ident) +
237
+ } => {
238
+ use $crate:: __macro_helpers:: { u8 , UnsafeCell } ;
239
+ use $crate:: runtime:: Sel ;
206
240
207
241
const X : & [ u8 ] = $data. as_bytes( ) ;
208
242
@@ -262,47 +296,128 @@ macro_rules! __sel_inner_statics_apple_generic {
262
296
UnsafeCell :: new( Sel :: __internal_from_ptr( NAME_DATA . as_ptr( ) . cast( ) ) )
263
297
} ;
264
298
} ;
299
+ {
300
+ @class;
301
+ $class_ref_section: literal;
302
+ $name: ident
303
+ } => {
304
+ use $crate:: __macro_helpers:: UnsafeCell ;
305
+ use $crate:: runtime:: Class ;
306
+
307
+ extern "C" {
308
+ /// Link to the Objective-C class static.
309
+ ///
310
+ /// This uses the special symbol that static and dynamic linkers
311
+ /// knows about.
312
+ ///
313
+ /// Failure modes:
314
+ /// - Unknown class: Static linker error.
315
+ /// - OS version < Class introduced version: Dynamic linker error
316
+ /// on program startup.
317
+ /// - Deployment target > Class introduced version: No error,
318
+ /// though _should_ be a static linker error.
319
+ ///
320
+ /// Ideally, we'd have some way of allowing this to be weakly
321
+ /// linked, and return `Option<&Class>` in that case, but Rust
322
+ /// doesn't have the capability to do so yet!
323
+ /// <https://github.com/rust-lang/rust/issues/29603>
324
+ /// <https://stackoverflow.com/a/16936512>
325
+ /// <http://sealiesoftware.com/blog/archive/2010/4/8/Do-it-yourself_Objective-C_weak_import.html>
326
+ #[ link_name = $crate:: __macro_helpers:: concat!(
327
+ "OBJC_CLASS_$_" ,
328
+ $crate:: __macro_helpers:: stringify!( $name) ,
329
+ ) ]
330
+ static CLASS : Class ;
331
+ }
332
+
333
+ /// SAFETY: Same as `REF` above.
334
+ #[ link_section = $class_ref_section]
335
+ #[ export_name = $crate:: __macro_helpers:: concat!(
336
+ "\x01 L_OBJC_CLASSLIST_REFERENCES_$_" ,
337
+ $crate:: __macro_helpers:: __hash_idents!( $name) ,
338
+ ) ]
339
+ static mut REF : UnsafeCell <& Class > = unsafe {
340
+ UnsafeCell :: new( & CLASS )
341
+ } ;
342
+ } ;
265
343
}
266
344
345
+ // These sections are found by reading clang/LLVM sources
267
346
#[ doc( hidden) ]
268
347
#[ macro_export]
269
348
#[ cfg( all( feature = "apple" , not( all( target_os = "macos" , target_arch = "x86" ) ) ) ) ]
270
- macro_rules! __sel_inner_statics {
271
- ( $( $args: tt) * ) => {
272
- // Found by reading clang/LLVM sources
273
- $crate :: __sel_inner_statics_apple_generic! {
349
+ macro_rules! __inner_statics {
350
+ ( @image_info $( $args: tt) * ) => {
351
+ $crate :: __inner_statics_apple_generic! {
352
+ @image_info ;
274
353
"__DATA,__objc_imageinfo,regular,no_dead_strip" ;
354
+ $( $args) *
355
+ }
356
+ } ;
357
+ ( @sel $( $args: tt) * ) => {
358
+ $crate:: __inner_statics_apple_generic! {
359
+ @sel;
275
360
"__TEXT,__objc_methname,cstring_literals" ;
276
361
"__DATA,__objc_selrefs,literal_pointers,no_dead_strip" ;
277
362
$( $args) *
278
363
}
279
364
} ;
365
+ ( @class $( $args: tt) * ) => {
366
+ $crate:: __inner_statics_apple_generic! {
367
+ @class;
368
+ "__DATA,__objc_classrefs,regular,no_dead_strip" ;
369
+ $( $args) *
370
+ }
371
+ } ;
280
372
}
281
373
282
374
#[ doc( hidden) ]
283
375
#[ macro_export]
284
376
#[ cfg( all( feature = "apple" , target_os = "macos" , target_arch = "x86" ) ) ]
285
- macro_rules! __sel_inner_statics {
286
- ( $( $args: tt) * ) => {
287
- $crate:: __sel_inner_statics_apple_generic! {
377
+ macro_rules! __inner_statics {
378
+ ( @image_info $( $args: tt) * ) => {
379
+ $crate:: __inner_statics_apple_generic! {
380
+ @image_info;
288
381
"__OBJC,__image_info,regular" ;
382
+ $( $args) *
383
+ }
384
+ } ;
385
+ ( @sel $( $args: tt) * ) => {
386
+ $crate:: __inner_statics_apple_generic! {
387
+ @sel;
289
388
"__TEXT,__cstring,cstring_literals" ;
290
389
"__OBJC,__message_refs,literal_pointers,no_dead_strip" ;
291
390
$( $args) *
292
391
}
293
392
} ;
393
+ ( @class $( $args: tt) * ) => {
394
+ // TODO
395
+ $crate:: __macro_helpers:: compile_error!(
396
+ "The `\" unstable-static-class\" ` feature is not yet supported on 32bit macOS!"
397
+ )
398
+ // TODO: module info
399
+ } ;
294
400
}
295
401
296
402
#[ doc( hidden) ]
297
403
#[ macro_export]
298
404
#[ cfg( not( feature = "apple" ) ) ]
299
- macro_rules! __sel_inner_statics {
300
- ( $( $args: tt) * ) => {
405
+ macro_rules! __inner_statics {
406
+ ( @image_info $( $args: tt) * ) => {
407
+ // TODO
408
+ } ;
409
+ ( @sel $( $args: tt) * ) => {
301
410
// TODO
302
411
$crate:: __macro_helpers:: compile_error!(
303
412
"The `\" unstable-static-sel\" ` feature is not yet supported on GNUStep!"
304
413
)
305
414
} ;
415
+ ( @class $( $args: tt) * ) => {
416
+ // TODO
417
+ $crate:: __macro_helpers:: compile_error!(
418
+ "The `\" unstable-static-class\" ` feature is not yet supported on GNUStep!"
419
+ )
420
+ } ;
306
421
}
307
422
308
423
#[ doc( hidden) ]
@@ -312,8 +427,9 @@ macro_rules! __sel_inner_statics {
312
427
not( feature = "unstable-static-sel-inlined" )
313
428
) ) ]
314
429
macro_rules! __sel_inner {
315
- ( $( $args: tt) * ) => { {
316
- $crate:: __sel_inner_statics!( $( $args) * ) ;
430
+ ( $data: expr, $( $idents: ident) +) => { {
431
+ $crate:: __inner_statics!( @image_info $( $idents) +) ;
432
+ $crate:: __inner_statics!( @sel $data, $( $idents) +) ;
317
433
318
434
/// HACK: Wrap the access in a non-generic, `#[inline(never)]`
319
435
/// function to make the compiler group it into the same codegen unit
@@ -340,8 +456,44 @@ macro_rules! __sel_inner {
340
456
#[ macro_export]
341
457
#[ cfg( all( feature = "unstable-static-sel-inlined" ) ) ]
342
458
macro_rules! __sel_inner {
343
- ( $( $args: tt) * ) => { {
344
- $crate:: __sel_inner_statics!( $( $args) * ) ;
459
+ ( $data: expr, $( $idents: ident) +) => { {
460
+ $crate:: __inner_statics!( @image_info $( $idents) +) ;
461
+ $crate:: __inner_statics!( @sel $data, $( $idents) +) ;
462
+
463
+ #[ allow( unused_unsafe) ]
464
+ // SAFETY: See above
465
+ unsafe { * REF . get( ) }
466
+ } } ;
467
+ }
468
+
469
+ #[ doc( hidden) ]
470
+ #[ macro_export]
471
+ #[ cfg( all(
472
+ feature = "unstable-static-class" ,
473
+ not( feature = "unstable-static-class-inlined" )
474
+ ) ) ]
475
+ macro_rules! __class_inner {
476
+ ( $name: ident) => { {
477
+ $crate:: __inner_statics!( @image_info $name) ;
478
+ $crate:: __inner_statics!( @class $name) ;
479
+
480
+ #[ inline( never) ]
481
+ fn objc_static_workaround( ) -> & ' static Class {
482
+ // SAFETY: Same as __sel_inner
483
+ unsafe { * REF . get( ) }
484
+ }
485
+
486
+ objc_static_workaround( )
487
+ } } ;
488
+ }
489
+
490
+ #[ doc( hidden) ]
491
+ #[ macro_export]
492
+ #[ cfg( all( feature = "unstable-static-class-inlined" ) ) ]
493
+ macro_rules! __class_inner {
494
+ ( $name: ident) => { {
495
+ $crate:: __inner_statics!( @image_info $name) ;
496
+ $crate:: __inner_statics!( @class $name) ;
345
497
346
498
#[ allow( unused_unsafe) ]
347
499
// SAFETY: See above
0 commit comments