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.rs68
1 files changed, 46 insertions, 22 deletions
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 08ac6f70f..b65875c96 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,30 +1,13 @@
1//! Missing batteries for standard libraries. 1//! Missing batteries for standard libraries.
2use std::{cell::Cell, fmt, time::Instant}; 2use std::{cell::Cell, fmt, time::Instant};
3 3
4mod macros;
5
4#[inline(always)] 6#[inline(always)]
5pub fn is_ci() -> bool { 7pub fn is_ci() -> bool {
6 option_env!("CI").is_some() 8 option_env!("CI").is_some()
7} 9}
8 10
9#[macro_export]
10macro_rules! eprintln {
11 ($($tt:tt)*) => {{
12 if $crate::is_ci() {
13 panic!("Forgot to remove debug-print?")
14 }
15 std::eprintln!($($tt)*)
16 }}
17}
18
19/// Appends formatted string to a `String`.
20#[macro_export]
21macro_rules! format_to {
22 ($buf:expr) => ();
23 ($buf:expr, $lit:literal $($arg:tt)*) => {
24 { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); }
25 };
26}
27
28pub trait SepBy: Sized { 11pub trait SepBy: Sized {
29 /// Returns an `impl fmt::Display`, which joins elements via a separator. 12 /// Returns an `impl fmt::Display`, which joins elements via a separator.
30 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>; 13 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>;
@@ -87,6 +70,8 @@ where
87 Ok(()) 70 Ok(())
88 } 71 }
89} 72}
73
74#[must_use]
90pub fn timeit(label: &'static str) -> impl Drop { 75pub fn timeit(label: &'static str) -> impl Drop {
91 struct Guard { 76 struct Guard {
92 label: &'static str, 77 label: &'static str,
@@ -124,9 +109,18 @@ pub fn replace(buf: &mut String, from: char, to: &str) {
124 *buf = buf.replace(from, to) 109 *buf = buf.replace(from, to)
125} 110}
126 111
127pub fn split_delim(haystack: &str, delim: char) -> Option<(&str, &str)> { 112// https://github.com/rust-lang/rust/issues/74773
128 let idx = haystack.find(delim)?; 113pub fn split_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
129 Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) 114 let mut split = haystack.splitn(2, delim);
115 let prefix = split.next()?;
116 let suffix = split.next()?;
117 Some((prefix, suffix))
118}
119pub fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
120 let mut split = haystack.rsplitn(2, delim);
121 let suffix = split.next()?;
122 let prefix = split.next()?;
123 Some((prefix, suffix))
130} 124}
131 125
132pub fn trim_indent(mut text: &str) -> String { 126pub fn trim_indent(mut text: &str) -> String {
@@ -173,6 +167,36 @@ impl<'a> Iterator for LinesWithEnds<'a> {
173 } 167 }
174} 168}
175 169
170// https://github.com/rust-lang/rust/issues/73831
171pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize
172where
173 P: FnMut(&T) -> bool,
174{
175 let mut left = 0;
176 let mut right = slice.len();
177
178 while left != right {
179 let mid = left + (right - left) / 2;
180 // SAFETY:
181 // When left < right, left <= mid < right.
182 // Therefore left always increases and right always decreases,
183 // and either of them is selected.
184 // In both cases left <= right is satisfied.
185 // Therefore if left < right in a step,
186 // left <= right is satisfied in the next step.
187 // Therefore as long as left != right, 0 <= left < right <= len is satisfied
188 // and if this case 0 <= mid < len is satisfied too.
189 let value = unsafe { slice.get_unchecked(mid) };
190 if pred(value) {
191 left = mid + 1;
192 } else {
193 right = mid;
194 }
195 }
196
197 left
198}
199
176#[cfg(test)] 200#[cfg(test)]
177mod tests { 201mod tests {
178 use super::*; 202 use super::*;