rust_analyzer/
op_queue.rs

1//! Bookkeeping to make sure only one long-running operation is being executed
2//! at a time.
3
4pub(crate) type Cause = String;
5
6/// A single-item queue that allows callers to request an operation to
7/// be performed later.
8///
9/// ```ignore
10/// let queue = OpQueue::default();
11///
12/// // Request work to be done.
13/// queue.request_op("user pushed a button", ());
14///
15/// // In a later iteration of the server loop, we start the work.
16/// if let Some((_cause, ())) = queue.should_start_op() {
17///     dbg!("Some slow operation here");
18/// }
19///
20/// // In an even later iteration of the server loop, we can see that the work
21/// // was completed.
22/// if !queue.op_in_progress() {
23///     dbg!("Work has been done!");
24/// }
25/// ```
26#[derive(Debug)]
27pub(crate) struct OpQueue<Args = (), Output = ()> {
28    op_requested: Option<(Cause, Args)>,
29    op_in_progress: bool,
30    last_op_result: Option<Output>,
31}
32
33impl<Args, Output> Default for OpQueue<Args, Output> {
34    fn default() -> Self {
35        Self { op_requested: None, op_in_progress: false, last_op_result: None }
36    }
37}
38
39impl<Args: std::fmt::Debug, Output> OpQueue<Args, Output> {
40    /// Request an operation to start.
41    pub(crate) fn request_op(&mut self, reason: Cause, args: Args) {
42        self.op_requested = Some((reason, args));
43    }
44
45    /// If there was an operation requested, mark this queue as
46    /// started and return the request arguments.
47    pub(crate) fn should_start_op(&mut self) -> Option<(Cause, Args)> {
48        if self.op_in_progress {
49            return None;
50        }
51        self.op_in_progress = self.op_requested.is_some();
52        self.op_requested.take()
53    }
54
55    /// Mark an operation as completed.
56    pub(crate) fn op_completed(&mut self, result: Output) {
57        assert!(self.op_in_progress);
58        self.op_in_progress = false;
59        self.last_op_result = Some(result);
60    }
61
62    /// Get the result of the last operation.
63    pub(crate) fn last_op_result(&self) -> Option<&Output> {
64        self.last_op_result.as_ref()
65    }
66
67    // Is there an operation that has started, but hasn't yet finished?
68    pub(crate) fn op_in_progress(&self) -> bool {
69        self.op_in_progress
70    }
71
72    // Has an operation been requested?
73    pub(crate) fn op_requested(&self) -> bool {
74        self.op_requested.is_some()
75    }
76}