Skip to main content

mir_analyzer/
indexing.rs

1//! Chunked, cancellable workspace-indexing primitives.
2//!
3//! These types support the rust-analyzer-style **eager background indexing**
4//! model: at session start the consumer enumerates every project + vendor file
5//! (see [`crate::composer::Psr4Map::all_vendor_files`]) and pumps them through
6//! [`crate::AnalysisSession::index_batch`] in bounded chunks. Each chunk takes
7//! one short write window and merges its declarations into the workspace symbol
8//! index incrementally, so the analyzer stays responsive (no multi-second
9//! freeze) while the index fills, and the input set becomes static afterward —
10//! no per-edit churn of the warm cache.
11//!
12//! The library owns **no** background thread. The consumer drives the pump:
13//! an LSP server runs it on a worker thread; a single-threaded wasm host pumps
14//! one chunk per `requestIdleCallback`/`setTimeout(0)` tick. Both pass the same
15//! API; only [`IndexParallelism`] differs.
16
17use std::sync::atomic::{AtomicBool, Ordering};
18use std::sync::Arc;
19
20/// Cooperative cancellation flag shared between a consumer's driver and the
21/// indexing/analysis calls it makes.
22///
23/// Salsa's own cancellation is query-granular and does not unwind the
24/// plain-Rust body-analysis walk, so long-running loops here check this flag at
25/// chunk / file boundaries instead. On each new edit the consumer should drop
26/// the old flag and create a fresh one for the new work rather than reusing a
27/// single flag.
28#[derive(Clone, Default)]
29pub struct IndexCancel(Arc<AtomicBool>);
30
31impl IndexCancel {
32    /// A fresh, un-cancelled token.
33    pub fn new() -> Self {
34        Self::default()
35    }
36
37    /// Request cancellation. In-flight chunks finish their current bounded unit
38    /// and stop at the next boundary.
39    pub fn cancel(&self) {
40        self.0.store(true, Ordering::Relaxed);
41    }
42
43    /// Whether cancellation has been requested.
44    pub fn is_cancelled(&self) -> bool {
45        self.0.load(Ordering::Relaxed)
46    }
47}
48
49/// How an [`crate::AnalysisSession::index_batch`] call parses the files in a
50/// chunk. `Sequential` is required on wasm (no threads / no rayon); `Rayon`
51/// parallelises the parse across the global thread pool on native consumers.
52#[derive(Clone, Copy, PartialEq, Eq, Debug)]
53pub enum IndexParallelism {
54    Sequential,
55    Rayon,
56}
57
58/// Result of one [`crate::AnalysisSession::index_batch`] call.
59#[derive(Clone, Copy, Debug, Default)]
60pub struct IndexBatchOutcome {
61    /// Files newly registered as salsa inputs by this batch (already-registered
62    /// paths are updated in place and not counted).
63    pub registered: usize,
64    /// `true` if the cancel flag was observed; the batch may be partial.
65    pub cancelled: bool,
66    /// The workspace generation epoch after this batch (see
67    /// [`crate::AnalysisSession::index_generation`]). The consumer records this
68    /// alongside published diagnostics; when it later advances, affected open
69    /// files become candidates for re-analysis.
70    pub generation: u64,
71}