use std::ops::{Deref, DerefMut};

use ash::vk;
use bytemuck::{Pod, Zeroable};

pub(crate) mod weak_vec {
    //! Module containing the [`WeakVec`] API.

    use std::{sync::Weak, vec::Vec};

    /// An optimized container for `Weak` references of `T` that minimizes reallocations by
    /// dropping older elements that no longer have strong references to them.
    #[derive(Debug)]
    pub(crate) struct WeakVec<T> {
        inner: Vec<Weak<T>>,
    }

    impl<T> Default for WeakVec<T> {
        fn default() -> Self {
            Self {
                inner: Default::default(),
            }
        }
    }

    impl<T> WeakVec<T> {
        pub(crate) fn new() -> Self {
            Self { inner: Vec::new() }
        }

        /// Pushes a new element to this collection.
        ///
        /// If the inner Vec needs to be reallocated, we will first drop older elements that
        /// no longer have strong references to them.
        pub(crate) fn push(&mut self, value: Weak<T>) {
            if self.inner.len() == self.inner.capacity() {
                // Iterating backwards has the advantage that we don't do more work than we have to.
                for i in (0..self.inner.len()).rev() {
                    if self.inner[i].strong_count() == 0 {
                        self.inner.swap_remove(i);
                    }
                }

                // Make sure our capacity is twice the number of live elements.
                // Leaving some spare capacity ensures that we won't re-scan immediately.
                self.inner.reserve_exact(self.inner.len());
            }

            self.inner.push(value);
        }
    }

    pub(crate) struct WeakVecIter<T> {
        inner: std::vec::IntoIter<Weak<T>>,
    }

    impl<T> Iterator for WeakVecIter<T> {
        type Item = Weak<T>;
        fn next(&mut self) -> Option<Self::Item> {
            self.inner.next()
        }
    }

    impl<T> IntoIterator for WeakVec<T> {
        type Item = Weak<T>;
        type IntoIter = WeakVecIter<T>;
        fn into_iter(self) -> Self::IntoIter {
            WeakVecIter {
                inner: self.inner.into_iter(),
            }
        }
    }
}

pub(crate) mod cow_arc {}

#[macro_export]
macro_rules! def_monotonic_id {
    ($vis:vis $ty:ident) => {
        #[derive(Copy, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, Debug)]
        $vis struct $ty(::core::num::NonZero<u32>);

        impl ::core::default::Default for $ty {
            fn default() -> Self {
                Self::new()
            }
        }

        impl $ty {
            #[allow(dead_code, reason = "This method is macro-generated")]
            pub fn new() -> Self {
                use ::core::sync::atomic::{AtomicU32, Ordering};
                static COUNTER: AtomicU32 = AtomicU32::new(1);

                let inner = COUNTER.fetch_add(1, Ordering::Relaxed);
                Self(
                    ::core::num::NonZero::<u32>::new(inner)
                        .expect(&format!("integer overwarp for {}", stringify!($ty))),
                )
            }

            #[allow(dead_code, reason = "This method is macro-generated")]
            pub fn as_u32(&self) -> u32 {
                self.0.get()
            }
        }
    };
}

pub trait MutexExt<'a, T: 'a> {
    type Guard: Deref<Target = T> + 'a;
    fn lock(&'a self) -> Self::Guard;
    fn with_locked<R, F: FnOnce(&T) -> R>(&'a self, f: F) -> R {
        let lock = MutexExt::lock(self);
        f(&*lock)
    }
}

impl<'a, T: 'a> MutexExt<'a, T> for parking_lot::Mutex<T> {
    type Guard = parking_lot::MutexGuard<'a, T>;
    fn lock(&'a self) -> Self::Guard {
        self.lock()
    }
}

#[allow(dead_code)]
pub trait FormatExt {
    fn get_component_kind(&self) -> FormatComponentKind;
    fn is_f32(&self) -> bool;
    fn is_u32(&self) -> bool;
    fn is_i32(&self) -> bool;
}

#[derive(Debug, PartialEq, Eq)]
pub enum FormatComponentKind {
    Float,
    UInt,
    SInt,
}

