1use std::fmt;
19
20mod intent;
21mod pool;
22
23pub use intent::ThreadIntent;
24pub use pool::Pool;
25
26pub fn spawn<F, T>(intent: ThreadIntent, name: String, f: F) -> JoinHandle<T>
30where
31 F: (FnOnce() -> T) + Send + 'static,
32 T: Send + 'static,
33{
34 Builder::new(intent, name).spawn(f).expect("failed to spawn thread")
35}
36
37pub struct Builder {
38 intent: ThreadIntent,
39 inner: jod_thread::Builder,
40 allow_leak: bool,
41}
42
43impl Builder {
44 #[must_use]
45 pub fn new(intent: ThreadIntent, name: impl Into<String>) -> Self {
46 Self { intent, inner: jod_thread::Builder::new().name(name.into()), allow_leak: false }
47 }
48
49 #[must_use]
50 pub fn stack_size(self, size: usize) -> Self {
51 Self { inner: self.inner.stack_size(size), ..self }
52 }
53
54 #[must_use]
57 pub fn allow_leak(self, allow_leak: bool) -> Self {
58 Self { allow_leak, ..self }
59 }
60
61 pub fn spawn<F, T>(self, f: F) -> std::io::Result<JoinHandle<T>>
62 where
63 F: (FnOnce() -> T) + Send + 'static,
64 T: Send + 'static,
65 {
66 let inner_handle = self.inner.spawn(move || {
67 self.intent.apply_to_current_thread();
68 f()
69 })?;
70
71 Ok(JoinHandle { inner: Some(inner_handle), allow_leak: self.allow_leak })
72 }
73}
74
75pub struct JoinHandle<T = ()> {
76 inner: Option<jod_thread::JoinHandle<T>>,
79 allow_leak: bool,
80}
81
82impl<T> JoinHandle<T> {
83 #[must_use]
87 pub fn join(mut self) -> T {
88 self.inner.take().unwrap().join()
89 }
90}
91
92impl<T> Drop for JoinHandle<T> {
93 fn drop(&mut self) {
94 if !self.allow_leak {
95 return;
96 }
97
98 if let Some(join_handle) = self.inner.take() {
99 join_handle.detach();
100 }
101 }
102}
103
104#[expect(clippy::min_ident_chars, reason = "trait impl")]
105impl<T> fmt::Debug for JoinHandle<T> {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 f.pad("JoinHandle { .. }")
108 }
109}