Skip to content

Commit b8c24dc

Browse files
committed
Change extern_class! syntax
Instead of specifying `impl ClassType for ...`, we instead parse the custom attributes `#[unsafe(super(...))]`, `#[thread_kind = ...]` and `#[name = ...]`. This is nice because: - It's more concise. - It more closely matches what we might end up with once it can become and attribute macro: rust-lang/rfcs#3697 - We need to parse the attributes anyhow to override derives: #267 (The extern_class! part of that issue is now resolved). - It makes it easier to change ClassType in the future without having to change the macro API as well. Additionally, this commit also adds incomplete support for generics, to avoid the framework crates depending on an internal macro, and it improves rust-analyzer support in extern_class! by having more relaxed parsing.
1 parent ae9e1f5 commit b8c24dc

File tree

69 files changed

+1396
-744
lines changed

Some content is hidden

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

69 files changed

+1396
-744
lines changed

crates/block2/src/lib.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,9 @@
6565
//! #
6666
//! # use objc2::ClassType;
6767
//! # objc2::extern_class!(
68+
//! # #[unsafe(super(objc2::runtime::NSObject))]
69+
//! # #[name = "NSObject"]
6870
//! # struct MyClass;
69-
//! #
70-
//! # unsafe impl ClassType for MyClass {
71-
//! # type Super = objc2::runtime::NSObject;
72-
//! # const NAME: &'static str = "NSObject";
73-
//! # }
7471
//! # );
7572
//!
7673
//! extern_methods!(

crates/header-translator/src/stmt.rs

+18-80
Original file line numberDiff line numberDiff line change
@@ -1658,18 +1658,23 @@ impl Stmt {
16581658
return Ok(());
16591659
}
16601660

1661-
let macro_name = if generics.is_empty() {
1662-
"extern_class"
1663-
} else {
1664-
"__inner_extern_class"
1665-
};
1666-
1667-
let (superclass, superclasses_rest) = superclasses.split_at(1);
1668-
let (superclass, superclass_generics) = superclass
1669-
.first()
1670-
.expect("must have a least one superclass");
1671-
1672-
writeln!(f, "{macro_name}!(")?;
1661+
writeln!(f, "extern_class!(")?;
1662+
write!(f, " #[unsafe(super(")?;
1663+
for (i, (superclass, generics)) in superclasses.iter().enumerate() {
1664+
if 0 < i {
1665+
write!(f, ", ")?;
1666+
}
1667+
write!(
1668+
f,
1669+
"{}{}",
1670+
superclass.path_in_relation_to(id.location()),
1671+
GenericTyHelper(generics)
1672+
)?;
1673+
}
1674+
writeln!(f, "))]")?;
1675+
if *main_thread_only {
1676+
writeln!(f, " #[thread_kind = MainThreadOnly]")?;
1677+
}
16731678
writeln!(f, " {derives}")?;
16741679
write!(f, " {}", self.cfg_gate_ln(config))?;
16751680
write!(f, " {availability}")?;
@@ -1681,74 +1686,7 @@ impl Stmt {
16811686
}
16821687
write!(f, ">")?;
16831688
};
1684-
if generics.is_empty() {
1685-
writeln!(f, ";")?;
1686-
} else {
1687-
writeln!(f, " {{")?;
1688-
writeln!(
1689-
f,
1690-
"__superclass: {}{},",
1691-
superclass.path_in_relation_to(id.location()),
1692-
GenericTyHelper(superclass_generics),
1693-
)?;
1694-
for (i, generic) in generics.iter().enumerate() {
1695-
// Invariant over the generic by default
1696-
writeln!(f, "_inner{i}: PhantomData<*mut {generic}>,")?;
1697-
}
1698-
writeln!(f, "notunwindsafe: PhantomData<&'static mut ()>,")?;
1699-
writeln!(f, "}}")?;
1700-
}
1701-
1702-
writeln!(f)?;
1703-
1704-
write!(f, " {}", self.cfg_gate_ln(config))?;
1705-
writeln!(
1706-
f,
1707-
" unsafe impl{} ClassType for {}{} {{",
1708-
GenericParamsHelper(generics, "?Sized + Message"),
1709-
id.name,
1710-
GenericTyHelper(generics),
1711-
)?;
1712-
if !superclasses_rest.is_empty() {
1713-
write!(f, " #[inherits(")?;
1714-
let mut iter = superclasses_rest.iter();
1715-
// Using generics in here is not technically correct, but
1716-
// should work for our use-cases.
1717-
if let Some((superclass, generics)) = iter.next() {
1718-
write!(
1719-
f,
1720-
"{}{}",
1721-
superclass.path_in_relation_to(id.location()),
1722-
GenericTyHelper(generics)
1723-
)?;
1724-
}
1725-
for (superclass, generics) in iter {
1726-
write!(
1727-
f,
1728-
", {}{}",
1729-
superclass.path_in_relation_to(id.location()),
1730-
GenericTyHelper(generics)
1731-
)?;
1732-
}
1733-
writeln!(f, ")]")?;
1734-
}
1735-
writeln!(
1736-
f,
1737-
" type Super = {}{};",
1738-
superclass.path_in_relation_to(id.location()),
1739-
GenericTyHelper(superclass_generics),
1740-
)?;
1741-
if *main_thread_only {
1742-
writeln!(f, " type ThreadKind = dyn MainThreadOnly;")?;
1743-
}
1744-
if !generics.is_empty() {
1745-
writeln!(f)?;
1746-
writeln!(
1747-
f,
1748-
" fn as_super(&self) -> &Self::Super {{ &self.__superclass }}"
1749-
)?;
1750-
}
1751-
writeln!(f, " }}")?;
1689+
writeln!(f, ";")?;
17521690
writeln!(f, ");")?;
17531691

