1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! Implementation of [`spawn()`] and types related to it.

use std::fmt::{Debug, Formatter};
use std::pin::Pin;
use std::task::{Context, Poll};
use std::{fmt, thread};

use super::{r#impl, Builder, Thread};

/// See [`std::thread::spawn()`].
///
/// # Panics
///
/// If the main thread does not support spawning threads, see
/// [`web::has_spawn_support()`](crate::web::has_spawn_support).
#[allow(clippy::min_ident_chars, clippy::type_repetition_in_bounds)]
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
	F: FnOnce() -> T,
	F: Send + 'static,
	T: Send + 'static,
{
	Builder::new().spawn(f).expect("failed to spawn thread")
}

/// See [`std::thread::JoinHandle`].
pub struct JoinHandle<T>(r#impl::JoinHandle<T>);

impl<T> Debug for JoinHandle<T> {
	fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
		formatter.debug_tuple("JoinHandle").field(&self.0).finish()
	}
}

impl<T> JoinHandle<T> {
	/// Creates a new [`JoinHandle`].
	pub(super) const fn new(handle: r#impl::JoinHandle<T>) -> Self {
		Self(handle)
	}

	/// See [`std::thread::JoinHandle::is_finished()`].
	///
	/// # Notes
	///
	/// When this returns [`true`] it guarantees [`JoinHandle::join()`] not to
	/// block.
	#[allow(clippy::must_use_candidate)]
	pub fn is_finished(&self) -> bool {
		self.0.is_finished()
	}

	/// See [`std::thread::JoinHandle::join()`].
	///
	/// # Notes
	///
	/// When compiling with [`panic = "abort"`], which is the only option
	/// without enabling the Wasm exception-handling proposal, this can never
	/// return [`Err`].
	///
	/// # Panics
	///
	/// - If the calling thread doesn't support blocking, see
	///   [`web::has_block_support()`](crate::web::has_block_support). Though it
	///   is guaranteed to not block if [`JoinHandle::is_finished()`] returns
	///   [`true`]. Alternatively consider using
	///   [`web::JoinHandleExt::join_async()`].
	/// - If called on the thread to join.
	/// - If it was already polled to completion through
	///   [`web::JoinHandleExt::join_async()`].
	///
	/// [`panic = "abort"`]: https://doc.rust-lang.org/1.75.0/cargo/reference/profiles.html#panic
	/// [`web::JoinHandleExt::join_async()`]: crate::web::JoinHandleExt::join_async
	#[allow(clippy::missing_errors_doc)]
	pub fn join(self) -> thread::Result<T> {
		self.0.join()
	}

	/// See [`std::thread::JoinHandle::thread()`].
	#[must_use]
	pub fn thread(&self) -> &Thread {
		self.0.thread()
	}

	/// Implementation for
	/// [`JoinHandleFuture::poll()`](crate::web::JoinHandleFuture).
	pub(crate) fn poll(&mut self, cx: &mut Context<'_>) -> Poll<thread::Result<T>> {
		Pin::new(&mut self.0).poll(cx)
	}
}