Struct MainThreadMarker

Source
pub struct MainThreadMarker { /* private fields */ }
Expand description

A marker type for functionality only available on the main thread.

The main thread is a system-level property on Apple/Darwin platforms, and has extra capabilities not available on other threads. This is usually relevant when using native GUI frameworks, where most operations must be done on the main thread.

This type enables you to manage that capability. By design, it is neither Send nor Sync, and can only be created on the main thread, meaning that if you have an instance of this, you are guaranteed to be on the main thread / have the “main-thread capability”.

The main function will run on the main thread. This type can also be used with #![no_main] or other such cases where Rust is not defining the binary entry point.

See the following links for more information on main-thread-only APIs:

§Main Thread Checker

Xcode provides a tool called the “Main Thread Checker” which verifies that UI APIs are being used from the correct thread. This is not as principled as MainThreadMarker, but is helpful for catching mistakes.

You can use this tool on macOS by loading libMainThreadChecker.dylib into your process using DYLD_INSERT_LIBRARIES:

DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/usr/lib/libMainThreadChecker.dylib MTC_RESET_INSERT_LIBRARIES=0 cargo run

If you’re not running your binary through Cargo, you can omit MTC_RESET_INSERT_LIBRARIES.

DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/usr/lib/libMainThreadChecker.dylib target/debug/myapp

If you’re developing for iOS, you probably better off enabling the tool in Xcode’s own UI.

See this excellent blog post for details on further configuration options.

§Examples

Retrieve the main thread marker in different situations.

use objc2::MainThreadMarker;

fn main() {
    // The thread that `fn main` runs on is the main thread.
    assert!(MainThreadMarker::new().is_some());

    // Subsequently spawned threads are not the main thread.
    std::thread::spawn(|| {
        assert!(MainThreadMarker::new().is_none());
    }).join().unwrap();
}

Use when accessing APIs that are only safe to use on the main thread.

use objc2::MainThreadMarker;
use objc2_app_kit::NSApplication;

fn main() {
    // Create a new MainThreadMarker.
    let mtm = MainThreadMarker::new().expect("must be on the main thread");

    // NSApplication is only usable on the main thread,
    // so we need to pass the marker as an argument.
    let app = NSApplication::sharedApplication(mtm);

    // Do something with the application
    // app.run();
}

Create a static that is only usable on the main thread. This is similar to a thread-local, but can be more efficient because it doesn’t handle multiple threads.

See also dispatch2::MainThreadBound.

use objc2::MainThreadMarker;
use std::cell::UnsafeCell;

struct SyncUnsafeCell<T>(UnsafeCell<T>);

unsafe impl<T> Sync for SyncUnsafeCell<T> {}

static MAIN_THREAD_ONLY_VALUE: SyncUnsafeCell<i32> = SyncUnsafeCell(UnsafeCell::new(0));

fn set(value: i32, _mtm: MainThreadMarker) {
    // SAFETY: We have an instance of `MainThreadMarker`, so we know that
    // we're running on the main thread (and thus do not need any
    // synchronization, since the only accesses to this value is from the
    // main thread).
    unsafe { *MAIN_THREAD_ONLY_VALUE.0.get() = value };
}

fn get(_mtm: MainThreadMarker) -> i32 {
    // SAFETY: Same as above.
    unsafe { *MAIN_THREAD_ONLY_VALUE.0.get() }
}

fn main() {
    let mtm = MainThreadMarker::new().expect("must be on the main thread");
    set(42, mtm);
    assert_eq!(get(mtm), 42);
}

Implementations§

Source§

impl MainThreadMarker

Source

pub fn new() -> Option<MainThreadMarker>

Construct a new MainThreadMarker.

Returns None if the current thread was not the main thread.

§Example

Check whether the current thread is the main thread.

use objc2::MainThreadMarker;

if MainThreadMarker::new().is_some() {
    // Is the main thread
} else {
    // Not the main thread
}
Source

pub const unsafe fn new_unchecked() -> MainThreadMarker

Construct a new MainThreadMarker without first checking whether the current thread is the main one.

§Safety

The current thread must be the main thread.

Alternatively, you may create this briefly if you know that a an API is safe in a specific case, but is not marked so. If you do that, you must ensure that any use of the marker is actually safe to do from another thread than the main one.

Source

pub fn alloc<T>(self) -> Allocated<T>
where T: ClassType,

Allocate a new instance of the specified class on the main thread.

This can be useful in certain situations, such as generic contexts where you don’t know whether the class is main thread or not, but usually you should prefer MainThreadOnly::alloc.

Trait Implementations§

Source§

impl Clone for MainThreadMarker

Source§

fn clone(&self) -> MainThreadMarker

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for MainThreadMarker

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl<T> From<&T> for MainThreadMarker
where T: MainThreadOnly + ?Sized,

Get a MainThreadMarker from a main-thread-only object.

This is a shorthand for MainThreadOnly::mtm.

Source§

fn from(obj: &T) -> MainThreadMarker

Converts to this type from the input type.
Source§

impl Hash for MainThreadMarker

Source§

fn hash<__H>(&self, state: &mut __H)
where __H: Hasher,

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl Ord for MainThreadMarker

Source§

fn cmp(&self, other: &MainThreadMarker) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl PartialEq for MainThreadMarker

Source§

fn eq(&self, other: &MainThreadMarker) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl PartialOrd for MainThreadMarker

Source§

fn partial_cmp(&self, other: &MainThreadMarker) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl Copy for MainThreadMarker

Source§

impl Eq for MainThreadMarker

Source§

impl StructuralPartialEq for MainThreadMarker

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> AutoreleaseSafe for T
where T: ?Sized,