diff options
Diffstat (limited to 'src/util')
| -rw-r--r-- | src/util/bytes.rs | 59 | ||||
| -rw-r--r-- | src/util/fat.rs | 55 | ||||
| -rw-r--r-- | src/util/mod.rs | 268 |
3 files changed, 0 insertions, 382 deletions
diff --git a/src/util/bytes.rs b/src/util/bytes.rs deleted file mode 100644 index 9165467b..00000000 --- a/src/util/bytes.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::borrow::Cow; -use std::fmt::{self, Debug, Formatter}; -use std::ops::Deref; -use std::sync::Arc; - -use comemo::Prehashed; - -/// A shared byte buffer that is cheap to clone and hash. -#[derive(Clone, Hash, Eq, PartialEq)] -pub struct Bytes(Arc<Prehashed<Cow<'static, [u8]>>>); - -impl Bytes { - /// Create a buffer from a static byte slice. - pub fn from_static(slice: &'static [u8]) -> Self { - Self(Arc::new(Prehashed::new(Cow::Borrowed(slice)))) - } - - /// Return a view into the buffer. - pub fn as_slice(&self) -> &[u8] { - self - } - - /// Return a copy of the buffer as a vector. - pub fn to_vec(&self) -> Vec<u8> { - self.0.to_vec() - } -} - -impl From<&[u8]> for Bytes { - fn from(slice: &[u8]) -> Self { - Self(Arc::new(Prehashed::new(slice.to_vec().into()))) - } -} - -impl From<Vec<u8>> for Bytes { - fn from(vec: Vec<u8>) -> Self { - Self(Arc::new(Prehashed::new(vec.into()))) - } -} - -impl Deref for Bytes { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl AsRef<[u8]> for Bytes { - fn as_ref(&self) -> &[u8] { - self - } -} - -impl Debug for Bytes { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "bytes({})", self.len()) - } -} diff --git a/src/util/fat.rs b/src/util/fat.rs deleted file mode 100644 index d3c9bb20..00000000 --- a/src/util/fat.rs +++ /dev/null @@ -1,55 +0,0 @@ -//! Fat pointer handling. -//! -//! This assumes the memory representation of fat pointers. Although it is not -//! guaranteed by Rust, it's improbable that it will change. Still, when the -//! pointer metadata APIs are stable, we should definitely move to them: -//! <https://github.com/rust-lang/rust/issues/81513> - -use std::alloc::Layout; -use std::mem; - -/// Create a fat pointer from a data address and a vtable address. -/// -/// # Safety -/// Must only be called when `T` is a `dyn Trait`. The data address must point -/// to a value whose type implements the trait of `T` and the `vtable` must have -/// been extracted with [`vtable`]. -#[track_caller] -pub unsafe fn from_raw_parts<T: ?Sized>(data: *const (), vtable: *const ()) -> *const T { - let fat = FatPointer { data, vtable }; - debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>()); - mem::transmute_copy::<FatPointer, *const T>(&fat) -} - -/// Create a mutable fat pointer from a data address and a vtable address. -/// -/// # Safety -/// Must only be called when `T` is a `dyn Trait`. The data address must point -/// to a value whose type implements the trait of `T` and the `vtable` must have -/// been extracted with [`vtable`]. -#[track_caller] -pub unsafe fn from_raw_parts_mut<T: ?Sized>(data: *mut (), vtable: *const ()) -> *mut T { - let fat = FatPointer { data, vtable }; - debug_assert_eq!(Layout::new::<*mut T>(), Layout::new::<FatPointer>()); - mem::transmute_copy::<FatPointer, *mut T>(&fat) -} - -/// Extract the address to a trait object's vtable. -/// -/// # Safety -/// Must only be called when `T` is a `dyn Trait`. -#[track_caller] -pub unsafe fn vtable<T: ?Sized>(ptr: *const T) -> *const () { - debug_assert_eq!(Layout::new::<*const T>(), Layout::new::<FatPointer>()); - mem::transmute_copy::<*const T, FatPointer>(&ptr).vtable -} - -/// The memory representation of a trait object pointer. -/// -/// Although this is not guaranteed by Rust, it's improbable that it will -/// change. -#[repr(C)] -struct FatPointer { - data: *const (), - vtable: *const (), -} diff --git a/src/util/mod.rs b/src/util/mod.rs deleted file mode 100644 index 05914b04..00000000 --- a/src/util/mod.rs +++ /dev/null @@ -1,268 +0,0 @@ -//! Utilities. - -pub mod fat; - -mod bytes; - -pub use bytes::Bytes; - -use std::fmt::{self, Debug, Formatter}; -use std::hash::Hash; -use std::num::NonZeroUsize; -use std::path::{Component, Path, PathBuf}; -use std::sync::Arc; - -use siphasher::sip128::{Hasher128, SipHasher13}; - -/// Turn a closure into a struct implementing [`Debug`]. -pub fn debug<F>(f: F) -> impl Debug -where - F: Fn(&mut Formatter) -> fmt::Result, -{ - struct Wrapper<F>(F); - - impl<F> Debug for Wrapper<F> - where - F: Fn(&mut Formatter) -> fmt::Result, - { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - self.0(f) - } - } - - Wrapper(f) -} - -/// Calculate a 128-bit siphash of a value. -pub fn hash128<T: Hash + ?Sized>(value: &T) -> u128 { - let mut state = SipHasher13::new(); - value.hash(&mut state); - state.finish128().as_u128() -} - -/// An extra constant for [`NonZeroUsize`]. -pub trait NonZeroExt { - /// The number `1`. - const ONE: Self; -} - -impl NonZeroExt for NonZeroUsize { - const ONE: Self = match Self::new(1) { - Some(v) => v, - None => unreachable!(), - }; -} - -/// Extra methods for [`str`]. -pub trait StrExt { - /// The number of code units this string would use if it was encoded in - /// UTF16. This runs in linear time. - fn len_utf16(&self) -> usize; -} - -impl StrExt for str { - fn len_utf16(&self) -> usize { - self.chars().map(char::len_utf16).sum() - } -} - -/// Extra methods for [`Arc`]. -pub trait ArcExt<T> { - /// Takes the inner value if there is exactly one strong reference and - /// clones it otherwise. - fn take(self) -> T; -} - -impl<T: Clone> ArcExt<T> for Arc<T> { - fn take(self) -> T { - match Arc::try_unwrap(self) { - Ok(v) => v, - Err(rc) => (*rc).clone(), - } - } -} - -/// Extra methods for [`[T]`](slice). -pub trait SliceExt<T> { - /// Split a slice into consecutive runs with the same key and yield for - /// each such run the key and the slice of elements with that key. - fn group_by_key<K, F>(&self, f: F) -> GroupByKey<'_, T, F> - where - F: FnMut(&T) -> K, - K: PartialEq; -} - -impl<T> SliceExt<T> for [T] { - fn group_by_key<K, F>(&self, f: F) -> GroupByKey<'_, T, F> { - GroupByKey { slice: self, f } - } -} - -/// This struct is created by [`SliceExt::group_by_key`]. -pub struct GroupByKey<'a, T, F> { - slice: &'a [T], - f: F, -} - -impl<'a, T, K, F> Iterator for GroupByKey<'a, T, F> -where - F: FnMut(&T) -> K, - K: PartialEq, -{ - type Item = (K, &'a [T]); - - fn next(&mut self) -> Option<Self::Item> { - let mut iter = self.slice.iter(); - let key = (self.f)(iter.next()?); - let count = 1 + iter.take_while(|t| (self.f)(t) == key).count(); - let (head, tail) = self.slice.split_at(count); - self.slice = tail; - Some((key, head)) - } -} - -/// Extra methods for [`Path`]. -pub trait PathExt { - /// Lexically normalize a path. - fn normalize(&self) -> PathBuf; - - /// Treat `self` as a virtual root relative to which the `path` is resolved. - /// - /// Returns `None` if the path lexically escapes the root. The path - /// might still escape through symlinks. - fn join_rooted(&self, path: &Path) -> Option<PathBuf>; -} - -impl PathExt for Path { - fn normalize(&self) -> PathBuf { - let mut out = PathBuf::new(); - for component in self.components() { - match component { - Component::CurDir => {} - Component::ParentDir => match out.components().next_back() { - Some(Component::Normal(_)) => { - out.pop(); - } - _ => out.push(component), - }, - Component::Prefix(_) | Component::RootDir | Component::Normal(_) => { - out.push(component) - } - } - } - if out.as_os_str().is_empty() { - out.push(Component::CurDir); - } - out - } - - fn join_rooted(&self, path: &Path) -> Option<PathBuf> { - let mut parts: Vec<_> = self.components().collect(); - let root = parts.len(); - for component in path.components() { - match component { - Component::Prefix(_) => return None, - Component::RootDir => parts.truncate(root), - Component::CurDir => {} - Component::ParentDir => { - if parts.len() <= root { - return None; - } - parts.pop(); - } - Component::Normal(_) => parts.push(component), - } - } - if parts.len() < root { - return None; - } - Some(parts.into_iter().collect()) - } -} - -/// Format pieces separated with commas and a final "and" or "or". -pub fn separated_list(pieces: &[impl AsRef<str>], last: &str) -> String { - let mut buf = String::new(); - for (i, part) in pieces.iter().enumerate() { - match i { - 0 => {} - 1 if pieces.len() == 2 => { - buf.push(' '); - buf.push_str(last); - buf.push(' '); - } - i if i + 1 == pieces.len() => { - buf.push_str(", "); - buf.push_str(last); - buf.push(' '); - } - _ => buf.push_str(", "), - } - buf.push_str(part.as_ref()); - } - buf -} - -/// Format a comma-separated list. -/// -/// Tries to format horizontally, but falls back to vertical formatting if the -/// pieces are too long. -pub fn pretty_comma_list(pieces: &[impl AsRef<str>], trailing_comma: bool) -> String { - const MAX_WIDTH: usize = 50; - - let mut buf = String::new(); - let len = pieces.iter().map(|s| s.as_ref().len()).sum::<usize>() - + 2 * pieces.len().saturating_sub(1); - - if len <= MAX_WIDTH { - for (i, piece) in pieces.iter().enumerate() { - if i > 0 { - buf.push_str(", "); - } - buf.push_str(piece.as_ref()); - } - if trailing_comma { - buf.push(','); - } - } else { - for piece in pieces { - buf.push_str(piece.as_ref().trim()); - buf.push_str(",\n"); - } - } - - buf -} - -/// Format an array-like construct. -/// -/// Tries to format horizontally, but falls back to vertical formatting if the -/// pieces are too long. -pub fn pretty_array_like(parts: &[impl AsRef<str>], trailing_comma: bool) -> String { - let list = pretty_comma_list(parts, trailing_comma); - let mut buf = String::new(); - buf.push('('); - if list.contains('\n') { - buf.push('\n'); - for (i, line) in list.lines().enumerate() { - if i > 0 { - buf.push('\n'); - } - buf.push_str(" "); - buf.push_str(line); - } - buf.push('\n'); - } else { - buf.push_str(&list); - } - buf.push(')'); - buf -} - -/// Check if the [`Option`]-wrapped L is same to R. -pub fn option_eq<L, R>(left: Option<L>, other: R) -> bool -where - L: PartialEq<R>, -{ - left.map(|v| v == other).unwrap_or(false) -} |
