diff options
Diffstat (limited to 'crates/stdx')
-rw-r--r-- | crates/stdx/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/stdx/src/lib.rs | 68 | ||||
-rw-r--r-- | crates/stdx/src/macros.rs | 40 |
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" | |||
3 | version = "0.1.0" | 3 | version = "0.1.0" |
4 | authors = ["rust-analyzer developers"] | 4 | authors = ["rust-analyzer developers"] |
5 | edition = "2018" | 5 | edition = "2018" |
6 | license = "MIT OR Apache-2.0" | ||
6 | 7 | ||
7 | [lib] | 8 | [lib] |
8 | doctest = false | 9 | doctest = 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. |
2 | use std::{cell::Cell, fmt, time::Instant}; | 2 | use std::{cell::Cell, fmt, time::Instant}; |
3 | 3 | ||
4 | mod macros; | ||
5 | |||
4 | #[inline(always)] | 6 | #[inline(always)] |
5 | pub fn is_ci() -> bool { | 7 | pub fn is_ci() -> bool { |
6 | option_env!("CI").is_some() | 8 | option_env!("CI").is_some() |
7 | } | 9 | } |
8 | 10 | ||
9 | #[macro_export] | ||
10 | macro_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] | ||
21 | macro_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 | |||
28 | pub trait SepBy: Sized { | 11 | pub 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] | ||
90 | pub fn timeit(label: &'static str) -> impl Drop { | 75 | pub 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 | ||
127 | pub 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)?; | 113 | pub 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 | } | ||
119 | pub 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 | ||
132 | pub fn trim_indent(mut text: &str) -> String { | 126 | pub 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 | ||
171 | pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize | ||
172 | where | ||
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)] |
177 | mod tests { | 201 | mod 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] | ||
3 | macro_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] | ||
14 | macro_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] | ||
23 | macro_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 | } | ||