aboutsummaryrefslogtreecommitdiff
path: root/crates/stdx/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/stdx/src')
-rw-r--r--crates/stdx/src/lib.rs111
-rw-r--r--crates/stdx/src/macros.rs40
2 files changed, 131 insertions, 20 deletions
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 71a57fba2..988853ed2 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,31 +1,13 @@
1//! Missing batteries for standard libraries. 1//! Missing batteries for standard libraries.
2
3use std::{cell::Cell, fmt, time::Instant}; 2use std::{cell::Cell, fmt, time::Instant};
4 3
4mod macros;
5
5#[inline(always)] 6#[inline(always)]
6pub fn is_ci() -> bool { 7pub fn is_ci() -> bool {
7 option_env!("CI").is_some() 8 option_env!("CI").is_some()
8} 9}
9 10
10#[macro_export]
11macro_rules! eprintln {
12 ($($tt:tt)*) => {{
13 if $crate::is_ci() {
14 panic!("Forgot to remove debug-print?")
15 }
16 std::eprintln!($($tt)*)
17 }}
18}
19
20/// Appends formatted string to a `String`.
21#[macro_export]
22macro_rules! format_to {
23 ($buf:expr) => ();
24 ($buf:expr, $lit:literal $($arg:tt)*) => {
25 { use ::std::fmt::Write as _; let _ = ::std::write!($buf, $lit $($arg)*); }
26 };
27}
28
29pub trait SepBy: Sized { 11pub trait SepBy: Sized {
30 /// Returns an `impl fmt::Display`, which joins elements via a separator. 12 /// Returns an `impl fmt::Display`, which joins elements via a separator.
31 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>; 13 fn sep_by<'a>(self, sep: &'a str) -> SepByBuilder<'a, Self>;
@@ -88,6 +70,8 @@ where
88 Ok(()) 70 Ok(())
89 } 71 }
90} 72}
73
74#[must_use]
91pub fn timeit(label: &'static str) -> impl Drop { 75pub fn timeit(label: &'static str) -> impl Drop {
92 struct Guard { 76 struct Guard {
93 label: &'static str, 77 label: &'static str,
@@ -124,3 +108,90 @@ pub fn replace(buf: &mut String, from: char, to: &str) {
124 // FIXME: do this in place. 108 // FIXME: do this in place.
125 *buf = buf.replace(from, to) 109 *buf = buf.replace(from, to)
126} 110}
111
112pub fn split_delim(haystack: &str, delim: char) -> Option<(&str, &str)> {
113 let idx = haystack.find(delim)?;
114 Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..]))
115}
116
117pub fn trim_indent(mut text: &str) -> String {
118 if text.starts_with('\n') {
119 text = &text[1..];
120 }
121 let indent = text
122 .lines()
123 .filter(|it| !it.trim().is_empty())
124 .map(|it| it.len() - it.trim_start().len())
125 .min()
126 .unwrap_or(0);
127 lines_with_ends(text)
128 .map(
129 |line| {
130 if line.len() <= indent {
131 line.trim_start_matches(' ')
132 } else {
133 &line[indent..]
134 }
135 },
136 )
137 .collect()
138}
139
140pub fn lines_with_ends(text: &str) -> LinesWithEnds {
141 LinesWithEnds { text }
142}
143
144pub struct LinesWithEnds<'a> {
145 text: &'a str,
146}
147
148impl<'a> Iterator for LinesWithEnds<'a> {
149 type Item = &'a str;
150 fn next(&mut self) -> Option<&'a str> {
151 if self.text.is_empty() {
152 return None;
153 }
154 let idx = self.text.find('\n').map_or(self.text.len(), |it| it + 1);
155 let (res, next) = self.text.split_at(idx);
156 self.text = next;
157 Some(res)
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_trim_indent() {
167 assert_eq!(trim_indent(""), "");
168 assert_eq!(
169 trim_indent(
170 "
171 hello
172 world
173"
174 ),
175 "hello\nworld\n"
176 );
177 assert_eq!(
178 trim_indent(
179 "
180 hello
181 world"
182 ),
183 "hello\nworld"
184 );
185 assert_eq!(trim_indent(" hello\n world\n"), "hello\nworld\n");
186 assert_eq!(
187 trim_indent(
188 "
189 fn main() {
190 return 92;
191 }
192 "
193 ),
194 "fn main() {\n return 92;\n}\n"
195 );
196 }
197}
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}