utils.rs
169 lines
| 4.0 KiB
| application/rls-services+xml
|
RustLexer
Raphaël Gomès
|
r42996 | // utils module | ||
// | ||||
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | ||||
// | ||||
// This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | ||||
//! Contains useful functions, traits, structs, etc. for use in core. | ||||
Raphaël Gomès
|
r44740 | use crate::utils::hg_path::HgPath; | ||
use std::{io::Write, ops::Deref}; | ||||
Raphaël Gomès
|
r42828 | pub mod files; | ||
Raphaël Gomès
|
r43226 | pub mod hg_path; | ||
Raphaël Gomès
|
r44737 | pub mod path_auditor; | ||
Raphaël Gomès
|
r42828 | |||
Raphaël Gomès
|
r44538 | /// Useful until rust/issues/56345 is stable | ||
/// | ||||
/// # Examples | ||||
/// | ||||
/// ``` | ||||
/// use crate::hg::utils::find_slice_in_slice; | ||||
/// | ||||
/// let haystack = b"This is the haystack".to_vec(); | ||||
/// assert_eq!(find_slice_in_slice(&haystack, b"the"), Some(8)); | ||||
/// assert_eq!(find_slice_in_slice(&haystack, b"not here"), None); | ||||
/// ``` | ||||
pub fn find_slice_in_slice<T>(slice: &[T], needle: &[T]) -> Option<usize> | ||||
where | ||||
for<'a> &'a [T]: PartialEq, | ||||
{ | ||||
slice | ||||
.windows(needle.len()) | ||||
.position(|window| window == needle) | ||||
} | ||||
Raphaël Gomès
|
r42829 | /// Replaces the `from` slice with the `to` slice inside the `buf` slice. | ||
/// | ||||
/// # Examples | ||||
/// | ||||
/// ``` | ||||
/// use crate::hg::utils::replace_slice; | ||||
/// let mut line = b"I hate writing tests!".to_vec(); | ||||
/// replace_slice(&mut line, b"hate", b"love"); | ||||
/// assert_eq!( | ||||
/// line, | ||||
/// b"I love writing tests!".to_vec() | ||||
Yuya Nishihara
|
r43109 | /// ); | ||
Raphaël Gomès
|
r42829 | /// ``` | ||
Raphaël Gomès
|
r42828 | pub fn replace_slice<T>(buf: &mut [T], from: &[T], to: &[T]) | ||
where | ||||
T: Clone + PartialEq, | ||||
{ | ||||
Raphaël Gomès
|
r42830 | if buf.len() < from.len() || from.len() != to.len() { | ||
Raphaël Gomès
|
r42828 | return; | ||
} | ||||
for i in 0..=buf.len() - from.len() { | ||||
if buf[i..].starts_with(from) { | ||||
buf[i..(i + from.len())].clone_from_slice(to); | ||||
} | ||||
} | ||||
} | ||||
pub trait SliceExt { | ||||
Raphaël Gomès
|
r42829 | fn trim_end(&self) -> &Self; | ||
fn trim_start(&self) -> &Self; | ||||
Raphaël Gomès
|
r42828 | fn trim(&self) -> &Self; | ||
Valentin Gatien-Baron
|
r43129 | fn drop_prefix(&self, needle: &Self) -> Option<&Self>; | ||
Raphaël Gomès
|
r42828 | } | ||
Raphaël Gomès
|
r45500 | #[allow(clippy::trivially_copy_pass_by_ref)] | ||
Raphaël Gomès
|
r42828 | fn is_not_whitespace(c: &u8) -> bool { | ||
!(*c as char).is_whitespace() | ||||
} | ||||
impl SliceExt for [u8] { | ||||
fn trim_end(&self) -> &[u8] { | ||||
if let Some(last) = self.iter().rposition(is_not_whitespace) { | ||||
Raphaël Gomès
|
r45500 | &self[..=last] | ||
Raphaël Gomès
|
r42828 | } else { | ||
&[] | ||||
} | ||||
} | ||||
Raphaël Gomès
|
r42829 | fn trim_start(&self) -> &[u8] { | ||
if let Some(first) = self.iter().position(is_not_whitespace) { | ||||
&self[first..] | ||||
} else { | ||||
&[] | ||||
} | ||||
} | ||||
/// ``` | ||||
/// use hg::utils::SliceExt; | ||||
/// assert_eq!( | ||||
/// b" to trim ".trim(), | ||||
/// b"to trim" | ||||
/// ); | ||||
/// assert_eq!( | ||||
/// b"to trim ".trim(), | ||||
/// b"to trim" | ||||
/// ); | ||||
/// assert_eq!( | ||||
/// b" to trim".trim(), | ||||
/// b"to trim" | ||||
/// ); | ||||
/// ``` | ||||
fn trim(&self) -> &[u8] { | ||||
self.trim_start().trim_end() | ||||
} | ||||
Valentin Gatien-Baron
|
r43129 | |||
fn drop_prefix(&self, needle: &Self) -> Option<&Self> { | ||||
if self.starts_with(needle) { | ||||
Some(&self[needle.len()..]) | ||||
} else { | ||||
None | ||||
} | ||||
} | ||||
Raphaël Gomès
|
r42828 | } | ||
Raphaël Gomès
|
r44740 | |||
pub trait Escaped { | ||||
/// Return bytes escaped for display to the user | ||||
fn escaped_bytes(&self) -> Vec<u8>; | ||||
} | ||||
impl Escaped for u8 { | ||||
fn escaped_bytes(&self) -> Vec<u8> { | ||||
let mut acc = vec![]; | ||||
match self { | ||||
c @ b'\'' | c @ b'\\' => { | ||||
acc.push(b'\\'); | ||||
acc.push(*c); | ||||
} | ||||
b'\t' => { | ||||
acc.extend(br"\\t"); | ||||
} | ||||
b'\n' => { | ||||
acc.extend(br"\\n"); | ||||
} | ||||
b'\r' => { | ||||
acc.extend(br"\\r"); | ||||
} | ||||
c if (*c < b' ' || *c >= 127) => { | ||||
write!(acc, "\\x{:x}", self).unwrap(); | ||||
} | ||||
c => { | ||||
acc.push(*c); | ||||
} | ||||
} | ||||
acc | ||||
} | ||||
} | ||||
impl<'a, T: Escaped> Escaped for &'a [T] { | ||||
fn escaped_bytes(&self) -> Vec<u8> { | ||||
Raphaël Gomès
|
r45500 | self.iter().flat_map(Escaped::escaped_bytes).collect() | ||
Raphaël Gomès
|
r44740 | } | ||
} | ||||
impl<T: Escaped> Escaped for Vec<T> { | ||||
fn escaped_bytes(&self) -> Vec<u8> { | ||||
self.deref().escaped_bytes() | ||||
} | ||||
} | ||||
impl<'a> Escaped for &'a HgPath { | ||||
fn escaped_bytes(&self) -> Vec<u8> { | ||||
self.as_bytes().escaped_bytes() | ||||
} | ||||
} | ||||