job_pool/
scope.rs

1use core::marker::PhantomData;
2use core::mem;
3
4use crate::worker::Job;
5use crate::{Counter, ThreadPool};
6
7/// A scope to spawn jobs inside a [ThreadPool]
8///
9/// This struct is created by the [ThreadPool::scope] function
10pub struct Scope<'scope, 'pool: 'scope> {
11    scope_counter: Counter,
12    pool: &'pool ThreadPool,
13
14    /// Invariance over 'scope, to make sure 'scope cannot shrink,
15    /// which is necessary for soundness.
16    ///
17    /// Without invariance, this would compile fine but be unsound:
18    ///
19    /// ```compile_fail,E0373
20    /// use job_pool::ThreadPool;
21    ///
22    /// let pool = ThreadPool::default();
23    /// pool.scope(|s| {
24    ///     s.spawn(|| {
25    ///         let a = String::from("abcd");
26    ///         s.spawn(|| println!("{a:?}")); // might run after `a` is dropped
27    ///     });
28    /// });
29    /// ```
30    _marker_scope: PhantomData<&'scope mut &'scope ()>,
31}
32
33impl<'scope, 'pool> Scope<'scope, 'pool> {
34    pub(super) fn new(pool: &'pool ThreadPool) -> Self {
35        Self {
36            scope_counter: Counter::new(),
37            pool,
38            _marker_scope: PhantomData,
39        }
40    }
41
42    /// Executes a job inside this [Scope].
43    pub fn execute(&self, job: impl Job<'scope>) {
44        let job: Box<dyn Job<'scope>> = Box::new(job);
45        /* SAFETY: Scope makes sure that all jobs sent through it are
46         * finished before droping it. So the jobs won't outlive the
47         * 'scope lifetime. */
48        let job: Box<dyn Job<'static>> = unsafe { mem::transmute(job) };
49        self.pool.execute_inside_scope(job, self.scope_counter.clone());
50    }
51
52    /// Creates a new scope inside `self`.
53    ///
54    /// # Example
55    /// ```
56    /// use job_pool::ThreadPool;
57    ///
58    /// let pool = ThreadPool::default();
59    ///
60    /// let msg = String::from("Helloo :)");
61    /// pool.scope(|scope| {
62    ///     let helloworld = format!("{msg} world!");
63    ///     scope.subscope(|subscope1| {
64    ///         subscope1.execute(|| println!("1) {helloworld}"));
65    ///         subscope1.execute(|| println!("2) {helloworld}"));
66    ///     });
67    /// });
68    /// ```
69    pub fn subscope<'new, F, R>(&self, f: F) -> R
70    where
71        F: FnOnce(&Scope<'new, 'pool>) -> R,
72        'scope: 'new
73    {
74        let scope = Scope {
75            scope_counter: Counter::new(),
76            pool: self.pool,
77            _marker_scope: PhantomData,
78        };
79        f(&scope)
80    }
81}
82
83impl Drop for Scope<'_, '_> {
84    fn drop(&mut self) {
85        self.scope_counter.join();
86    }
87}