//! Extensions use super::*; use std::{ borrow::{ Borrow, ToOwned, }, iter, }; pub trait Tuple2MapExt { fn map(self, fun: F) -> (U, U) where F: FnMut(T) -> U; } impl Tuple2MapExt for (T,T) { fn map(self, mut fun: F) -> (U, U) where F: FnMut(T) -> U { (fun(self.0), fun(self.1)) } } pub trait JitterExt { /// Produce a random value between `self.0` and `self.1` inclusive fn jitter(self) -> T; } impl JitterExt for (T, T) where T: rand::distributions::uniform::SampleUniform { fn jitter(self) -> T { util::jitter(self.0, self.1) } } pub trait Unreference { fn cloned(self) -> Option; } impl<'a, T> Unreference for Option<&'a T> where T: Clone { fn cloned(self) -> Option { self.map(Clone::clone) } } /// An iterator over `char` that maps certain characters to others pub struct CharSubstituteIter<'map, I, T= char> where I: Iterator, { iter: I, map: &'map smallmap::Map, } impl<'a, I, T> Iterator for CharSubstituteIter<'a, I, T> where I: Iterator, T: From + smallmap::Collapse, char: Borrow { type Item = T; fn next(&mut self) -> Option { self.iter.next() .map(|item| self.map.get(&item) .cloned() .map(T::from) .unwrap_or(item)) } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } impl<'a, I, T> DoubleEndedIterator for CharSubstituteIter<'a, I, T> where I: Iterator + DoubleEndedIterator, T: From + smallmap::Collapse, char: Borrow { fn next_back(&mut self) -> Option { self.iter.next_back() .map(|item| self.map.get(&item) .cloned() .map(T::from) .unwrap_or(item)) } } impl<'a, I, T> iter::FusedIterator for CharSubstituteIter<'a, I, T> where I: Iterator + iter::FusedIterator, T: From + smallmap::Collapse, char: Borrow{} impl<'a, I, T> iter::ExactSizeIterator for CharSubstituteIter<'a, I, T> where I: Iterator + ExactSizeIterator, T: From + smallmap::Collapse, char: Borrow{} pub trait CharMapExt: Sized + IntoIterator { /// Creates an iterator that maps chars over this one fn replace_chars(self, map: &smallmap::Map) -> CharSubstituteIter<'_, Self::IntoIter, T>; } impl CharMapExt for S where S: IntoIterator, T: From + smallmap::Collapse, char: Borrow { #[inline] fn replace_chars(self, map: &smallmap::Map) -> CharSubstituteIter<'_, Self::IntoIter, T> { CharSubstituteIter { iter: self.into_iter(), map, } } } /// The ID type used for backing ID types; pub type GenericID = uuid::Uuid; /// Create a type that contains a (globally) unique ID. #[macro_export] macro_rules! id_type { ($name:ident $(: $doc:literal)?) => ($crate::id_type!{pub(self) $name $(: $doc)?}); ($vis:vis $name:ident $(: $doc:literal)?) => { $(#[doc=$doc])? #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)] $vis struct $name($crate::ext::GenericID); impl $name { /// Create a new unique ID. #[inline(always)] fn id_new() -> Self { Self($crate::ext::GenericID::new_v4()) } /// The generic ID type backing this one #[inline(always)] fn id_generic(&self) -> &$crate::ext::GenericID { &self.0 } /// Consume into the generic ID #[inline(always)] fn id_into_generic(self) -> $crate::ext::GenericID { self.0 } /// Create from a generic ID #[inline(always)] fn id_from_generic(gen: $crate::ext::GenericID) -> Self { Self(gen) } } impl ::std::fmt::Display for $name { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { use ::std::fmt::Write; f.write_str(concat!(stringify!($name),"<"))?; self.0.fmt(f)?; f.write_str(">") } } } } /// Expands to `unreachable_unchecked` in non-debug builds. /// /// # Safety /// You must make 100% sure this code path will never be entered, or it will cause undefined behaviour in release builds. #[macro_export] macro_rules! debug_unreachable { () => { if cfg!(debug_assertions) { #[cold] unreachable!() } else { ::std::hint::unreachable_unchecked() } }; } /// Dirty debugging macro to get the compiler to print an error message telling you the size of a type. /// ``` /// check_size!((u8, u8)); // Expected ... found one with *2* elements /// ``` /// Can also be used to statically assert the size of a type /// ``` /// # use datse::ext::check_size; /// check_size!(u16 as 2; "u16 should be 2 bytes"); /// ``` #[macro_export] macro_rules! check_size { ($t:ty) => { const _: [(); 0] = [(); ::std::mem::size_of::<$t>()]; }; ($t:ty as $n:literal $(; $msg:literal)?) => { const _: [(); $n] = [(); ::std::mem::size_of::<$t>()]; } } /// Assert the output of a constant boolean expression is `true` at compile time. #[macro_export] macro_rules! static_assert { ($val:expr $(; $msg:literal)?) => { const _: [(); 1] = [(); ($val as bool) as usize]; } } /// Assert a trait is object safe. This will produce a compiler error if the trait is not object safe #[macro_export] macro_rules! assert_object_safe { ($trait:path $(; $msg:literal)?) => { const _:() = { #[cold] fn __assert_object_safe() -> ! { let _: &dyn $trait; unsafe { debug_unreachable!() } } }; } } assert_object_safe!(AsRef; "object safety assertion test"); static_assert!(1+1==2; "static assertion test"); pub trait UnwrapInfallible { fn unwrap_infallible(self) -> T; } impl UnwrapInfallible for Result { /// Unwrap with 0 overhead for values that cannot possibly be `Err`. #[inline(always)] fn unwrap_infallible(self) -> T { match self { Ok(v) => v, #[cold] Err(_) => unsafe { debug_unreachable!() }, } } } #[cfg(nightly)] impl UnwrapInfallible for Result { /// Unwrap with 0 overhead for values that cannot possibly be `Err`. #[inline(always)] fn unwrap_infallible(self) -> T { match self { Ok(v) => v, #[cold] Err(_) => unsafe { debug_unreachable!() }, } } } pub trait UnwrapErrInfallible { fn unwrap_err_infallible(self) -> T; } impl UnwrapErrInfallible for Result { /// Unwrap with 0 overhead for values that cannot possibly be `Ok`. #[inline(always)] fn unwrap_err_infallible(self) -> T { match self { Err(v) => v, #[cold] Ok(_) => unsafe { debug_unreachable!() }, } } } #[cfg(nightly)] impl UnwrapErrInfallible for Result { /// Unwrap with 0 overhead for values that cannot possibly be `Ok`. #[inline(always)] fn unwrap_err_infallible(self) -> T { match self { Err(v) => v, #[cold] Ok(_) => unsafe { debug_unreachable!() }, } } }