use crate::intern::{Intern, Interned};
use bitvec::{bits, order::Lsb0, slice::BitSlice, view::BitView};
use std::{
fmt::{self, Debug, Write},
rc::Rc,
sync::{Arc, OnceLock},
};
pub fn iter_eq_by<L: IntoIterator, R: IntoIterator, F: FnMut(L::Item, R::Item) -> bool>(
l: L,
r: R,
mut f: F,
) -> bool {
let mut l = l.into_iter();
let mut r = r.into_iter();
l.try_for_each(|l| {
if let Some(r) = r.next() {
f(l, r).then_some(())
} else {
None
}
})
.is_some()
&& r.next().is_none()
}
pub struct DebugAsDisplay<T>(pub T);
impl<T: fmt::Display> fmt::Debug for DebugAsDisplay<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
pub trait MakeMutSlice {
type Element: Clone;
fn make_mut_slice(&mut self) -> &mut [Self::Element];
}
impl<T: Clone> MakeMutSlice for Arc<[T]> {
type Element = T;
fn make_mut_slice(&mut self) -> &mut [Self::Element] {
if Arc::get_mut(self).is_none() {
*self = Arc::<[T]>::from(&**self);
}
Arc::get_mut(self).unwrap()
}
}
impl<T: Clone> MakeMutSlice for Rc<[T]> {
type Element = T;
fn make_mut_slice(&mut self) -> &mut [Self::Element] {
if Rc::get_mut(self).is_none() {
*self = Rc::<[T]>::from(&**self);
}
Rc::get_mut(self).unwrap()
}
}
pub struct DebugAsRawString<'a>(pub &'a str);
impl fmt::Debug for DebugAsRawString<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let pounds = self
.0
.split_inclusive('"')
.skip(1)
.map(|v| v.len() - v.trim_start_matches('#').len())
.max()
.map(|v| v + 1)
.unwrap_or(0);
f.write_char('r')?;
for _ in 0..pounds {
f.write_char('#')?;
}
f.write_char('"')?;
f.write_str(self.0)?;
f.write_char('"')?;
for _ in 0..pounds {
f.write_char('#')?;
}
Ok(())
}
}
pub fn interned_bit(v: bool) -> Interned<BitSlice> {
static RETVAL: OnceLock<[Interned<BitSlice>; 2]> = OnceLock::new();
RETVAL.get_or_init(|| [bits![0; 1].intern(), bits![1; 1].intern()])[v as usize]
}
#[derive(Copy, Clone, Debug)]
pub struct BitSliceWriteWithBase<'a>(pub &'a BitSlice);
impl BitSliceWriteWithBase<'_> {
fn fmt_with_base<const BITS_PER_DIGIT: usize, const UPPER_CASE: bool>(
self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
let digit_count = self.0.len().div_ceil(BITS_PER_DIGIT).max(1);
let mut buf = String::with_capacity(digit_count);
for digit_index in (0..digit_count).rev() {
let mut digit = 0;
let src = self
.0
.get(digit_index * BITS_PER_DIGIT..)
.unwrap_or_default();
let src = src.get(..BITS_PER_DIGIT).unwrap_or(src);
digit.view_bits_mut::<Lsb0>()[..src.len()].copy_from_bitslice(src);
let mut ch = char::from_digit(digit as u32, 1 << BITS_PER_DIGIT).unwrap();
if UPPER_CASE {
ch = ch.to_ascii_uppercase();
}
buf.push(ch);
}
f.pad_integral(
true,
match BITS_PER_DIGIT {
1 => "0b",
3 => "0o",
4 => "0x",
_ => "",
},
&buf,
)
}
}
impl fmt::Binary for BitSliceWriteWithBase<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.fmt_with_base::<1, false>(f)
}
}
impl fmt::Octal for BitSliceWriteWithBase<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.fmt_with_base::<3, false>(f)
}
}
impl fmt::LowerHex for BitSliceWriteWithBase<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.fmt_with_base::<4, false>(f)
}
}
impl fmt::UpperHex for BitSliceWriteWithBase<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.fmt_with_base::<4, true>(f)
}
}