Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/span/src/map.rs')
| -rw-r--r-- | crates/span/src/map.rs | 79 |
1 files changed, 34 insertions, 45 deletions
diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs index d14c497474..dc7d471aa0 100644 --- a/crates/span/src/map.rs +++ b/crates/span/src/map.rs @@ -6,24 +6,21 @@ use std::{fmt, hash::Hash}; use stdx::{always, itertools::Itertools}; use crate::{ - EditionedFileId, ErasedFileAstId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SpanData, - SyntaxContext, TextRange, TextSize, + EditionedFileId, ErasedFileAstId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, + TextRange, TextSize, }; /// Maps absolute text ranges for the corresponding file to the relevant span data. #[derive(Debug, PartialEq, Eq, Clone, Hash)] -pub struct SpanMap<S> { +pub struct SpanMap { /// The offset stored here is the *end* of the node. - spans: Vec<(TextSize, SpanData<S>)>, + spans: Vec<(TextSize, Span)>, /// Index of the matched macro arm on successful expansion for declarative macros. // FIXME: Does it make sense to have this here? pub matched_arm: Option<u32>, } -impl<S> SpanMap<S> -where - SpanData<S>: Copy, -{ +impl SpanMap { /// Creates a new empty [`SpanMap`]. pub fn empty() -> Self { Self { spans: Vec::new(), matched_arm: None } @@ -40,7 +37,7 @@ where } /// Pushes a new span onto the [`SpanMap`]. - pub fn push(&mut self, offset: TextSize, span: SpanData<S>) { + pub fn push(&mut self, offset: TextSize, span: Span) { if cfg!(debug_assertions) && let Some(&(last_offset, _)) = self.spans.last() { @@ -57,11 +54,8 @@ where /// Note this does a linear search through the entire backing vector. pub fn ranges_with_span_exact( &self, - span: SpanData<S>, - ) -> impl Iterator<Item = (TextRange, S)> + '_ - where - S: Copy, - { + span: Span, + ) -> impl Iterator<Item = (TextRange, SyntaxContext)> + '_ { self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| { if !s.eq_ignoring_ctx(span) { return None; @@ -74,10 +68,10 @@ where /// Returns all [`TextRange`]s whose spans contain the given span. /// /// Note this does a linear search through the entire backing vector. - pub fn ranges_with_span(&self, span: SpanData<S>) -> impl Iterator<Item = (TextRange, S)> + '_ - where - S: Copy, - { + pub fn ranges_with_span( + &self, + span: Span, + ) -> impl Iterator<Item = (TextRange, SyntaxContext)> + '_ { self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| { if s.anchor != span.anchor { return None; @@ -91,28 +85,28 @@ where } /// Returns the span at the given position. - pub fn span_at(&self, offset: TextSize) -> SpanData<S> { + pub fn span_at(&self, offset: TextSize) -> Span { let entry = self.spans.partition_point(|&(it, _)| it <= offset); self.spans[entry].1 } /// Returns the spans associated with the given range. /// In other words, this will return all spans that correspond to all offsets within the given range. - pub fn spans_for_range(&self, range: TextRange) -> impl Iterator<Item = SpanData<S>> + '_ { + pub fn spans_for_range(&self, range: TextRange) -> impl Iterator<Item = Span> + '_ { let (start, end) = (range.start(), range.end()); let start_entry = self.spans.partition_point(|&(it, _)| it <= start); let end_entry = self.spans[start_entry..].partition_point(|&(it, _)| it <= end); // FIXME: this might be wrong? self.spans[start_entry..][..end_entry].iter().map(|&(_, s)| s) } - pub fn iter(&self) -> impl Iterator<Item = (TextSize, SpanData<S>)> + '_ { + pub fn iter(&self) -> impl Iterator<Item = (TextSize, Span)> + '_ { self.spans.iter().copied() } /// Merges this span map with another span map, where `other` is inserted at (and replaces) `other_range`. /// /// The length of the replacement node needs to be `other_size`. - pub fn merge(&mut self, other_range: TextRange, other_size: TextSize, other: &SpanMap<S>) { + pub fn merge(&mut self, other_range: TextRange, other_size: TextSize, other: &SpanMap) { // I find the following diagram helpful to illustrate the bounds and why we use `<` or `<=`: // -------------------------------------------------------------------- // 1 3 5 6 7 10 11 <-- offsets we store @@ -157,39 +151,34 @@ where } #[cfg(not(no_salsa_async_drops))] -impl<S> Drop for SpanMap<S> { +impl Drop for SpanMap { fn drop(&mut self) { - struct SendPtr(*mut [()]); - unsafe impl Send for SendPtr {} + let spans = std::mem::take(&mut self.spans); static SPAN_MAP_DROP_THREAD: std::sync::OnceLock< - std::sync::mpsc::Sender<(SendPtr, fn(SendPtr))>, + std::sync::mpsc::Sender<Vec<(TextSize, Span)>>, > = std::sync::OnceLock::new(); + SPAN_MAP_DROP_THREAD .get_or_init(|| { - let (sender, receiver) = std::sync::mpsc::channel::<(SendPtr, fn(SendPtr))>(); + let (sender, receiver) = std::sync::mpsc::channel::<Vec<(TextSize, Span)>>(); std::thread::Builder::new() .name("SpanMapDropper".to_owned()) - .spawn(move || receiver.iter().for_each(|(b, drop)| drop(b))) + .spawn(move || { + loop { + // block on a receive + _ = receiver.recv(); + // then drain the entire channel + while receiver.try_recv().is_ok() {} + // and sleep for a bit + std::thread::sleep(std::time::Duration::from_millis(100)); + } + // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock. + // otherwise this thread will constantly wake up and sleep again. + }) .unwrap(); sender }) - .send(( - unsafe { - SendPtr(std::mem::transmute::<*mut [(TextSize, SpanData<S>)], *mut [()]>( - Box::<[(TextSize, SpanData<S>)]>::into_raw( - std::mem::take(&mut self.spans).into_boxed_slice(), - ), - )) - }, - |b: SendPtr| { - _ = unsafe { - Box::from_raw(std::mem::transmute::< - *mut [()], - *mut [(TextSize, SpanData<S>)], - >(b.0)) - } - }, - )) + .send(spans) .unwrap(); } } |