Skip to content

Commit 9fbdbf4

Browse files
committed
Add MainThreadMarker From implementation for MainThreadOnly types
1 parent 5ccff61 commit 9fbdbf4

File tree

4 files changed

+37
-0
lines changed

4 files changed

+37
-0
lines changed

crates/icrate/CHANGELOG.md

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

1111
## icrate Unreleased - YYYY-MM-DD
1212

13+
### Added
14+
* Added `MainThreadMarker` `From` implementation for `MainThreadOnly` types.
15+
1316
### Changed
1417
* Moved the `ns_string!` macro to `icrate::Foundation::ns_string`. The old
1518
location in the crate root is deprecated.

crates/icrate/src/Foundation/additions/thread.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::common::*;
88
use crate::Foundation::NSThread;
99

1010
use objc2::msg_send_id;
11+
use objc2::mutability::IsMainThreadOnly;
1112

1213
unsafe impl Send for NSThread {}
1314
unsafe impl Sync for NSThread {}
@@ -191,6 +192,23 @@ impl MainThreadMarker {
191192
}
192193
}
193194

195+
/// Get a [`MainThreadMarker`] from a main-thread-only object.
196+
///
197+
/// This function exists purely in the type-system, and will always
198+
/// succeed at runtime.
199+
impl<T: ?Sized + IsMainThreadOnly> From<&T> for MainThreadMarker {
200+
#[inline]
201+
fn from(_obj: &T) -> Self {
202+
// SAFETY: Objects which are `IsMainThreadOnly` are guaranteed
203+
// `!Send + !Sync` and are only constructible on the main thread.
204+
//
205+
// Since we hold a reference to such an object, and we know it cannot
206+
// now possibly be on another thread than the main, we know that the
207+
// current thread is the main thread.
208+
unsafe { Self::new_unchecked() }
209+
}
210+
}
211+
194212
impl fmt::Debug for MainThreadMarker {
195213
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196214
f.debug_tuple("MainThreadMarker").finish()

crates/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 `mutability::IsMainThreadOnly`.
11+
12+
913
## 0.4.1 - 2023-07-31
1014

1115
### Added

crates/objc2/src/mutability.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ pub struct InteriorMutable {
190190
///
191191
/// This is commonly used in GUI code like `AppKit` and `UIKit`, e.g.
192192
/// `UIWindow` is only usable from the application's main thread.
193+
///
194+
/// It is unsound to implement [`Send`] or [`Sync`] on a type with this
195+
/// mutability.
193196
//
194197
// While Xcode's Main Thread Checker doesn't report `alloc` and `dealloc` as
195198
// unsafe from other threads, things like `NSView` and `NSWindow` still do a
@@ -308,6 +311,15 @@ impl<T: ?Sized + ClassType> IsAllocableAnyThread for T where
308311
pub trait IsMutable: ClassType {}
309312
impl<T: ?Sized + ClassType> IsMutable for T where T::Mutability: private::MutabilityIsMutable {}
310313

314+
/// Marker trait for classes that are only available on the main thread.
315+
///
316+
/// This is implemented for classes whose [`ClassType::Mutability`] is one of:
317+
/// - [`MainThreadOnly`].
318+
//
319+
// Note: MainThreadMarker::from relies on this.
320+
pub trait IsMainThreadOnly: ClassType {}
321+
impl<T: ?Sized + ClassType<Mutability = MainThreadOnly>> IsMainThreadOnly for T {}
322+
311323
#[cfg(test)]
312324
mod tests {
313325
use super::*;

0 commit comments

Comments
 (0)