mod range;
pub(crate) mod write;
use {
    crate::{memory::Memory, util::fits_usize},
    gfx_hal::{Backend, Device as _},
    std::{ops::Range, ptr::NonNull},
};
pub(crate) use self::range::{
    mapped_fitting_range, mapped_slice, mapped_slice_mut, mapped_sub_range,
};
use self::write::{Write, WriteCoherent, WriteFlush};
#[derive(Clone, Copy, Debug)]
pub struct NonCoherent;
#[derive(Clone, Copy, Debug)]
pub struct Coherent;
#[derive(Clone, Copy, Debug)]
pub struct MaybeCoherent(bool);
#[derive(Debug)]
pub struct MappedRange<'a, B: Backend, C = MaybeCoherent> {
    
    memory: &'a Memory<B>,
    
    ptr: NonNull<u8>,
    
    range: Range<u64>,
    
    coherent: C,
}
impl<'a, B> MappedRange<'a, B>
where
    B: Backend,
{
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    pub unsafe fn from_raw(memory: &'a Memory<B>, ptr: NonNull<u8>, range: Range<u64>) -> Self {
        assert!(
            range.start < range.end,
            "Memory mapping region must have valid size"
        );
        MappedRange {
            ptr,
            range,
            memory,
            coherent: MaybeCoherent(memory.host_coherent()),
        }
    }
    
    
    pub fn ptr(&self) -> NonNull<u8> {
        self.ptr
    }
    
    pub fn range(&self) -> Range<u64> {
        self.range.clone()
    }
    
    
    
    
    
    
    
    
    
    pub unsafe fn read<'b, T>(
        &'b mut self,
        device: &B::Device,
        range: Range<u64>,
    ) -> Result<&'b [T], gfx_hal::mapping::Error>
    where
        'a: 'b,
        T: Copy,
    {
        assert!(
            range.start < range.end,
            "Memory mapping region must have valid size"
        );
        assert!(
            fits_usize(range.end - range.start),
            "Range length must fit in usize"
        );
        let (ptr, range) = mapped_sub_range(self.ptr, self.range.clone(), range)
            .ok_or_else(|| gfx_hal::mapping::Error::OutOfBounds)?;
        let size = (range.end - range.start) as usize;
        if self.coherent.0 {
            device
                .invalidate_mapped_memory_ranges(Some((self.memory.raw(), self.range.clone())))?;
        }
        let slice = mapped_slice::<T>(ptr, size);
        Ok(slice)
    }
    
    
    
    
    
    
    pub unsafe fn write<'b, T: 'b>(
        &'b mut self,
        device: &'b B::Device,
        range: Range<u64>,
    ) -> Result<impl Write<T> + 'b, gfx_hal::mapping::Error>
    where
        'a: 'b,
        T: Copy,
    {
        assert!(
            range.start < range.end,
            "Memory mapping region must have valid size"
        );
        assert!(
            fits_usize(range.end - range.start),
            "Range length must fit in usize"
        );
        let (ptr, range) = mapped_sub_range(self.ptr, self.range.clone(), range)
            .ok_or_else(|| gfx_hal::mapping::Error::OutOfBounds)?;
        let size = (range.end - range.start) as usize;
        if !self.coherent.0 {
            device
                .invalidate_mapped_memory_ranges(Some((self.memory.raw(), self.range.clone())))?;
        }
        let slice = mapped_slice_mut::<T>(ptr, size);
        let ref memory = self.memory;
        Ok(WriteFlush {
            slice,
            flush: if !self.coherent.0 {
                Some(move || {
                    device
                        .flush_mapped_memory_ranges(Some((memory.raw(), range)))
                        .expect("Should flush successfully");
                })
            } else {
                None
            },
        })
    }
    
    pub fn coherent(self) -> Result<MappedRange<'a, B, Coherent>, MappedRange<'a, B, NonCoherent>> {
        if self.coherent.0 {
            Ok(MappedRange {
                memory: self.memory,
                ptr: self.ptr,
                range: self.range,
                coherent: Coherent,
            })
        } else {
            Err(MappedRange {
                memory: self.memory,
                ptr: self.ptr,
                range: self.range,
                coherent: NonCoherent,
            })
        }
    }
}
impl<'a, B> From<MappedRange<'a, B, Coherent>> for MappedRange<'a, B>
where
    B: Backend,
{
    fn from(range: MappedRange<'a, B, Coherent>) -> Self {
        MappedRange {
            memory: range.memory,
            ptr: range.ptr,
            range: range.range,
            coherent: MaybeCoherent(true),
        }
    }
}
impl<'a, B> From<MappedRange<'a, B, NonCoherent>> for MappedRange<'a, B>
where
    B: Backend,
{
    fn from(range: MappedRange<'a, B, NonCoherent>) -> Self {
        MappedRange {
            memory: range.memory,
            ptr: range.ptr,
            range: range.range,
            coherent: MaybeCoherent(false),
        }
    }
}
impl<'a, B> MappedRange<'a, B, Coherent>
where
    B: Backend,
{
    
    
    
    
    
    pub unsafe fn write<'b, U: 'b>(
        &'b mut self,
        range: Range<u64>,
    ) -> Result<impl Write<U> + 'b, gfx_hal::mapping::Error>
    where
        U: Copy,
    {
        assert!(
            range.start < range.end,
            "Memory mapping region must have valid size"
        );
        assert!(
            fits_usize(range.end - range.start),
            "Range length must fit in usize"
        );
        let (ptr, range) = mapped_sub_range(self.ptr, self.range.clone(), range)
            .ok_or_else(|| gfx_hal::mapping::Error::OutOfBounds)?;
        let size = (range.end - range.start) as usize;
        let slice = mapped_slice_mut::<U>(ptr, size);
        Ok(WriteCoherent { slice })
    }
}