use std::{io::Cursor, ops::Range};
use smallvec::SmallVec;
use crate::{
block::BlockIndex,
error::{Result, UnitResult},
math::*,
meta::attribute::ChannelList,
};
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct LineSlice<T> {
pub location: LineIndex,
pub value: T,
}
pub type LineRef<'s> = LineSlice<&'s [u8]>;
pub type LineRefMut<'s> = LineSlice<&'s mut [u8]>;
#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
pub struct LineIndex {
pub layer: usize,
pub channel: usize,
pub level: Vec2<usize>,
pub position: Vec2<usize>,
pub sample_count: usize,
}
impl LineIndex {
#[inline]
#[must_use]
pub fn lines_in_block(
block: BlockIndex,
channels: &ChannelList,
) -> impl Iterator<Item = (Range<usize>, LineIndex)> {
struct LineIter {
layer: usize,
level: Vec2<usize>,
width: usize,
end_y: usize,
x: usize,
channel_sizes: SmallVec<[usize; 8]>,
byte: usize,
channel: usize,
y: usize,
}
impl Iterator for LineIter {
type Item = (Range<usize>, LineIndex);
fn next(&mut self) -> Option<Self::Item> {
if self.y < self.end_y {
let byte_len = self.channel_sizes[self.channel];
let return_value = (
(self.byte..self.byte + byte_len),
LineIndex {
channel: self.channel,
layer: self.layer,
level: self.level,
position: Vec2(self.x, self.y),
sample_count: self.width,
},
);
{
self.byte += byte_len;
self.channel += 1;
if self.channel == self.channel_sizes.len() {
self.channel = 0;
self.y += 1;
}
}
Some(return_value)
} else {
None
}
}
}
let channel_line_sizes: SmallVec<[usize; 8]> = channels
.list
.iter()
.map(move |channel| block.pixel_size.0 * channel.sample_type.bytes_per_sample()) .collect();
LineIter {
layer: block.layer,
level: block.level,
width: block.pixel_size.0,
x: block.pixel_position.0,
end_y: block.pixel_position.y() + block.pixel_size.height(),
channel_sizes: channel_line_sizes,
byte: 0,
channel: 0,
y: block.pixel_position.y(),
}
}
}
impl<'s> LineRefMut<'s> {
#[inline]
#[must_use]
pub fn write_samples_from_slice<T: crate::io::Data>(self, slice: &[T]) -> UnitResult {
debug_assert_eq!(
slice.len(),
self.location.sample_count,
"slice size does not match the line width"
);
debug_assert_eq!(
self.value.len(),
self.location.sample_count * T::BYTE_SIZE,
"sample type size does not match line byte size"
);
T::write_slice_ne(&mut Cursor::new(self.value), slice)
}
#[inline]
#[must_use]
pub fn write_samples<T: crate::io::Data>(
self,
mut get_sample: impl FnMut(usize) -> T,
) -> UnitResult {
debug_assert_eq!(
self.value.len(),
self.location.sample_count * T::BYTE_SIZE,
"sample type size does not match line byte size"
);
let mut write = Cursor::new(self.value);
for index in 0..self.location.sample_count {
T::write_ne(get_sample(index), &mut write)?;
}
Ok(())
}
}
impl LineRef<'_> {
pub fn read_samples_into_slice<T: crate::io::Data>(self, slice: &mut [T]) -> UnitResult {
debug_assert_eq!(
slice.len(),
self.location.sample_count,
"slice size does not match the line width"
);
debug_assert_eq!(
self.value.len(),
self.location.sample_count * T::BYTE_SIZE,
"sample type size does not match line byte size"
);
T::read_slice_ne(&mut Cursor::new(self.value), slice)
}
pub fn read_samples<T: crate::io::Data>(&self) -> impl Iterator<Item = Result<T>> + '_ {
debug_assert_eq!(
self.value.len(),
self.location.sample_count * T::BYTE_SIZE,
"sample type size does not match line byte size"
);
let mut read = self.value; (0..self.location.sample_count).map(move |_| T::read_ne(&mut read))
}
}