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