use {
    crate::{memory::Memory, Size},
    hal::{device::Device as _, Backend},
    std::{iter, ops::Range, ptr::NonNull, slice},
};
#[derive(Debug)]
struct Flush<'a, B: Backend> {
    device: &'a B::Device,
    memory: &'a B::Memory,
    segment: hal::memory::Segment,
}
#[derive(Debug)]
pub struct Writer<'a, 'b, T, B: Backend> {
    
    pub slice: &'a mut [T],
    flush: Option<Flush<'b, B>>,
}
impl<T, B: Backend> Writer<'_, '_, T, B> {
    
    
    
    
    pub fn forget(mut self) -> (*mut T, Option<hal::memory::Segment>) {
        (
            self.slice.as_mut_ptr(),
            self.flush.take().map(|f| f.segment),
        )
    }
}
impl<'a, 'b, T, B: Backend> Drop for Writer<'a, 'b, T, B> {
    fn drop(&mut self) {
        if let Some(f) = self.flush.take() {
            unsafe {
                f.device
                    .flush_mapped_memory_ranges(iter::once((f.memory, f.segment)))
                    .expect("Should flush successfully")
            };
        }
    }
}
#[derive(Debug)]
pub struct MappedRange<'a, B: Backend> {
    
    memory: &'a Memory<B>,
    
    ptr: NonNull<u8>,
    
    mapping_range: Range<Size>,
    
    
    requested_range: Range<Size>,
}
impl<'a, B: Backend> MappedRange<'a, B> {
    
    
    
    
    
    
    
    pub(crate) unsafe fn from_raw(
        memory: &'a Memory<B>,
        ptr: *mut u8,
        mapping_range: Range<Size>,
        requested_range: Range<Size>,
    ) -> Self {
        debug_assert!(
            mapping_range.start < mapping_range.end,
            "Memory mapping region must have valid size"
        );
        debug_assert!(
            requested_range.start < requested_range.end,
            "Memory mapping region must have valid size"
        );
        match memory.non_coherent_atom_size {
            Some(atom) => {
                debug_assert_eq!((mapping_range.start % atom.get(), mapping_range.end % atom.get()), (0, 0),
                    "Bounds of non-coherent memory mapping ranges must be multiple of `Limits::non_coherent_atom_size`",
                );
                debug_assert!(
                    crate::is_sub_range(&requested_range, &mapping_range),
                    "Requested {:?} must be sub-range of mapping {:?}",
                    requested_range,
                    mapping_range,
                );
            }
            None => {
                debug_assert_eq!(mapping_range, requested_range);
            }
        };
        MappedRange {
            ptr: NonNull::new_unchecked(ptr),
            mapping_range,
            requested_range,
            memory,
        }
    }
    
    
    pub fn ptr(&self) -> NonNull<u8> {
        let offset = (self.requested_range.start - self.mapping_range.start) as isize;
        unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }
    }
    
    pub fn range(&self) -> Range<Size> {
        self.requested_range.clone()
    }
    
    pub fn is_coherent(&self) -> bool {
        self.memory.non_coherent_atom_size.is_none()
    }
    
    
    
    
    
    
    
    pub unsafe fn read<'b, T>(
        &'b mut self,
        device: &B::Device,
        segment: hal::memory::Segment,
    ) -> Result<&'b [T], hal::device::MapError>
    where
        'a: 'b,
        T: Copy,
    {
        let sub_range = crate::segment_to_sub_range(segment, &self.requested_range)?;
        if let Some(atom) = self.memory.non_coherent_atom_size {
            let aligned_range = crate::align_range(&sub_range, atom);
            let segment = hal::memory::Segment {
                offset: aligned_range.start,
                size: Some(aligned_range.end - aligned_range.start),
            };
            device.invalidate_mapped_memory_ranges(iter::once((self.memory.raw(), segment)))?;
        }
        let ptr = self
            .ptr
            .as_ptr()
            .offset((sub_range.start - self.mapping_range.start) as isize);
        let size = (sub_range.end - sub_range.start) as usize;
        let (_pre, slice, _post) = slice::from_raw_parts(ptr, size).align_to();
        Ok(slice)
    }
    
    
    
    
    
    
    pub unsafe fn write<'b, T: 'b>(
        &'b mut self,
        device: &'b B::Device,
        segment: hal::memory::Segment,
    ) -> Result<Writer<'a, 'b, T, B>, hal::device::MapError>
    where
        'a: 'b,
        T: Copy,
    {
        let sub_range = crate::segment_to_sub_range(segment, &self.requested_range)?;
        let ptr = self
            .ptr
            .as_ptr()
            .offset((sub_range.start - self.mapping_range.start) as isize);
        let size = (sub_range.end - sub_range.start) as usize;
        let (_pre, slice, _post) = slice::from_raw_parts_mut(ptr, size).align_to_mut();
        let memory = self.memory.raw();
        let flush = self.memory.non_coherent_atom_size.map(|atom| Flush {
            device,
            memory,
            segment: {
                let range = crate::align_range(&sub_range, atom);
                hal::memory::Segment {
                    offset: range.start,
                    size: Some(range.end - range.start),
                }
            },
        });
        Ok(Writer { slice, flush })
    }
}