1use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
10
11use bincode::{Decode, Encode};
12
13use super::Item;
14
15#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)]
19pub struct Point {
20 b: u32,
21 c: u32,
22 l: u32,
23}
24
25impl Point {
26 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub(super) fn from_raw(b: usize, c: usize, l: usize) -> Self {
35 let (b, c, l) = (b as u32, c as u32, l as u32);
36 Self { b, c, l }
37 }
38
39 pub fn len_of(str: impl AsRef<str>) -> Self {
50 let str = str.as_ref();
51 Self {
52 b: str.len() as u32,
53 c: str.chars().count() as u32,
54 l: str.bytes().filter(|c| *c == b'\n').count() as u32,
55 }
56 }
57
58 pub fn byte(&self) -> usize {
61 self.b as usize
62 }
63
64 pub fn char(&self) -> usize {
67 self.c as usize
68 }
69
70 pub fn line(&self) -> usize {
72 self.l as usize
73 }
74
75 pub fn checked_sub(self, rhs: Point) -> Option<Point> {
77 Some(Self {
78 b: self.b.checked_sub(rhs.b)?,
79 c: self.c.checked_sub(rhs.c)?,
80 l: self.l.checked_sub(rhs.l)?,
81 })
82 }
83
84 #[inline(always)]
88 pub(crate) fn fwd(self, char: char) -> Self {
89 Self {
90 b: self.b + char.len_utf8() as u32,
91 c: self.c + 1,
92 l: self.l + (char == '\n') as u32,
93 }
94 }
95
96 #[inline(always)]
98 pub(crate) fn rev(self, char: char) -> Self {
99 Self {
100 b: self.b - char.len_utf8() as u32,
101 c: self.c - 1,
102 l: self.l - (char == '\n') as u32,
103 }
104 }
105
106 pub(crate) fn shift_by(self, [b, c, l]: [i32; 3]) -> Self {
110 Self {
111 b: (self.b as i32 + b) as u32,
112 c: (self.c as i32 + c) as u32,
113 l: (self.l as i32 + l) as u32,
114 }
115 }
116}
117
118impl std::fmt::Debug for Point {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 write!(f, "Point {{ b: {}, c: {}, l: {} }}", self.b, self.c, self.l)
121 }
122}
123
124impl std::fmt::Display for Point {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 write!(f, "{}, {}, {}", self.b, self.c, self.l)
127 }
128}
129
130impl std::ops::Add for Point {
131 type Output = Self;
132
133 fn add(self, rhs: Self) -> Self::Output {
134 Self {
135 b: self.b + rhs.b,
136 c: self.c + rhs.c,
137 l: self.l + rhs.l,
138 }
139 }
140}
141
142impl std::ops::AddAssign for Point {
143 fn add_assign(&mut self, rhs: Self) {
144 *self = *self + rhs;
145 }
146}
147
148impl std::ops::Sub for Point {
149 type Output = Self;
150
151 fn sub(self, rhs: Self) -> Self::Output {
152 Self {
153 b: self.b - rhs.b,
154 c: self.c - rhs.c,
155 l: self.l - rhs.l,
156 }
157 }
158}
159
160impl std::ops::SubAssign for Point {
161 fn sub_assign(&mut self, rhs: Self) {
162 *self = *self - rhs;
163 }
164}
165
166#[inline]
169pub const fn utf8_char_width(b: u8) -> u32 {
170 const UTF8_CHAR_WIDTH: &[u8; 256] = &[
172 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
190
191 UTF8_CHAR_WIDTH[b as usize] as u32
192}
193
194pub trait TextRange: Clone {
206 fn to_range(self, max: usize) -> Range<usize>;
210}
211
212implTextRange!(Range, r, r.start, r.end, r.start.byte(), r.end.byte());
213implTextRange!(
214 RangeInclusive,
215 r,
216 *r.start(),
217 r.end() + 1,
218 r.start().byte(),
219 r.end().byte() + 1
220);
221implTextRange!(RangeTo, r, 0, r.end, 0, r.end.byte());
222implTextRange!(RangeToInclusive, r, 0, r.end, 0, r.end.byte());
223implTextRange!(RangeFrom, r, r.start, MAX, r.start.byte(), MAX);
224
225impl TextRange for RangeFull {
226 fn to_range(self, max: usize) -> Range<usize> {
227 0..max
228 }
229}
230
231pub trait TextRangeOrPoint {
242 fn to_range(self, max: usize) -> Range<usize>;
244}
245
246impl TextRangeOrPoint for usize {
247 fn to_range(self, max: usize) -> Range<usize> {
248 max.min(self)..max.min(self + 1)
249 }
250}
251
252impl TextRangeOrPoint for Point {
253 fn to_range(self, max: usize) -> Range<usize> {
254 max.min(self.byte())..max.min(self.byte() + 1)
255 }
256}
257
258impl TextRangeOrPoint for RangeFull {
259 fn to_range(self, max: usize) -> Range<usize> {
260 TextRange::to_range(self, max)
261 }
262}
263
264implTextRangeOrPoint!(Range);
265implTextRangeOrPoint!(RangeInclusive);
266implTextRangeOrPoint!(RangeTo);
267implTextRangeOrPoint!(RangeToInclusive);
268implTextRangeOrPoint!(RangeFrom);
269
270pub trait TwoPoints: Clone + Copy {
280 fn to_points(self) -> (Point, Option<Point>);
282}
283
284impl TwoPoints for Point {
285 fn to_points(self) -> (Point, Option<Point>) {
286 (self, None)
287 }
288}
289
290impl TwoPoints for (Point, Point) {
291 fn to_points(self) -> (Point, Option<Point>) {
292 (self.0, Some(self.1))
293 }
294}
295
296impl TwoPoints for (Point, Option<Point>) {
297 fn to_points(self) -> (Point, Option<Point>) {
298 self
299 }
300}
301
302impl TwoPoints for Item {
303 fn to_points(self) -> (Point, Option<Point>) {
304 (self.real, self.ghost)
305 }
306}
307
308const MAX: usize = usize::MAX;
309
310macro implTextRange($range:ident, $r:ident, $sb:expr, $eb:expr, $sp:expr, $ep:expr) {
311 impl TextRange for $range<usize> {
312 fn to_range(self, max: usize) -> Range<usize> {
313 let $r = self;
314 max.min($sb)..max.min($eb)
315 }
316 }
317
318 impl TextRange for $range<Point> {
319 fn to_range(self, max: usize) -> Range<usize> {
320 let $r = self;
321 max.min($sp)..max.min($ep)
322 }
323 }
324}
325
326macro implTextRangeOrPoint($range:ident) {
327 impl TextRangeOrPoint for $range<usize> {
328 fn to_range(self, max: usize) -> Range<usize> {
329 TextRange::to_range(self, max)
330 }
331 }
332
333 impl TextRangeOrPoint for $range<Point> {
334 fn to_range(self, max: usize) -> Range<usize> {
335 TextRange::to_range(self, max)
336 }
337 }
338}