17541692
if *sendable && generics.is_empty() {

crates/objc2/src/__framework_prelude.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ pub use crate::runtime::{
1717
AnyClass, AnyObject, Bool, NSObject, NSObjectProtocol, ProtocolObject, Sel,
1818
};
1919
pub use crate::{
20-
MainThreadOnly, __inner_extern_class, extern_category, extern_class, extern_methods,
21-
extern_protocol, ClassType, MainThreadMarker, Message, ProtocolType,
20+
extern_category, extern_class, extern_methods, extern_protocol, ClassType, MainThreadMarker,
21+
MainThreadOnly, Message, ProtocolType,
2222
};
2323

2424
// TODO

crates/objc2/src/__macro_helpers/class.rs

+14-29
Original file line numberDiff line numberDiff line change
@@ -54,54 +54,39 @@ mod tests {
5454
use crate::runtime::NSObject;
5555

5656
extern_class!(
57+
#[unsafe(super(NSObject))]
58+
#[thread_kind = AllocAnyThread]
59+
#[name = "NSObject"]
5760
struct SetAnyThread;
58-
59-
unsafe impl ClassType for SetAnyThread {
60-
type Super = NSObject;
61-
type ThreadKind = dyn AllocAnyThread;
62-
const NAME: &'static str = "NSObject";
63-
}
6461
);
6562

6663
extern_class!(
64+
#[unsafe(super(NSObject))]
65+
#[thread_kind = AllocAnyThread]
66+
#[name = "NSObject"]
6767
struct SendSync;
68-
69-
unsafe impl ClassType for SendSync {
70-
type Super = NSObject;
71-
type ThreadKind = dyn AllocAnyThread;
72-
const NAME: &'static str = "NSObject";
73-
}
7468
);
7569

7670
unsafe impl Send for SendSync {}
7771
unsafe impl Sync for SendSync {}
7872

7973
extern_class!(
74+
#[unsafe(super(NSObject))]
75+
#[thread_kind = MainThreadOnly]
76+
#[name = "NSObject"]
8077
struct OnlyMain;
81-
82-
unsafe impl ClassType for OnlyMain {
83-
type Super = NSObject;
84-
type ThreadKind = dyn MainThreadOnly;
85-
const NAME: &'static str = "NSObject";
86-
}
8778
);
8879

8980
extern_class!(
81+
#[unsafe(super(OnlyMain))]
82+
#[name = "NSObject"]
9083
struct OnlyMainSubDefault;
91-
92-
unsafe impl ClassType for OnlyMainSubDefault {
93-
type Super = OnlyMain;
94-
const NAME: &'static str = "NSObject";
95-
}
9684
);
9785

9886
extern_class!(
87+
#[unsafe(super(OnlyMain))]
88+
#[thread_kind = MainThreadOnly]
89+
#[name = "NSObject"]
9990
struct OnlyMainSubExplicit;
100-
101-
unsafe impl ClassType for OnlyMainSubExplicit {
102-
type Super = OnlyMain;
103-
type ThreadKind = dyn MainThreadOnly;
104-
const NAME: &'static str = "NSObject";
105-
}
10691
);
10792
}

crates/objc2/src/__macro_helpers/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
pub use core::borrow::Borrow;
22
pub use core::cell::UnsafeCell;
3+
pub use core::cmp::{Eq, PartialEq};
34
pub use core::convert::AsRef;
45
pub use core::default::Default;
6+
pub use core::fmt;
7+
pub use core::hash::{Hash, Hasher};
58
pub use core::marker::{PhantomData, Sized};
69
pub use core::mem::{size_of, ManuallyDrop, MaybeUninit};
710
pub use core::ops::Deref;

0 commit comments

Comments
 (0)