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}