fn format_to_primitive(format: vk::Format) -> FormatComponentKind {
    use FormatComponentKind::*;
    match format {
        vk::Format::BC6H_SFLOAT_BLOCK => Float,
        vk::Format::D32_SFLOAT => Float,
        vk::Format::R16G16B16A16_SFLOAT => Float,
        vk::Format::R16G16B16_SFLOAT => Float,
        vk::Format::R16G16_SFLOAT => Float,
        vk::Format::R16_SFLOAT => Float,
        vk::Format::R32G32B32A32_SFLOAT => Float,
        vk::Format::R32G32B32_SFLOAT => Float,
        vk::Format::R32G32_SFLOAT => Float,
        vk::Format::R32_SFLOAT => Float,
        vk::Format::R64G64B64A64_SFLOAT => Float,
        vk::Format::R64G64B64_SFLOAT => Float,
        vk::Format::R64G64_SFLOAT => Float,
        vk::Format::R64_SFLOAT => Float,
        vk::Format::D32_SFLOAT_S8_UINT => Float,
        vk::Format::A2B10G10R10_SINT_PACK32 => SInt,
        vk::Format::A2R10G10B10_SINT_PACK32 => SInt,
        vk::Format::A8B8G8R8_SINT_PACK32 => SInt,
        vk::Format::B8G8R8A8_SINT => SInt,
        vk::Format::B8G8R8_SINT => SInt,
        vk::Format::R16G16B16A16_SINT => SInt,
        vk::Format::R16G16B16_SINT => SInt,
        vk::Format::R16G16_SINT => SInt,
        vk::Format::R16_SINT => SInt,
        vk::Format::R32G32B32A32_SINT => SInt,
        vk::Format::R32G32B32_SINT => SInt,
        vk::Format::R32G32_SINT => SInt,
        vk::Format::R32_SINT => SInt,
        vk::Format::R64G64B64A64_SINT => SInt,
        vk::Format::R64G64B64_SINT => SInt,
        vk::Format::R64G64_SINT => SInt,
        vk::Format::R64_SINT => SInt,
        vk::Format::R8G8B8A8_SINT => SInt,
        vk::Format::R8G8B8_SINT => SInt,
        vk::Format::R8G8_SINT => SInt,
        vk::Format::R8_SINT => SInt,
        vk::Format::A2B10G10R10_SNORM_PACK32 => Float,
        vk::Format::A2R10G10B10_SNORM_PACK32 => Float,
        vk::Format::A8B8G8R8_SNORM_PACK32 => Float,
        vk::Format::B8G8R8A8_SNORM => Float,
        vk::Format::B8G8R8_SNORM => Float,
        vk::Format::BC4_SNORM_BLOCK => Float,
        vk::Format::BC5_SNORM_BLOCK => Float,
        vk::Format::EAC_R11G11_SNORM_BLOCK => Float,
        vk::Format::EAC_R11_SNORM_BLOCK => Float,
        vk::Format::R16G16B16A16_SNORM => Float,
        vk::Format::R16G16B16_SNORM => Float,
        vk::Format::R16G16_SNORM => Float,
        vk::Format::R16_SNORM => Float,
        vk::Format::R8G8B8A8_SNORM => Float,
        vk::Format::R8G8B8_SNORM => Float,
        vk::Format::R8G8_SNORM => Float,
        vk::Format::R8_SNORM => Float,
        vk::Format::A8B8G8R8_SRGB_PACK32 => Float,
        vk::Format::ASTC_10X10_SRGB_BLOCK => Float,
        vk::Format::ASTC_10X5_SRGB_BLOCK => Float,
        vk::Format::ASTC_10X6_SRGB_BLOCK => Float,
        vk::Format::ASTC_10X8_SRGB_BLOCK => Float,
        vk::Format::ASTC_12X10_SRGB_BLOCK => Float,
        vk::Format::ASTC_12X12_SRGB_BLOCK => Float,
        vk::Format::ASTC_4X4_SRGB_BLOCK => Float,
        vk::Format::ASTC_5X4_SRGB_BLOCK => Float,
        vk::Format::ASTC_5X5_SRGB_BLOCK => Float,
        vk::Format::ASTC_6X5_SRGB_BLOCK => Float,
        vk::Format::ASTC_6X6_SRGB_BLOCK => Float,
        vk::Format::ASTC_8X5_SRGB_BLOCK => Float,
        vk::Format::ASTC_8X6_SRGB_BLOCK => Float,
        vk::Format::ASTC_8X8_SRGB_BLOCK => Float,
        vk::Format::B8G8R8A8_SRGB => Float,
        vk::Format::B8G8R8_SRGB => Float,
        vk::Format::BC1_RGBA_SRGB_BLOCK => Float,
        vk::Format::BC1_RGB_SRGB_BLOCK => Float,
        vk::Format::BC2_SRGB_BLOCK => Float,
        vk::Format::BC3_SRGB_BLOCK => Float,
        vk::Format::BC7_SRGB_BLOCK => Float,
        vk::Format::ETC2_R8G8B8A1_SRGB_BLOCK => Float,
        vk::Format::ETC2_R8G8B8A8_SRGB_BLOCK => Float,
        vk::Format::ETC2_R8G8B8_SRGB_BLOCK => Float,
        vk::Format::R8G8B8A8_SRGB => Float,
        vk::Format::R8G8B8_SRGB => Float,
        vk::Format::R8G8_SRGB => Float,
        vk::Format::R8_SRGB => Float,
        vk::Format::A2B10G10R10_SSCALED_PACK32 => Float,
        vk::Format::A2R10G10B10_SSCALED_PACK32 => Float,
        vk::Format::A8B8G8R8_SSCALED_PACK32 => Float,
        vk::Format::B8G8R8A8_SSCALED => Float,
        vk::Format::B8G8R8_SSCALED => Float,
        vk::Format::R16G16B16A16_SSCALED => Float,
        vk::Format::R16G16B16_SSCALED => Float,
        vk::Format::R16G16_SSCALED => Float,
        vk::Format::R16_SSCALED => Float,
        vk::Format::R8G8B8A8_SSCALED => Float,
        vk::Format::R8G8B8_SSCALED => Float,
        vk::Format::R8G8_SSCALED => Float,
        vk::Format::R8_SSCALED => Float,
        vk::Format::B10G11R11_UFLOAT_PACK32 => Float,
        vk::Format::BC6H_UFLOAT_BLOCK => Float,
        vk::Format::E5B9G9R9_UFLOAT_PACK32 => Float,
        vk::Format::A2B10G10R10_UINT_PACK32 => UInt,
        vk::Format::A2R10G10B10_UINT_PACK32 => UInt,
        vk::Format::A8B8G8R8_UINT_PACK32 => UInt,
        vk::Format::B8G8R8A8_UINT => UInt,
        vk::Format::B8G8R8_UINT => UInt,
        vk::Format::R16G16B16A16_UINT => UInt,
        vk::Format::R16G16B16_UINT => UInt,
        vk::Format::R16G16_UINT => UInt,
        vk::Format::R16_UINT => UInt,
        vk::Format::R32G32B32A32_UINT => UInt,
        vk::Format::R32G32B32_UINT => UInt,
        vk::Format::R32G32_UINT => UInt,
        vk::Format::R32_UINT => UInt,
        vk::Format::R64G64B64A64_UINT => UInt,
        vk::Format::R64G64B64_UINT => UInt,
        vk::Format::R64G64_UINT => UInt,
        vk::Format::R64_UINT => UInt,
        vk::Format::R8G8B8A8_UINT => UInt,
        vk::Format::R8G8B8_UINT => UInt,
        vk::Format::R8G8_UINT => UInt,
        vk::Format::R8_UINT => UInt,
        vk::Format::S8_UINT => UInt,
        vk::Format::A1R5G5B5_UNORM_PACK16 => Float,
        vk::Format::A2B10G10R10_UNORM_PACK32 => Float,
        vk::Format::A2R10G10B10_UNORM_PACK32 => Float,
        vk::Format::A8B8G8R8_UNORM_PACK32 => Float,
        vk::Format::ASTC_10X10_UNORM_BLOCK => Float,
        vk::Format::ASTC_10X5_UNORM_BLOCK => Float,
        vk::Format::ASTC_10X6_UNORM_BLOCK => Float,
        vk::Format::ASTC_10X8_UNORM_BLOCK => Float,
        vk::Format::ASTC_12X10_UNORM_BLOCK => Float,
        vk::Format::ASTC_12X12_UNORM_BLOCK => Float,
        vk::Format::ASTC_4X4_UNORM_BLOCK => Float,
        vk::Format::ASTC_5X4_UNORM_BLOCK => Float,
        vk::Format::ASTC_5X5_UNORM_BLOCK => Float,
        vk::Format::ASTC_6X5_UNORM_BLOCK => Float,
        vk::Format::ASTC_6X6_UNORM_BLOCK => Float,
        vk::Format::ASTC_8X5_UNORM_BLOCK => Float,
        vk::Format::ASTC_8X6_UNORM_BLOCK => Float,
        vk::Format::ASTC_8X8_UNORM_BLOCK => Float,
        vk::Format::B4G4R4A4_UNORM_PACK16 => Float,
        vk::Format::B5G5R5A1_UNORM_PACK16 => Float,
        vk::Format::B5G6R5_UNORM_PACK16 => Float,
        vk::Format::B8G8R8A8_UNORM => Float,
        vk::Format::B8G8R8_UNORM => Float,
        vk::Format::BC1_RGBA_UNORM_BLOCK => Float,
        vk::Format::BC1_RGB_UNORM_BLOCK => Float,
        vk::Format::BC2_UNORM_BLOCK => Float,
        vk::Format::BC3_UNORM_BLOCK => Float,
        vk::Format::BC4_UNORM_BLOCK => Float,
        vk::Format::BC5_UNORM_BLOCK => Float,
        vk::Format::BC7_UNORM_BLOCK => Float,
        vk::Format::D16_UNORM => Float,
        vk::Format::D16_UNORM_S8_UINT => Float,
        vk::Format::D24_UNORM_S8_UINT => Float,
        vk::Format::EAC_R11G11_UNORM_BLOCK => Float,
        vk::Format::EAC_R11_UNORM_BLOCK => Float,
        vk::Format::ETC2_R8G8B8A1_UNORM_BLOCK => Float,
        vk::Format::ETC2_R8G8B8A8_UNORM_BLOCK => Float,
        vk::Format::ETC2_R8G8B8_UNORM_BLOCK => Float,
        vk::Format::R16G16B16A16_UNORM => Float,
        vk::Format::R16G16B16_UNORM => Float,
        vk::Format::R16G16_UNORM => Float,
        vk::Format::R16_UNORM => Float,
        vk::Format::R4G4B4A4_UNORM_PACK16 => Float,
        vk::Format::R4G4_UNORM_PACK8 => Float,
        vk::Format::R5G5B5A1_UNORM_PACK16 => Float,
        vk::Format::R5G6B5_UNORM_PACK16 => Float,
        vk::Format::R8G8B8A8_UNORM => Float,
        vk::Format::R8G8B8_UNORM => Float,
        vk::Format::R8G8_UNORM => Float,
        vk::Format::R8_UNORM => Float,
        vk::Format::X8_D24_UNORM_PACK32 => Float,
        vk::Format::A2B10G10R10_USCALED_PACK32 => Float,
        vk::Format::A2R10G10B10_USCALED_PACK32 => Float,
        vk::Format::A8B8G8R8_USCALED_PACK32 => Float,
        vk::Format::B8G8R8A8_USCALED => Float,
        vk::Format::B8G8R8_USCALED => Float,
        vk::Format::R16G16B16A16_USCALED => Float,
        vk::Format::R16G16B16_USCALED => Float,
        vk::Format::R16G16_USCALED => Float,
        vk::Format::R16_USCALED => Float,
        vk::Format::R8G8B8A8_USCALED => Float,
        vk::Format::R8G8B8_USCALED => Float,
        vk::Format::R8G8_USCALED => Float,
        vk::Format::R8_USCALED => Float,
        _ => unimplemented!(),
    }
}

