use std::{ mem, iter::{ self, ExactSizeIterator, FusedIterator, }, slice, fmt, }; pub use std::{ marker::{ Send, Sync, Unpin, }, borrow::{ Borrow, BorrowMut }, convert::{ Infallible, TryFrom, TryInto }, }; pub use tokio::{ io::{ AsyncWriteExt, AsyncReadExt, }, task::JoinHandle, }; /// Make this type act as a reference to itself. /// /// Implements `AsRef` for type `T`. #[macro_export] macro_rules! ref_self { ($type:ty) => { impl AsRef<$type> for $type { #[inline] fn as_ref(&self) -> &$type { self } } } } #[derive(Debug, Clone)] pub struct HexStringIter(I, [u8; 2]); impl> HexStringIter { /// Write this hex string iterator to a formattable buffer pub fn consume(self, f: &mut F) -> fmt::Result where F: std::fmt::Write { if self.1[0] != 0 { write!(f, "{}", self.1[0] as char)?; } if self.1[1] != 0 { write!(f, "{}", self.1[1] as char)?; } for x in self.0 { write!(f, "{:02x}", x)?; } Ok(()) } /// Consume into a string pub fn into_string(self) -> String { let mut output = match self.size_hint() { (0, None) => String::new(), (_, Some(x)) | (x, None) => String::with_capacity(x), }; self.consume(&mut output).unwrap(); output } } pub trait HexStringIterExt: Sized { fn into_hex(self) -> HexStringIter; } pub type HexStringSliceIter<'a> = HexStringIter>>; pub trait HexStringSliceIterExt { fn hex(&self) -> HexStringSliceIter<'_>; } impl HexStringSliceIterExt for S where S: AsRef<[u8]> { fn hex(&self) -> HexStringSliceIter<'_> { self.as_ref().iter().copied().into_hex() } } impl> HexStringIterExt for I { #[inline] fn into_hex(self) -> HexStringIter { HexStringIter(self.into_iter(), [0u8; 2]) } } impl> Iterator for HexStringIter { type Item = char; fn next(&mut self) -> Option { match self.1 { [_, 0] => { use std::io::Write; write!(&mut self.1[..], "{:02x}", self.0.next()?).unwrap(); Some(mem::replace(&mut self.1[0], 0) as char) }, [0, _] => Some(mem::replace(&mut self.1[1], 0) as char), _ => unreachable!(), } } fn size_hint(&self) -> (usize, Option) { let (l, h) = self.0.size_hint(); (l * 2, h.map(|x| x*2)) } } impl + ExactSizeIterator> ExactSizeIterator for HexStringIter{} impl + FusedIterator> FusedIterator for HexStringIter{} impl> From> for String { fn from(from: HexStringIter) -> Self { from.into_string() } } impl + Clone> fmt::Display for HexStringIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.clone().consume(f) } } pub trait CollectArrayExt: Sized { /// Collect an iterator into an array. /// /// If the iterator has more elements than `N`, the rest are discarded. /// /// # Panics /// If the iterator has **less** elements than `N`. fn collect_array(self) -> [T; N]; } impl CollectArrayExt for I where I: Iterator { fn collect_array(self) -> [I::Item; N] { use std::mem::MaybeUninit; // SAFETY: This pattern is safe. The array elements are still maybeuninit. let mut out = unsafe { MaybeUninit::<[MaybeUninit::; N]>::uninit().assume_init() }; let mut init_to = 0; if N == 0 { // SAFETY: This is valid, [I::Item; N] is 0 sized. (i uhh think...) return unsafe { MaybeUninit::<[I::Item; N]>::uninit().assume_init() }; } let res = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { #[cold] #[inline(never)] fn _panic_bad_size(exp: usize, got: usize) -> ! { panic!("tried to collect into array of size {}, when iterator is only {} elements", exp, got) } init_to = out.iter_mut().zip(self) .map(|(o, i)| *o = MaybeUninit::new(i)).count(); match init_to { n if n == N => (), got => _panic_bad_size(N, got), } })); match res { Ok(()) => { // SAFETY: Transmuting MaybeUninit to T is fine. // All elements are initialised by this point unsafe { #[inline(always)] unsafe fn assume_init_array(array: [MaybeUninit; N]) -> [T; N] { //std::intrinsics::assert_inhabited::<[T; N]>(); (&array as *const _ as *const [T; N]).read() } //MaybeUninit::array_assume_init(out) assume_init_array(out) } }, Err(e) => { // Drop all initialised elements before resuming unwind. unsafe { std::ptr::drop_in_place(&mut out[..init_to] as *mut [MaybeUninit] as *mut [I::Item]); } std::panic::resume_unwind(e) }, } } } #[macro_export] macro_rules! prog1 { ($first:expr, $($rest:expr);+ $(;)?) => { ($first, $( $rest ),+).0 } } #[macro_export] macro_rules! r#if { ($if:expr, $then:expr, $else:expr) => { if $if { $then } else { $else } } }