diff options
Diffstat (limited to 'crates/utils/src')
-rw-r--r-- | crates/utils/src/lib.rs | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 248227a..3649666 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -1,6 +1,7 @@ +//! Common utilities. #![no_std] -use core::fmt; +use core::{fmt, mem::size_of}; /// Creates an ad-hoc `Debug` instance. pub fn debug(f: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl fmt::Debug { @@ -14,3 +15,95 @@ pub fn debug(f: impl Fn(&mut fmt::Formatter) -> fmt::Result) -> impl fmt::Debug Debug(f) } + +/// A hint that this branch is unlikely to be called. +#[cold] +#[inline(always)] +fn cold() {} + +/// A hint that `b` is likely to be true. See `core::intrinsics::likely`. +#[inline(always)] +pub fn likely(b: bool) -> bool { + if !b { + cold() + } + b +} + +/// A hint that `b` is likely to be false. See `core::intrinsics::unlikely`. +#[inline(always)] +pub fn unlikely(b: bool) -> bool { + if b { + cold() + } + b +} + +/// A version of `std::dbg` built on top of `log::debug` instead of +/// `std::eprintln`. +/// +/// This code is copied from libstd, and inherits its copyright. +#[macro_export] +macro_rules! dbg { + // NOTE: We cannot use `concat!` to make a static string as a format + // argument of `log::debug!` because the `$expr` expression could be a + // block (`{ .. }`), in which case the format string will be malformed. + () => { + log::debug!("") + }; + ($expr:expr $(,)?) => { + // Use of `match` here is intentional because it affects the lifetimes + // of temporaries - https://stackoverflow.com/a/48732525/1063961 + match $expr { + tmp => { + log::debug!("{} = {:#?}", core::stringify!($expr), &tmp); + tmp + } + } + }; + ($($expr:expr),+ $(,)?) => { + ($($crate::dbg!($expr)),+,) + }; +} + +/// A trait for types that can be converted to from big-endian or little-endian byte slices. +pub trait FromEndianBytes { + /// Converts from a big-endian byte slice. + fn from_big_endian_bytes(bytes: &[u8]) -> Self; + + /// Converts from a little-endian byte slice. + fn from_little_endian_bytes(bytes: &[u8]) -> Self; +} + +macro_rules! impl_FromEndianBytes { + ($($ty:ty),* $(,)?) => { + $(impl FromEndianBytes for $ty { + fn from_big_endian_bytes(bytes: &[u8]) -> $ty { + let chunk = match bytes.last_chunk() { + Some(chunk) => *chunk, + None => { + let mut chunk = [0; size_of::<$ty>()]; + chunk[size_of::<$ty>() - bytes.len()..] + .copy_from_slice(bytes); + chunk + }, + }; + <$ty>::from_be_bytes(chunk) + } + + fn from_little_endian_bytes(bytes: &[u8]) -> $ty { + let chunk = match bytes.first_chunk() { + Some(chunk) => *chunk, + None => { + let mut chunk = [0; size_of::<$ty>()]; + chunk[.. bytes.len()].copy_from_slice(bytes); + chunk + }, + }; + <$ty>::from_le_bytes(chunk) + } + })* + }; +} + +impl_FromEndianBytes!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); |