impl FormatExt for vk::Format {
    fn get_component_kind(&self) -> FormatComponentKind {
        format_to_primitive(*self)
    }
    fn is_f32(&self) -> bool {
        format_to_primitive(*self) == FormatComponentKind::Float
    }

    fn is_u32(&self) -> bool {
        format_to_primitive(*self) == FormatComponentKind::UInt
    }

    fn is_i32(&self) -> bool {
        format_to_primitive(*self) == FormatComponentKind::SInt
    }
}

#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Rect2D {
    top_left: glam::IVec2,
    bottom_right: glam::IVec2,
}

impl Rect2D {
    pub fn new(left: i32, top: i32, right: i32, bottom: i32) -> Self {
        use glam::ivec2;
        Self {
            top_left: ivec2(left, top),
            bottom_right: ivec2(right, bottom),
        }
    }
    pub fn new_from_size(pos: glam::IVec2, size: glam::IVec2) -> Self {
        Self {
            top_left: pos,
            bottom_right: pos + size,
        }
    }

    pub fn into_offsets_3d(&self) -> [vk::Offset3D; 2] {
        [
            vk::Offset3D {
                x: self.top_left.x,
                y: self.top_left.y,
                z: 0,
            },
            vk::Offset3D {
                x: self.bottom_right.x,
                y: self.bottom_right.y,
                z: 1,
            },
        ]
    }

