aboutsummaryrefslogtreecommitdiff
path: root/crates/stdx
diff options
context:
space:
mode:
Diffstat (limited to 'crates/stdx')
-rw-r--r--crates/stdx/Cargo.toml1
-rw-r--r--crates/stdx/src/lib.rs68
-rw-r--r--crates/stdx/src/macros.rs40
3 files changed, 87 insertions, 22 deletions
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index f9e380c10..4c0b85861 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -3,6 +3,7 @@ name = "stdx"
3version = "0.1.0" 3version = "0.1.0"
4authors = ["rust-analyzer developers"] 4authors = ["rust-analyzer developers"]
5edition = "2018" 5edition = "2018"
6license = "MIT OR Apache-2.0"
6 7
7[lib] 8[lib]
8doctest = false 9doctest = false
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::*;
diff --git a/crates/stdx/src/macros.rs b/crates/stdx/src/macros.rs
new file mode 100644
index 000000000..bf298460f
--- /dev/null
+++ b/crates/stdx/src/macros.rs
@@ -0,0 +1,40 @@
1//! Convenience macros.
2#[macro_export]
3macro_rules! eprintln {
4 ($($tt:tt)*) => {{
5 if $crate::is_ci() {
6 panic!("Forgot to remove debug-print?")
7 }
8 std::eprintln!($($tt)*)
9 }}
10}
11
12/// Appends formatted string to a `String`.
13#[macro_export]
14macro_rules! format_to {
15 ($buf:expr) => ();
16 ($buf:expr, $lit:literal $($arg:tt)*) => {
17 { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); }
18 };
19}
20
21// Generates `From` impls for `Enum E { Foo(Foo), Bar(Bar) }` enums
22#[macro_export]
23macro_rules! impl_from {
24 ($($variant:ident $(($($sub_variant:ident),*))?),* for $enum:ident) => {
25 $(
26 impl From<$variant> for $enum {
27 fn from(it: $variant) -> $enum {
28 $enum::$variant(it)
29 }
30 }
31 $($(
32 impl From<$sub_variant> for $enum {
33 fn from(it: $sub_variant) -> $enum {
34 $enum::$variant($variant::$sub_variant(it))
35 }
36 }
37 )*)?
38 )*
39 }
40}