1 //! Missing batteries for standard libraries.
3 sync::atomic::{AtomicUsize, Ordering},
11 pub fn is_ci() -> bool {
12 option_env!("CI").is_some()
16 pub fn timeit(label: &'static str) -> impl Drop {
24 eprintln!("{}: {:.2?}", self.label, self.start.elapsed())
28 Guard { label, start: Instant::now() }
31 pub fn to_lower_snake_case(s: &str) -> String {
32 let mut buf = String::with_capacity(s.len());
35 // `&& prev` is required to not insert `_` before the first symbol.
36 if c.is_ascii_uppercase() && prev {
37 // This check is required to not translate `Weird_Case` into `weird__case`.
38 if !buf.ends_with('_') {
44 buf.push(c.to_ascii_lowercase());
49 pub fn replace(buf: &mut String, from: char, to: &str) {
50 if !buf.contains(from) {
53 // FIXME: do this in place.
54 *buf = buf.replace(from, to)
57 // https://github.com/rust-lang/rust/issues/74773
58 pub fn split_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
59 let mut split = haystack.splitn(2, delim);
60 let prefix = split.next()?;
61 let suffix = split.next()?;
62 Some((prefix, suffix))
64 pub fn rsplit_once(haystack: &str, delim: char) -> Option<(&str, &str)> {
65 let mut split = haystack.rsplitn(2, delim);
66 let suffix = split.next()?;
67 let prefix = split.next()?;
68 Some((prefix, suffix))
71 pub fn trim_indent(mut text: &str) -> String {
72 if text.starts_with('\n') {
77 .filter(|it| !it.trim().is_empty())
78 .map(|it| it.len() - it.trim_start().len())
84 if line.len() <= indent {
85 line.trim_start_matches(' ')
94 pub fn lines_with_ends(text: &str) -> LinesWithEnds {
95 LinesWithEnds { text }
98 pub struct LinesWithEnds<'a> {
102 impl<'a> Iterator for LinesWithEnds<'a> {
104 fn next(&mut self) -> Option<&'a str> {
105 if self.text.is_empty() {
108 let idx = self.text.find('\n').map_or(self.text.len(), |it| it + 1);
109 let (res, next) = self.text.split_at(idx);
115 // https://github.com/rust-lang/rust/issues/73831
116 pub fn partition_point<T, P>(slice: &[T], mut pred: P) -> usize
118 P: FnMut(&T) -> bool,
121 let mut right = slice.len();
123 while left != right {
124 let mid = left + (right - left) / 2;
126 // When left < right, left <= mid < right.
127 // Therefore left always increases and right always decreases,
128 // and either of them is selected.
129 // In both cases left <= right is satisfied.
130 // Therefore if left < right in a step,
131 // left <= right is satisfied in the next step.
132 // Therefore as long as left != right, 0 <= left < right <= len is satisfied
133 // and if this case 0 <= mid < len is satisfied too.
134 let value = unsafe { slice.get_unchecked(mid) };
145 pub struct RacyFlag(AtomicUsize);
148 pub const fn new() -> RacyFlag {
149 RacyFlag(AtomicUsize::new(!0))
152 pub fn get(&self, init: impl FnMut() -> bool) -> bool {
153 let mut init = Some(init);
154 self.get_impl(&mut || init.take().map_or(false, |mut f| f()))
157 fn get_impl(&self, init: &mut dyn FnMut() -> bool) -> bool {
158 match self.0.load(Ordering::Relaxed) {
163 self.0.store(if res { 1 } else { 0 }, Ordering::Relaxed);
175 fn test_trim_indent() {
176 assert_eq!(trim_indent(""), "");
194 assert_eq!(trim_indent(" hello\n world\n"), "hello\nworld\n");
203 "fn main() {\n return 92;\n}\n"