af_core/
thread.rs

1// Copyright © 2020 Alexandra Frydl
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! Thread management.
8
9pub use std::thread::yield_now;
10
11use crate::channel;
12use crate::prelude::*;
13use std::thread::{Builder, JoinHandle};
14
15/// An operating system thread.
16pub struct Thread<T> {
17  inner: JoinHandle<()>,
18  rx: channel::Receiver<T>,
19}
20
21/// Blocks the current thread until a given future is ready.
22pub fn block_on<T>(future: impl Future<Output = T>) -> T {
23  async_io::block_on(future)
24}
25
26/// Blocks the current thread for a given duration.
27pub fn sleep(dur: Duration) {
28  if dur.is_infinite() {
29    std::thread::sleep(std::time::Duration::new(u64::MAX, 0));
30  } else {
31    std::thread::sleep(dur.into());
32  }
33}
34
35/// Starts running an operation on a new thread.
36pub fn start<T: Send + 'static>(
37  name: impl Into<String>,
38  func: impl FnOnce() -> T + Send + 'static,
39) -> Thread<T> {
40  let (tx, rx) = channel::with_capacity(1);
41
42  let func = move || {
43    let output = func();
44    let _ = tx.try_send(output);
45  };
46
47  let inner = Builder::new().name(name.into()).spawn(func).expect("Failed to start thread");
48
49  Thread { inner, rx }
50}
51
52impl<T> Thread<T> {
53  /// Waits for the thread to stop and returns its result.
54  pub async fn join(self) -> Result<T, Panic> {
55    if let Ok(output) = self.rx.recv().await {
56      return Ok(output);
57    }
58
59    if let Err(value) = self.inner.join() {
60      return Err(Panic { value });
61    }
62
63    unreachable!("Thread finished but did not send output.");
64  }
65}
66
67impl<T, E> Thread<Result<T, E>>
68where
69  E: From<Panic>,
70{
71  /// Waits for the thread to stop and returns its result.
72  pub async fn try_join(self) -> Result<T, E> {
73    self.join().await?
74  }
75}