cargo/core/compiler/job_queue/
job.rs

1//! See [`Job`] and [`Work`].
2
3use std::fmt;
4use std::mem;
5
6use super::JobState;
7use crate::core::compiler::fingerprint::DirtyReason;
8use crate::util::CargoResult;
9
10/// Represents a unit of [`Work`] with a [`Freshness`] for caller
11/// to determine whether to re-execute or not.
12pub struct Job {
13    work: Work,
14    fresh: Freshness,
15}
16
17/// The basic unit of work.
18///
19/// Each proc should send its description before starting.
20/// It should send either once or close immediately.
21pub struct Work {
22    inner: Box<dyn FnOnce(&JobState<'_, '_>) -> CargoResult<()> + Send>,
23}
24
25impl Work {
26    /// Creates a unit of work.
27    pub fn new<F>(f: F) -> Work
28    where
29        F: FnOnce(&JobState<'_, '_>) -> CargoResult<()> + Send + 'static,
30    {
31        Work { inner: Box::new(f) }
32    }
33
34    /// Creates a unit of work that does nothing.
35    pub fn noop() -> Work {
36        Work::new(|_| Ok(()))
37    }
38
39    /// Consumes this work by running it.
40    pub fn call(self, tx: &JobState<'_, '_>) -> CargoResult<()> {
41        (self.inner)(tx)
42    }
43
44    /// Creates a new unit of work that chains `next` after ourself.
45    pub fn then(self, next: Work) -> Work {
46        Work::new(move |state| {
47            self.call(state)?;
48            next.call(state)
49        })
50    }
51}
52
53impl Job {
54    /// Creates a new job that does nothing.
55    pub fn new_fresh() -> Job {
56        Job {
57            work: Work::noop(),
58            fresh: Freshness::Fresh,
59        }
60    }
61
62    /// Creates a new job representing a unit of work.
63    pub fn new_dirty(work: Work, dirty_reason: DirtyReason) -> Job {
64        Job {
65            work,
66            fresh: Freshness::Dirty(dirty_reason),
67        }
68    }
69
70    /// Consumes this job by running it, returning the result of the
71    /// computation.
72    pub fn run(self, state: &JobState<'_, '_>) -> CargoResult<()> {
73        self.work.call(state)
74    }
75
76    /// Returns whether this job was fresh/dirty, where "fresh" means we're
77    /// likely to perform just some small bookkeeping where "dirty" means we'll
78    /// probably do something slow like invoke rustc.
79    pub fn freshness(&self) -> &Freshness {
80        &self.fresh
81    }
82
83    /// Chains the given work by putting it in front of our own unit of work.
84    pub fn before(&mut self, next: Work) {
85        let prev = mem::replace(&mut self.work, Work::noop());
86        self.work = next.then(prev);
87    }
88}
89
90impl fmt::Debug for Job {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        write!(f, "Job {{ ... }}")
93    }
94}
95
96/// Indication of the freshness of a package.
97///
98/// A fresh package does not necessarily need to be rebuilt (unless a dependency
99/// was also rebuilt), and a dirty package must always be rebuilt.
100#[derive(Debug, Clone)]
101pub enum Freshness {
102    Fresh,
103    Dirty(DirtyReason),
104}
105
106impl Freshness {
107    pub fn is_dirty(&self) -> bool {
108        matches!(self, Freshness::Dirty(_))
109    }
110
111    pub fn is_fresh(&self) -> bool {
112        matches!(self, Freshness::Fresh)
113    }
114}