    #[allow(dead_code)]
    pub fn top_left(&self) -> glam::IVec2 {
        self.top_left
    }
    #[allow(dead_code)]
    pub fn size(&self) -> glam::IVec2 {
        self.bottom_right - self.top_left
    }
    #[allow(dead_code)]
    pub fn width(&self) -> i32 {
        self.bottom_right.x - self.top_left.x
    }
    #[allow(dead_code)]
    pub fn height(&self) -> i32 {
        self.bottom_right.y - self.top_left.y
    }
}

pub fn eq_f32(lhs: f32, rhs: f32) -> bool {
    use core::num::FpCategory::*;
    match (lhs.classify(), rhs.classify()) {
        (Zero, Zero) | (Nan, Nan) => true,
        (Infinite, Infinite) => lhs.signum() == rhs.signum(),
        _ => lhs == rhs,
    }
}
pub fn ord_f32(lhs: f32, rhs: f32) -> core::cmp::Ordering {
    use core::cmp::Ordering;
    use core::num::FpCategory::*;
    match (lhs.classify(), rhs.classify()) {
        (Zero, Zero) | (Nan, Nan) => Ordering::Equal,
        (Infinite, Infinite) => {
            core::cmp::PartialOrd::partial_cmp(&lhs.signum(), &rhs.signum()).unwrap()
        }
        _ => core::cmp::PartialOrd::partial_cmp(&lhs, &rhs).unwrap(),
    }
}

