1use crate::{BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset, ToPoint, ToPointUtf16};
2use anyhow::Result;
3use std::{cmp::Ordering, fmt::Debug, ops::Range};
4use sum_tree::Bias;
5
6#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
7pub struct Anchor {
8 pub timestamp: clock::Local,
9 pub offset: usize,
10 pub bias: Bias,
11 pub buffer_id: Option<u64>,
12}
13
14impl Anchor {
15 pub const MIN: Self = Self {
16 timestamp: clock::Local::MIN,
17 offset: usize::MIN,
18 bias: Bias::Left,
19 buffer_id: None,
20 };
21
22 pub const MAX: Self = Self {
23 timestamp: clock::Local::MAX,
24 offset: usize::MAX,
25 bias: Bias::Right,
26 buffer_id: None,
27 };
28
29 pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
30 let fragment_id_comparison = if self.timestamp == other.timestamp {
31 Ordering::Equal
32 } else {
33 buffer
34 .fragment_id_for_anchor(self)
35 .cmp(buffer.fragment_id_for_anchor(other))
36 };
37
38 fragment_id_comparison
39 .then_with(|| self.offset.cmp(&other.offset))
40 .then_with(|| self.bias.cmp(&other.bias))
41 }
42
43 pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
44 if self.cmp(other, buffer).is_le() {
45 *self
46 } else {
47 *other
48 }
49 }
50
51 pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
52 if self.cmp(other, buffer).is_ge() {
53 *self
54 } else {
55 *other
56 }
57 }
58
59 pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
60 if bias == Bias::Left {
61 self.bias_left(buffer)
62 } else {
63 self.bias_right(buffer)
64 }
65 }
66
67 pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
68 if self.bias == Bias::Left {
69 *self
70 } else {
71 buffer.anchor_before(self)
72 }
73 }
74
75 pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor {
76 if self.bias == Bias::Right {
77 *self
78 } else {
79 buffer.anchor_after(self)
80 }
81 }
82
83 pub fn summary<D>(&self, content: &BufferSnapshot) -> D
84 where
85 D: TextDimension,
86 {
87 content.summary_for_anchor(self)
88 }
89}
90
91pub trait OffsetRangeExt {
92 fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize>;
93 fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point>;
94 fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16>;
95}
96
97impl<T> OffsetRangeExt for Range<T>
98where
99 T: ToOffset,
100{
101 fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize> {
102 self.start.to_offset(snapshot)..self.end.to_offset(snapshot)
103 }
104
105 fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point> {
106 self.start.to_offset(snapshot).to_point(snapshot)
107 ..self.end.to_offset(snapshot).to_point(snapshot)
108 }
109
110 fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16> {
111 self.start.to_offset(snapshot).to_point_utf16(snapshot)
112 ..self.end.to_offset(snapshot).to_point_utf16(snapshot)
113 }
114}
115
116pub trait AnchorRangeExt {
117 fn cmp(&self, b: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering>;
118}
119
120impl AnchorRangeExt for Range<Anchor> {
121 fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering> {
122 Ok(match self.start.cmp(&other.start, buffer) {
123 Ordering::Equal => other.end.cmp(&self.end, buffer),
124 ord => ord,
125 })
126 }
127}