use crate::*;
pub trait ImageData<T: Type>: Sync + Send + AsRef<[T]> + AsMut<[T]>
where
T: Copy,
{
fn flush(&self) -> Result<(), Error> {
Ok(())
}
fn data(&self) -> &[T] {
self.as_ref()
}
fn data_mut(&mut self) -> &mut [T] {
self.as_mut()
}
fn as_ptr(&self) -> *const T {
self.as_ref().as_ptr()
}
fn as_mut_ptr(&mut self) -> *mut T {
self.as_mut().as_mut_ptr()
}
fn buffer(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(
self.as_ref().as_ptr() as *const u8,
self.as_ref().len() * std::mem::size_of::<T>(),
)
}
}
fn buffer_mut(&mut self) -> &mut [u8] {
unsafe {
std::slice::from_raw_parts_mut(
self.as_mut().as_ptr() as *mut u8,
self.as_mut().len() * std::mem::size_of::<T>(),
)
}
}
}
impl<T: Type> std::ops::Index<usize> for dyn ImageData<T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.as_ref()[index]
}
}
impl<T: Type> std::ops::IndexMut<usize> for dyn ImageData<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.as_mut()[index]
}
}
impl<T: Type> std::ops::Index<std::ops::Range<usize>> for dyn ImageData<T> {
type Output = [T];
fn index(&self, index: std::ops::Range<usize>) -> &Self::Output {
&self.as_ref()[index]
}
}
impl<T: Type> std::ops::IndexMut<std::ops::Range<usize>> for dyn ImageData<T> {
fn index_mut(&mut self, index: std::ops::Range<usize>) -> &mut Self::Output {
&mut self.as_mut()[index]
}
}
#[cfg(feature = "mmap")]
pub mod mmap {
use super::*;
use memmap2::MmapOptions;
use std::io::{Read, Write};
pub struct Mmap<T: Type> {
inner: memmap2::MmapMut,
_t: std::marker::PhantomData<T>,
}
impl<T: Type> Mmap<T> {
fn header_len() -> u64 {
4 + std::mem::size_of::<u64>() as u64
+ std::mem::size_of::<u64>() as u64
+ std::mem::size_of::<u64>() as u64
+ std::mem::size_of::<u16>() as u64
}
pub fn create<C: Color>(
filename: impl AsRef<std::path::Path>,
meta: &Meta<T, C>,
) -> Result<Self, Error> {
let mut file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(filename)?;
file.set_len(Self::header_len() + meta.num_bytes() as u64)?;
file.write_all(b"img2")?;
file.write_all(&(std::mem::size_of::<T>() as u64).to_le_bytes())?;
file.write_all(&(meta.width() as u64).to_le_bytes())?;
file.write_all(&(meta.height() as u64).to_le_bytes())?;
file.write_all(&(C::CHANNELS as u16).to_le_bytes())?;
let inner = unsafe {
MmapOptions::new()
.offset(Self::header_len())
.map_mut(&file)?
};
let data = Self {
inner,
_t: std::marker::PhantomData,
};
Ok(data)
}
pub(crate) fn create_image<C: Color>(
filename: impl AsRef<std::path::Path>,
meta: &Meta<T, C>,
) -> Result<Image<T, C>, Error> {
let data = Self::create(filename, meta)?;
Image::new_with_data(meta.size(), data)
}
pub(crate) fn load<C: Color>(
filename: impl AsRef<std::path::Path>,
) -> Result<(Mmap<T>, Meta<T, C>), Error> {
let mut file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(filename)?;
let mut hdr = [0u8; 4];
file.read_exact(&mut hdr)?;
if hdr.as_slice() != b"img2" {
return Err(Error::Message("invalid mmap header".to_string()));
}
let mut size = [0u8; 8];
file.read_exact(&mut size)?;
if size != (std::mem::size_of::<T>() as u64).to_le_bytes() {
return Err(Error::InvalidType);
}
let mut width = [0u8; 8];
file.read_exact(&mut width)?;
let mut height = [0u8; 8];
file.read_exact(&mut height)?;
let mut channels = [0u8; 2];
file.read_exact(&mut channels)?;
if u16::from_le_bytes(channels) as usize != C::CHANNELS {
return Err(Error::InvalidType);
}
let inner = unsafe {
MmapOptions::new()
.offset(Self::header_len())
.map_mut(&file)?
};
let width = u64::from_le_bytes(width) as usize;
let height = u64::from_le_bytes(height) as usize;
let data = Self {
inner,
_t: std::marker::PhantomData,
};
Ok((data, Meta::new((width, height))))
}
pub(crate) fn load_image<C: Color>(
filename: impl AsRef<std::path::Path>,
) -> Result<Image<T, C>, Error> {
let (data, meta) = Self::load::<C>(filename)?;
Image::new_with_data(meta.size(), data)
}
}
impl<T: Type> AsRef<[T]> for Mmap<T> {
fn as_ref(&self) -> &[T] {
unsafe {
std::slice::from_raw_parts(
self.inner.as_ptr() as *const _,
self.inner.len() / std::mem::size_of::<T>(),
)
}
}
}
impl<T: Type> AsMut<[T]> for Mmap<T> {
fn as_mut(&mut self) -> &mut [T] {
unsafe {
std::slice::from_raw_parts_mut(
self.inner.as_ptr() as *mut _,
self.inner.len() / std::mem::size_of::<T>(),
)
}
}
}
impl<T: Type> ImageData<T> for Mmap<T> {
fn flush(&self) -> Result<(), Error> {
self.inner.flush()?;
Ok(())
}
}
impl<T: Type> Drop for Mmap<T> {
fn drop(&mut self) {
let _ = self.flush();
}
}
}
impl<T: Type> ImageData<T> for [T] {}
impl<T: Type> ImageData<T> for Vec<T> {}
impl<T: Type> ImageData<T> for Box<[T]> {}