#
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}