use super::{Buffer, Content, FromAnchor, FullOffset, Point, ToOffset}; use anyhow::Result; use std::{ cmp::Ordering, fmt::{Debug, Formatter}, ops::Range, }; use sum_tree::{Bias, SumTree}; #[derive(Clone, Eq, PartialEq, Debug, Hash)] pub struct Anchor { pub full_offset: FullOffset, pub bias: Bias, pub version: clock::Global, } #[derive(Clone)] pub struct AnchorMap { pub(crate) version: clock::Global, pub(crate) entries: Vec<((FullOffset, Bias), T)>, } #[derive(Clone)] pub struct AnchorSet(pub(crate) AnchorMap<()>); #[derive(Clone)] pub struct AnchorRangeMap { pub(crate) version: clock::Global, pub(crate) entries: Vec<(Range<(FullOffset, Bias)>, T)>, } #[derive(Clone)] pub struct AnchorRangeSet(pub(crate) AnchorRangeMap<()>); #[derive(Clone)] pub struct AnchorRangeMultimap { pub(crate) entries: SumTree>, pub(crate) version: clock::Global, pub(crate) start_bias: Bias, pub(crate) end_bias: Bias, } #[derive(Clone)] pub(crate) struct AnchorRangeMultimapEntry { pub(crate) range: FullOffsetRange, pub(crate) value: T, } #[derive(Clone, Debug)] pub(crate) struct FullOffsetRange { pub(crate) start: FullOffset, pub(crate) end: FullOffset, } #[derive(Clone, Debug)] pub(crate) struct AnchorRangeMultimapSummary { start: FullOffset, end: FullOffset, min_start: FullOffset, max_end: FullOffset, count: usize, } impl Anchor { pub fn min() -> Self { Self { full_offset: FullOffset(0), bias: Bias::Left, version: Default::default(), } } pub fn max() -> Self { Self { full_offset: FullOffset::MAX, bias: Bias::Right, version: Default::default(), } } pub fn cmp<'a>(&self, other: &Anchor, buffer: impl Into>) -> Result { let buffer = buffer.into(); if self == other { return Ok(Ordering::Equal); } let offset_comparison = if self.version == other.version { self.full_offset.cmp(&other.full_offset) } else { buffer .full_offset_for_anchor(self) .cmp(&buffer.full_offset_for_anchor(other)) }; Ok(offset_comparison.then_with(|| self.bias.cmp(&other.bias))) } pub fn bias_left(&self, buffer: &Buffer) -> Anchor { if self.bias == Bias::Left { self.clone() } else { buffer.anchor_before(self) } } pub fn bias_right(&self, buffer: &Buffer) -> Anchor { if self.bias == Bias::Right { self.clone() } else { buffer.anchor_after(self) } } } impl AnchorMap { pub fn version(&self) -> &clock::Global { &self.version } pub fn len(&self) -> usize { self.entries.len() } pub fn offsets<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { let content = content.into(); content .summaries_for_anchors(self) .map(move |(sum, value)| (sum.bytes, value)) } pub fn points<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { let content = content.into(); content .summaries_for_anchors(self) .map(move |(sum, value)| (sum.lines, value)) } } impl AnchorSet { pub fn version(&self) -> &clock::Global { &self.0.version } pub fn len(&self) -> usize { self.0.len() } pub fn offsets<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { self.0.offsets(content).map(|(offset, _)| offset) } pub fn points<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator + 'a { self.0.points(content).map(|(point, _)| point) } } impl AnchorRangeMap { pub fn version(&self) -> &clock::Global { &self.version } pub fn len(&self) -> usize { self.entries.len() } pub fn from_raw(version: clock::Global, entries: Vec<(Range<(FullOffset, Bias)>, T)>) -> Self { Self { version, entries } } pub fn raw_entries(&self) -> &[(Range<(FullOffset, Bias)>, T)] { &self.entries } pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator, &'a T)> + 'a { let content = content.into(); content .summaries_for_anchor_ranges(self) .map(move |(range, value)| ((range.start.lines..range.end.lines), value)) } pub fn offset_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator, &'a T)> + 'a { let content = content.into(); content .summaries_for_anchor_ranges(self) .map(move |(range, value)| ((range.start.bytes..range.end.bytes), value)) } } impl PartialEq for AnchorRangeMap { fn eq(&self, other: &Self) -> bool { self.version == other.version && self.entries == other.entries } } impl Eq for AnchorRangeMap {} impl Debug for AnchorRangeMap { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { let mut f = f.debug_map(); for (range, value) in &self.entries { f.key(range); f.value(value); } f.finish() } } impl Debug for AnchorRangeSet { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut f = f.debug_set(); for (range, _) in &self.0.entries { f.entry(range); } f.finish() } } impl AnchorRangeSet { pub fn len(&self) -> usize { self.0.len() } pub fn version(&self) -> &clock::Global { self.0.version() } pub fn offset_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator> + 'a { self.0.offset_ranges(content).map(|(range, _)| range) } pub fn point_ranges<'a>( &'a self, content: impl Into> + 'a, ) -> impl Iterator> + 'a { self.0.point_ranges(content).map(|(range, _)| range) } } impl Default for AnchorRangeMultimap { fn default() -> Self { Self { entries: Default::default(), version: Default::default(), start_bias: Bias::Left, end_bias: Bias::Left, } } } impl AnchorRangeMultimap { pub fn intersecting_ranges<'a, I, O>( &'a self, range: Range, content: Content<'a>, inclusive: bool, ) -> impl Iterator, &T)> + 'a where I: ToOffset, O: FromAnchor, { let end_bias = if inclusive { Bias::Right } else { Bias::Left }; let range = range.start.to_full_offset(&content, Bias::Left) ..range.end.to_full_offset(&content, end_bias); let mut cursor = self.entries.filter::<_, usize>( { let content = content.clone(); let mut endpoint = Anchor { full_offset: FullOffset(0), bias: Bias::Right, version: self.version.clone(), }; move |summary: &AnchorRangeMultimapSummary| { endpoint.full_offset = summary.max_end; endpoint.bias = self.end_bias; let max_end = endpoint.to_full_offset(&content, self.end_bias); let start_cmp = range.start.cmp(&max_end); endpoint.full_offset = summary.min_start; endpoint.bias = self.start_bias; let min_start = endpoint.to_full_offset(&content, self.start_bias); let end_cmp = range.end.cmp(&min_start); if inclusive { start_cmp <= Ordering::Equal && end_cmp >= Ordering::Equal } else { start_cmp == Ordering::Less && end_cmp == Ordering::Greater } } }, &(), ); std::iter::from_fn({ let mut endpoint = Anchor { full_offset: FullOffset(0), bias: Bias::Left, version: self.version.clone(), }; move || { if let Some(item) = cursor.item() { let ix = *cursor.start(); endpoint.full_offset = item.range.start; endpoint.bias = self.start_bias; let start = O::from_anchor(&endpoint, &content); endpoint.full_offset = item.range.end; endpoint.bias = self.end_bias; let end = O::from_anchor(&endpoint, &content); let value = &item.value; cursor.next(&()); Some((ix, start..end, value)) } else { None } } }) } } impl sum_tree::Item for AnchorRangeMultimapEntry { type Summary = AnchorRangeMultimapSummary; fn summary(&self) -> Self::Summary { AnchorRangeMultimapSummary { start: self.range.start, end: self.range.end, min_start: self.range.start, max_end: self.range.end, count: 1, } } } impl Default for AnchorRangeMultimapSummary { fn default() -> Self { Self { start: FullOffset(0), end: FullOffset::MAX, min_start: FullOffset::MAX, max_end: FullOffset(0), count: 0, } } } impl sum_tree::Summary for AnchorRangeMultimapSummary { type Context = (); fn add_summary(&mut self, other: &Self, _: &Self::Context) { self.min_start = self.min_start.min(other.min_start); self.max_end = self.max_end.max(other.max_end); #[cfg(debug_assertions)] { let start_comparison = self.start.cmp(&other.start); assert!(start_comparison <= Ordering::Equal); if start_comparison == Ordering::Equal { assert!(self.end.cmp(&other.end) >= Ordering::Equal); } } self.start = other.start; self.end = other.end; self.count += other.count; } } impl Default for FullOffsetRange { fn default() -> Self { Self { start: FullOffset(0), end: FullOffset::MAX, } } } impl<'a> sum_tree::Dimension<'a, AnchorRangeMultimapSummary> for usize { fn add_summary(&mut self, summary: &'a AnchorRangeMultimapSummary, _: &()) { *self += summary.count; } } impl<'a> sum_tree::Dimension<'a, AnchorRangeMultimapSummary> for FullOffsetRange { fn add_summary(&mut self, summary: &'a AnchorRangeMultimapSummary, _: &()) { self.start = summary.start; self.end = summary.end; } } impl<'a> sum_tree::SeekTarget<'a, AnchorRangeMultimapSummary, FullOffsetRange> for FullOffsetRange { fn cmp(&self, cursor_location: &FullOffsetRange, _: &()) -> Ordering { Ord::cmp(&self.start, &cursor_location.start) .then_with(|| Ord::cmp(&cursor_location.end, &self.end)) } } pub trait AnchorRangeExt { fn cmp<'a>(&self, b: &Range, buffer: impl Into>) -> Result; } impl AnchorRangeExt for Range { fn cmp<'a>(&self, other: &Range, buffer: impl Into>) -> Result { let buffer = buffer.into(); Ok(match self.start.cmp(&other.start, &buffer)? { Ordering::Equal => other.end.cmp(&self.end, buffer)?, ord @ _ => ord, }) } }