aboutsummaryrefslogtreecommitdiff
path: root/crates/stdx/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/stdx/src/lib.rs')
-rw-r--r--crates/stdx/src/lib.rs78
1 files changed, 3 insertions, 75 deletions
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 1b6211044..340fcacfa 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -65,20 +65,6 @@ pub fn replace(buf: &mut String, from: char, to: &str) {
65 *buf = buf.replace(from, to) 65 *buf = buf.replace(from, to)
66} 66}
67 67
68// https://github.com/rust-lang/rust/issues/74773
69pub fn split_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
70 let mut split = haystack.splitn(2, delim);
71 let prefix = split.next()?;
72 let suffix = split.next()?;
73 Some((prefix, suffix))
74}
75pub fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
76 let mut split = haystack.rsplitn(2, delim);
77 let suffix = split.next()?;
78 let prefix = split.next()?;
79 Some((prefix, suffix))
80}
81
82pub fn trim_indent(mut text: &str) -> String { 68pub fn trim_indent(mut text: &str) -> String {
83 if text.starts_with('\n') { 69 if text.starts_with('\n') {
84 text = &text[1..]; 70 text = &text[1..];
@@ -89,7 +75,7 @@ pub fn trim_indent(mut text: &str) -> String {
89 .map(|it| it.len() - it.trim_start().len()) 75 .map(|it| it.len() - it.trim_start().len())
90 .min() 76 .min()
91 .unwrap_or(0); 77 .unwrap_or(0);
92 lines_with_ends(text) 78 text.split_inclusive('\n')
93 .map( 79 .map(
94 |line| { 80 |line| {
95 if line.len() <= indent { 81 if line.len() <= indent {
@@ -102,70 +88,12 @@ pub fn trim_indent(mut text: &str) -> String {
102 .collect() 88 .collect()
103} 89}
104 90
105pub fn lines_with_ends(text: &str) -> LinesWithEnds {
106 LinesWithEnds { text }
107}
108
109pub struct LinesWithEnds<'a> {
110 text: &'a str,
111}
112
113impl<'a> Iterator for LinesWithEnds<'a> {
114 type Item = &'a str;
115 fn next(&mut self) -> Option<&'a str> {
116 if self.text.is_empty() {
117 return None;
118 }
119 let idx = self.text.find('\n').map_or(self.text.len(), |it| it + 1);
120 let (res, next) = self.text.split_at(idx);
121 self.text = next;
122 Some(res)
123 }
124}
125
126/// Returns `idx` such that:
127///
128/// ```text
129/// ∀ x in slice[..idx]: pred(x)
130/// && ∀ x in slice[idx..]: !pred(x)
131/// ```
132///
133/// https://github.com/rust-lang/rust/issues/73831
134pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize
135where
136 P: FnMut(&T) -> bool,
137{
138 let mut left = 0;
139 let mut right = slice.len();
140
141 while left != right {
142 let mid = left + (right - left) / 2;
143 // SAFETY:
144 // When left < right, left <= mid < right.
145 // Therefore left always increases and right always decreases,
146 // and either of them is selected.
147 // In both cases left <= right is satisfied.
148 // Therefore if left < right in a step,
149 // left <= right is satisfied in the next step.
150 // Therefore as long as left != right, 0 <= left < right <= len is satisfied
151 // and if this case 0 <= mid < len is satisfied too.
152 let value = unsafe { slice.get_unchecked(mid) };
153 if pred(value) {
154 left = mid + 1;
155 } else {
156 right = mid;
157 }
158 }
159
160 left
161}
162
163pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize> 91pub fn equal_range_by<T, F>(slice: &[T], mut key: F) -> ops::Range<usize>
164where 92where
165 F: FnMut(&T) -> Ordering, 93 F: FnMut(&T) -> Ordering,
166{ 94{
167 let start = partition_point(slice, |it| key(it) == Ordering::Less); 95 let start = slice.partition_point(|it| key(it) == Ordering::Less);
168 let len = partition_point(&slice[start..], |it| key(it) == Ordering::Equal); 96 let len = slice[start..].partition_point(|it| key(it) == Ordering::Equal);
169 start..start + len 97 start..start + len
170} 98}
171 99