pub fn hash_f32<H: std::hash::Hasher>(state: &mut H, f: f32) {
    use std::hash::Hash;
    let classify = f.classify();
    match classify {
        std::num::FpCategory::Nan => (classify as u8).hash(state),
        std::num::FpCategory::Infinite | std::num::FpCategory::Zero => {
            (classify as u8, f.signum() as i8).hash(state)
        }
        std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => f.to_bits().hash(state),
    }
}

#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct F32(f32);

impl F32 {
    #[inline]
    pub fn from_bits(bits: u32) -> Self {
        Self(f32::from_bits(bits))
    }
    #[inline]
    pub fn into_bits(self) -> u32 {
        self.0.to_bits()
    }
}

impl From<f32> for F32 {
    fn from(value: f32) -> Self {
        Self(value)
    }
}
impl From<F32> for f32 {
    fn from(value: F32) -> Self {
        value.0
    }
}

impl Deref for F32 {
    type Target = f32;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for F32 {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl PartialEq for F32 {
    fn eq(&self, other: &Self) -> bool {
        eq_f32(self.0, other.0)
    }
}

impl Eq for F32 {}

impl PartialOrd for F32 {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(ord_f32(self.0, other.0))
    }
}

impl Ord for F32 {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        ord_f32(self.0, other.0)
    }
}

impl core::hash::Hash for F32 {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        hash_f32(state, self.0)
    }
}

pub fn timed<T, F: FnOnce() -> T>(label: &str, f: F) -> T {
    let now = std::time::Instant::now();
    let out = f();
    tracing::info!("{label}: {}ms", now.elapsed().as_micros() as f32 / 1e3);

    out
}

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct Rgba(pub [f32; 4]);

#[derive(Debug, Clone, Copy, Pod, Zeroable)]
#[repr(transparent)]
pub struct Rgba8(pub [u8; 4]);

impl std::hash::Hash for Rgba {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.0.iter().for_each(|&f| hash_f32(state, f));
    }
}

#[allow(dead_code)]
impl Rgba {
    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
        Self([r, g, b, a])
    }
    pub fn into_u32(&self) -> [u32; 4] {
        self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as u32)
    }
    pub fn into_f32(&self) -> [f32; 4] {
        self.0
    }
    pub fn into_u8(&self) -> Rgba8 {
        Rgba8(self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as u8))
    }
    pub fn into_snorm(&self) -> [f32; 4] {
        self.0.map(|f| (f - 0.5) * 2.0)
    }
    pub fn into_i32(&self) -> [i32; 4] {
        self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as i32 - 128)
    }
}

