|
|
|
//! Utility functions
|
|
|
|
use std::{
|
|
|
|
borrow::{
|
|
|
|
Borrow,
|
|
|
|
ToOwned,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Copy slice `src` into `dst` and return the number of elements copied.
|
|
|
|
#[inline] pub fn copy_slice<T,U,V,W,X>(mut dst: V, src: W) -> usize
|
|
|
|
where V: AsMut<[T]>,
|
|
|
|
W: AsRef<[U]>,
|
|
|
|
U: ToOwned<Owned=X>,
|
|
|
|
X: Borrow<U> + Into<T>
|
|
|
|
{
|
|
|
|
|
|
|
|
let mut i=0;
|
|
|
|
for (d, s) in dst.as_mut().iter_mut().zip(src.as_ref().iter())
|
|
|
|
{
|
|
|
|
*d = s.to_owned().into();
|
|
|
|
i+=1
|
|
|
|
}
|
|
|
|
i
|
|
|
|
}
|
|
|
|
|
|
|
|
pub mod bytes
|
|
|
|
{
|
|
|
|
/// Copy `src`'s bytes into `dst`, returning the number of bytes copied.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
/// The memory regions must not overlap
|
|
|
|
pub fn copy_slice(dst: &mut [u8], src: &[u8]) -> usize
|
|
|
|
{
|
|
|
|
let sz = std::cmp::min(dst.len(), src.len());
|
|
|
|
if sz != 0 {
|
|
|
|
unsafe {
|
|
|
|
std::ptr::copy_nonoverlapping(&src[0] as *const u8, &mut dst[0] as *mut u8, sz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sz
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Copy `src`'s bytes into `dst`, returning the number of bytes copied.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
/// The memory regions can overlap
|
|
|
|
pub fn move_slice(dst: &mut [u8], src: &[u8]) -> usize
|
|
|
|
{
|
|
|
|
let sz = std::cmp::min(dst.len(), src.len());
|
|
|
|
if sz != 0 {
|
|
|
|
unsafe {
|
|
|
|
std::ptr::copy(&src[0] as *const u8, &mut dst[0] as *mut u8, sz);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sz
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests
|
|
|
|
{
|
|
|
|
#[test]
|
|
|
|
fn copy_slice()
|
|
|
|
{
|
|
|
|
let mut to = [0u8; 40];
|
|
|
|
let from = [10u8; 37];
|
|
|
|
|
|
|
|
assert_eq!(super::copy_slice(&mut to, &from), 37);
|
|
|
|
|
|
|
|
assert_eq!(from, &to[0..37]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait NewWithCap: Sized
|
|
|
|
{
|
|
|
|
fn new() -> Self;
|
|
|
|
fn with_capacity(cap: usize) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> NewWithCap for Vec<T>
|
|
|
|
{
|
|
|
|
#[inline(always)] fn new() -> Self
|
|
|
|
{
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)] fn with_capacity(cap: usize) -> Self
|
|
|
|
{
|
|
|
|
Self::with_capacity(cap)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl NewWithCap for String
|
|
|
|
{
|
|
|
|
#[inline(always)] fn new() -> Self
|
|
|
|
{
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)] fn with_capacity(cap: usize) -> Self
|
|
|
|
{
|
|
|
|
Self::with_capacity(cap)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allocate with capacity based on iterator `size_hint`
|
|
|
|
#[inline] pub fn alloc_iterator_hint<T: NewWithCap, I: Iterator+?Sized>(hint: &I) -> T
|
|
|
|
{
|
|
|
|
match hint.size_hint() {
|
|
|
|
(0, None) | (_, Some(0)) => T::new(),
|
|
|
|
(_, Some(x)) | (x, None) => T::with_capacity(x),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allocate with capacity based on stream `size_hint`
|
|
|
|
#[inline] pub fn alloc_stream_hint<T: NewWithCap, I: futures::stream::Stream+?Sized>(hint: &I) -> T
|
|
|
|
{
|
|
|
|
match hint.size_hint() {
|
|
|
|
(0, None) | (_, Some(0)) => T::new(),
|
|
|
|
(_, Some(x)) | (x, None) => T::with_capacity(x),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Defer an action until drop
|
|
|
|
pub fn defer<F: FnOnce()>(fun: F) -> impl std::ops::Drop
|
|
|
|
{
|
|
|
|
struct DropWrap<F: FnOnce()>(Option<F>);
|
|
|
|
impl<F: FnOnce()> std::ops::Drop for DropWrap<F>
|
|
|
|
{
|
|
|
|
fn drop(&mut self)
|
|
|
|
{
|
|
|
|
self.0.take().map(|x| x());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DropWrap(Some(fun))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Simplification for single expression `if x {y} else {z}`
|
|
|
|
#[macro_export] macro_rules! tern {
|
|
|
|
($if:expr; $then:expr, $else:expr) => (if $if {$then} else {$else});
|
|
|
|
}
|