1 | use crate::find::find; |
2 | use std::fmt::Debug; |
3 | use std::ops::{self, RangeFrom, RangeFull, RangeTo}; |
4 | |
5 | #[derive (Copy, Clone)] |
6 | pub struct Range<'a> { |
7 | pub doc: &'a [char], |
8 | pub offset: usize, |
9 | pub len: usize, |
10 | } |
11 | |
12 | impl<'a> Range<'a> { |
13 | pub fn empty() -> Self { |
14 | Range { |
15 | doc: &[], |
16 | offset: 0, |
17 | len: 0, |
18 | } |
19 | } |
20 | |
21 | pub fn new(doc: &'a [char], bounds: impl RangeBounds) -> Self { |
22 | let (offset, len) = bounds.index(doc.len()); |
23 | Range { doc, offset, len } |
24 | } |
25 | |
26 | pub fn is_empty(&self) -> bool { |
27 | self.len == 0 |
28 | } |
29 | |
30 | pub fn len_bytes(&self) -> usize { |
31 | self.chars().map(char::len_utf8).sum() |
32 | } |
33 | |
34 | pub fn substring(&self, bounds: impl RangeBounds) -> Self { |
35 | let (offset, len) = bounds.index(self.len); |
36 | Range { |
37 | doc: self.doc, |
38 | offset: self.offset + offset, |
39 | len, |
40 | } |
41 | } |
42 | |
43 | pub fn get(&self, bounds: impl RangeBounds) -> Option<Self> { |
44 | let (offset, len) = bounds.try_index(self.len)?; |
45 | Some(Range { |
46 | doc: self.doc, |
47 | offset: self.offset + offset, |
48 | len, |
49 | }) |
50 | } |
51 | |
52 | pub fn split_at(&self, mid: usize) -> (Self, Self) { |
53 | (self.substring(..mid), self.substring(mid..)) |
54 | } |
55 | |
56 | pub fn chars( |
57 | &self, |
58 | ) -> impl Iterator<Item = char> + DoubleEndedIterator + ExactSizeIterator + 'a { |
59 | slice(*self).iter().copied() |
60 | } |
61 | |
62 | pub fn starts_with(&self, prefix: impl AsRef<[char]>) -> bool { |
63 | slice(*self).starts_with(prefix.as_ref()) |
64 | } |
65 | |
66 | pub fn ends_with(&self, suffix: impl AsRef<[char]>) -> bool { |
67 | slice(*self).ends_with(suffix.as_ref()) |
68 | } |
69 | |
70 | pub fn find(&self, needle: impl AsRef<[char]>) -> Option<usize> { |
71 | find(slice(*self), needle.as_ref()) |
72 | } |
73 | } |
74 | |
75 | pub fn slice(range: Range) -> &[char] { |
76 | if cfg!(debug) |
77 | && rangeOption<&[char]> |
78 | .doc |
79 | .get(index:range.offset..range.offset + range.len) |
80 | .is_none() |
81 | { |
82 | eprintln!( |
83 | "doc= {:?} offset= {} len= {}" , |
84 | range.doc, range.offset, range.len |
85 | ); |
86 | } |
87 | &range.doc[range.offset..range.offset + range.len] |
88 | } |
89 | |
90 | impl AsRef<[char]> for Range<'_> { |
91 | fn as_ref(&self) -> &[char] { |
92 | slice(*self) |
93 | } |
94 | } |
95 | |
96 | pub trait RangeBounds: Sized + Clone + Debug { |
97 | // Returns (offset, len). |
98 | fn try_index(self, len: usize) -> Option<(usize, usize)>; |
99 | fn index(self, len: usize) -> (usize, usize) { |
100 | match self.clone().try_index(len) { |
101 | Some(range: (usize, usize)) => range, |
102 | None => panic!("index out of range, index= {:?}, len= {}" , self, len), |
103 | } |
104 | } |
105 | } |
106 | |
107 | impl RangeBounds for ops::Range<usize> { |
108 | fn try_index(self, len: usize) -> Option<(usize, usize)> { |
109 | if self.start <= self.end && self.end <= len { |
110 | Some((self.start, self.end - self.start)) |
111 | } else { |
112 | None |
113 | } |
114 | } |
115 | } |
116 | |
117 | impl RangeBounds for RangeFrom<usize> { |
118 | fn try_index(self, len: usize) -> Option<(usize, usize)> { |
119 | if self.start <= len { |
120 | Some((self.start, len - self.start)) |
121 | } else { |
122 | None |
123 | } |
124 | } |
125 | } |
126 | |
127 | impl RangeBounds for RangeTo<usize> { |
128 | fn try_index(self, len: usize) -> Option<(usize, usize)> { |
129 | if self.end <= len { |
130 | Some((0, self.end)) |
131 | } else { |
132 | None |
133 | } |
134 | } |
135 | } |
136 | |
137 | impl RangeBounds for RangeFull { |
138 | fn try_index(self, len: usize) -> Option<(usize, usize)> { |
139 | Some((0, len)) |
140 | } |
141 | } |
142 | |