use core::marker::PhantomData;
use objc2::rc::{Id, Shared};
use objc2::{msg_send, msg_send_bool, msg_send_id};
use crate::{NSObject, NSString};
extern_class! {
#[derive(Debug, PartialEq, Eq, Hash)]
unsafe pub struct NSThread: NSObject;
}
unsafe impl Send for NSThread {}
unsafe impl Sync for NSThread {}
impl NSThread {
pub fn current() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), currentThread].unwrap() }
}
pub fn main() -> Id<NSThread, Shared> {
unsafe { msg_send_id![Self::class(), mainThread] }.expect("Could not retrieve main thread.")
}
pub fn is_main(&self) -> bool {
unsafe { msg_send_bool![self, isMainThread] }
}
pub fn name(&self) -> Option<Id<NSString, Shared>> {
unsafe { msg_send_id![self, name] }
}
fn new() -> Id<Self, Shared> {
unsafe { msg_send_id![Self::class(), new] }.unwrap()
}
fn start(&self) {
unsafe { msg_send![self, start] }
}
}
pub fn is_multi_threaded() -> bool {
unsafe { msg_send_bool![NSThread::class(), isMultiThreaded] }
}
pub fn is_main_thread() -> bool {
unsafe { msg_send_bool![NSThread::class(), isMainThread] }
}
#[allow(unused)]
fn make_multithreaded() {
let thread = NSThread::new();
thread.start();
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MainThreadMarker {
_priv: PhantomData<*mut ()>,
}
impl MainThreadMarker {
pub fn new() -> Option<Self> {
if is_main_thread() {
Some(unsafe { Self::new_unchecked() })
} else {
None
}
}
pub unsafe fn new_unchecked() -> Self {
Self { _priv: PhantomData }
}
}
#[cfg(test)]
mod tests {
use core::panic::{RefUnwindSafe, UnwindSafe};
use super::*;
#[test]
#[cfg_attr(
feature = "gnustep-1-7",
ignore = "Retrieving main thread is weirdly broken, only works with --test-threads=1"
)]
fn test_main_thread() {
let current = NSThread::current();
let main = NSThread::main();
assert!(main.is_main());
if main == current {
assert!(current.is_main());
assert!(is_main_thread());
} else {
assert!(!current.is_main());
assert!(!is_main_thread());
}
}
#[test]
fn test_not_main_thread() {
let res = std::thread::spawn(|| (is_main_thread(), NSThread::current().is_main()))
.join()
.unwrap();
assert_eq!(res, (false, false));
}
#[test]
fn test_main_thread_auto_traits() {
fn assert_traits<T: Unpin + UnwindSafe + RefUnwindSafe + Sized>() {}
assert_traits::<MainThreadMarker>()
}
}