1 //! Missing batteries for standard libraries.
3 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
5 use std
::process
::Command
;
6 use std
::{cmp::Ordering, ops, time::Instant}
;
7 use std
::{io as sio, iter}
;
11 pub mod panic_context
;
12 pub mod non_empty_vec
;
14 pub use always_assert
::{always, never}
;
17 pub fn is_ci() -> bool
{
18 option_env
!("CI").is_some()
22 pub fn timeit(label
: &'
static str) -> impl Drop
{
23 let start
= Instant
::now();
24 defer(move || eprintln
!("{}: {:.2?}", label
, start
.elapsed()))
27 /// Prints backtrace to stderr, useful for debugging.
28 pub fn print_backtrace() {
29 #[cfg(feature = "backtrace")]
30 eprintln
!("{:?}", backtrace
::Backtrace
::new());
32 #[cfg(not(feature = "backtrace"))]
34 r
#"Enable the backtrace feature.
35 Uncomment `default = [ "backtrace" ]` in `crates/stdx/Cargo.toml`.
40 pub fn to_lower_snake_case(s
: &str) -> String
{
41 to_snake_case(s
, char::to_ascii_lowercase
)
43 pub fn to_upper_snake_case(s
: &str) -> String
{
44 to_snake_case(s
, char::to_ascii_uppercase
)
47 // Code partially taken from rust/compiler/rustc_lint/src/nonstandard_style.rs
49 fn to_snake_case
<F
: Fn(&char) -> char>(mut s
: &str, change_case
: F
) -> String
{
50 let mut words
= vec
![];
52 // Preserve leading underscores
53 s
= s
.trim_start_matches(|c
: char| {
55 words
.push(String
::new());
62 for s
in s
.split('_'
) {
63 let mut last_upper
= false;
64 let mut buf
= String
::new();
71 if !buf
.is_empty() && buf
!= "'" && ch
.is_uppercase() && !last_upper
{
76 last_upper
= ch
.is_uppercase();
77 buf
.extend(iter
::once(change_case(&ch
)));
86 pub fn replace(buf
: &mut String
, from
: char, to
: &str) {
87 if !buf
.contains(from
) {
90 // FIXME: do this in place.
91 *buf
= buf
.replace(from
, to
);
94 pub fn trim_indent(mut text
: &str) -> String
{
95 if text
.starts_with('
\n'
) {
100 .filter(|it
| !it
.trim().is_empty())
101 .map(|it
| it
.len() - it
.trim_start().len())
104 text
.split_inclusive('
\n'
)
107 if line
.len() <= indent
{
108 line
.trim_start_matches(' '
)
117 pub fn equal_range_by
<T
, F
>(slice
: &[T
], mut key
: F
) -> ops
::Range
<usize>
119 F
: FnMut(&T
) -> Ordering
,
121 let start
= slice
.partition_point(|it
| key(it
) == Ordering
::Less
);
122 let len
= slice
[start
..].partition_point(|it
| key(it
) == Ordering
::Equal
);
127 pub fn defer
<F
: FnOnce()>(f
: F
) -> impl Drop
{
128 struct D
<F
: FnOnce()>(Option
<F
>);
129 impl<F
: FnOnce()> Drop
for D
<F
> {
131 if let Some(f
) = self.0.take() {
139 /// A [`std::process::Child`] wrapper that will kill the child on drop.
140 #[cfg_attr(not(target_arch = "wasm32"), repr(transparent))]
142 pub struct JodChild(pub std
::process
::Child
);
144 impl ops
::Deref
for JodChild
{
145 type Target
= std
::process
::Child
;
146 fn deref(&self) -> &std
::process
::Child
{
151 impl ops
::DerefMut
for JodChild
{
152 fn deref_mut(&mut self) -> &mut std
::process
::Child
{
157 impl Drop
for JodChild
{
159 let _
= self.0.kill();
160 let _
= self.0.wait();
165 pub fn spawn(mut command
: Command
) -> sio
::Result
<Self> {
166 command
.spawn().map(Self)
169 pub fn into_inner(self) -> std
::process
::Child
{
170 if cfg
!(target_arch
= "wasm32") {
171 panic
!("no processes on wasm");
173 // SAFETY: repr transparent, except on WASM
174 unsafe { std::mem::transmute::<JodChild, std::process::Child>(self) }
178 // feature: iter_order_by
180 pub fn iter_eq_by
<I
, I2
, F
>(this
: I2
, other
: I
, mut eq
: F
) -> bool
184 F
: FnMut(I2
::Item
, I
::Item
) -> bool
,
186 let mut other
= other
.into_iter();
187 let mut this
= this
.into_iter();
190 let x
= match this
.next() {
191 None
=> return other
.next().is_none(),
195 let y
= match other
.next() {
196 None
=> return false,
206 /// Returns all final segments of the argument, longest first.
207 pub fn slice_tails
<T
>(this
: &[T
]) -> impl Iterator
<Item
= &[T
]> {
208 (0..this
.len()).map(|i
| &this
[i
..])
216 fn test_trim_indent() {
217 assert_eq
!(trim_indent(""), "");
235 assert_eq
!(trim_indent(" hello\n world\n"), "hello\nworld\n");
244 "fn main() {\n return 92;\n}\n"