#[allow(dead_code)]
pub fn image_aspect_from_format(format: vk::Format) -> vk::ImageAspectFlags {
    use vk::{Format, ImageAspectFlags};
    match format {
        Format::D32_SFLOAT | Format::X8_D24_UNORM_PACK32 | Format::D16_UNORM => {
            ImageAspectFlags::DEPTH
        }
        Format::S8_UINT => ImageAspectFlags::STENCIL,
        Format::D32_SFLOAT_S8_UINT | Format::D16_UNORM_S8_UINT | Format::D24_UNORM_S8_UINT => {
            ImageAspectFlags::DEPTH | ImageAspectFlags::STENCIL
        }
        _ => ImageAspectFlags::COLOR,
    }
}

#[repr(transparent)]
pub struct WithLifetime<'a, T>(T, std::marker::PhantomData<&'a ()>);

impl<T> WithLifetime<'_, T> {
    pub fn new(t: T) -> Self {
        Self(t, std::marker::PhantomData)
    }
}

impl<'a, T: 'a> Deref for WithLifetime<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a, T: 'a> DerefMut for WithLifetime<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

bitflags::bitflags! {
    pub struct PipelineAccess: u32 {
        const TRANSFER = 1 << 0;
        const VERTEX_ATTRIBUTE_INPUT = 1 << 1;
        const DRAW_INDIRECT = 1 << 2;
        const VERTEX_INPUT = 1 << 3;
    }
}

#[derive(Debug, Clone)]
pub struct BitIter<'a> {
    bits: &'a [u64],
    num_bits: usize,
    bit_offset: usize,
    bit_index: usize,
}

impl<'a> std::fmt::Display for BitIter<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BitIter")
            .field_with("bits", |f| {
                write!(f, "[")?;
                for bit in self.clone() {
                    write!(f, "{bit}, ")?;
                }
                write!(f, " ]")
            })
            .finish()
    }
}

impl<'a> BitIter<'a> {
    pub fn new(bits: &'a [u64], num_bits: usize) -> Self {
        Self {
            bits,
            num_bits,
            bit_index: 0,
            bit_offset: 0,
        }
    }

    pub fn chunks(self, chunk_size: usize) -> ChunkedBitIter<'a> {
        ChunkedBitIter {
            inner: self,
            chunk_size,
            pos: 0,
        }
    }
}
impl Iterator for BitIter<'_> {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.bit_index >= self.num_bits {
                return None;
            }

            let bit_index = self.bit_index + self.bit_offset;
            let byte_idx = bit_index / 64;
            let byte_offset = bit_index % 64;
            self.bit_index += 1;

            if (self.bits[byte_idx] >> byte_offset) & 1 == 1 {
                return Some(self.bit_index - 1);
            }
        }
    }
}

#[derive(Debug)]
pub struct ChunkedBitIter<'a> {
    inner: BitIter<'a>,
    chunk_size: usize,
    pos: usize,
}

impl<'a> Iterator for ChunkedBitIter<'a> {
    type Item = BitIter<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.pos >= self.inner.num_bits {
            return None;
        }
        let bits = (self.inner.num_bits - self.pos).min(self.chunk_size);

        let iter = BitIter {
            bits: &self.inner.bits[self.pos / 64..],
            bit_offset: self.pos % 64,
            bit_index: 0,
            num_bits: bits,
        };
        self.pos += bits;

        Some(iter)
    }
}

pub struct RawMutexGuard<'a, T> {
    pub(crate) mutex: &'a parking_lot::RawMutex,
    pub(crate) value: &'a T,
    pub(crate) _pd: std::marker::PhantomData<&'a ()>,
}

impl<'a, T> std::ops::Deref for RawMutexGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.value
    }
}

impl<T> Drop for RawMutexGuard<'_, T> {
    fn drop(&mut self) {
        use parking_lot::lock_api::RawMutex;
        unsafe {
            self.mutex.unlock();
        }
    }
}

pub struct CStringList {
    pub strings: Box<[*const i8]>,
    #[allow(unused)]
    bytes: Box<[u8]>,
}

impl CStringList {
    pub fn from_iter<I, S>(i: I) -> CStringList
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        let mut bytes = vec![];
        let mut strings = vec![];
        i.into_iter().for_each(|s| {
            let start = bytes.len();
            bytes.extend_from_slice(s.as_ref().as_bytes());
            bytes.push(0);
            strings.push(start);
        });

        let bytes = bytes.into_boxed_slice();
        Self {
            strings: strings
                .into_iter()
                .map(|offset| unsafe { bytes.as_ptr().offset(offset as isize) as *const i8 })
                .collect(),
            bytes,
        }
    }
}
