use core::ops::Range;
use super::{
EncodedImageError,
groups::{CodingRecords, GroupMetadata, GroupRecords},
};
use crate::{
ByteAlignment,
image::{
CoverageBudget, DecodeUnitRef, EncodedGroupError, GroupPlanes, Region, RegionError,
SurfaceDescriptor,
units::{GroupLayout, RegionCells},
},
media::{CodingRecord, CodingTable},
};
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug)]
pub struct EncodedImageLayout<'a> {
pub(super) metadata: GroupMetadata<'a>,
}
impl<'a> EncodedImageLayout<'a> {
pub fn new(
surface: SurfaceDescriptor,
codings: &'a [u8],
groups: Option<&'a [u8]>,
indexes: Option<&'a [u8]>,
data_len: u32,
data_file_offset: Option<u32>,
) -> Result<Self, EncodedImageError> {
if indexes.is_some_and(|bytes| bytes.is_empty()) {
return Err(EncodedImageError::EmptyIndexSection);
}
if groups.is_none() && indexes.is_some() {
return Err(EncodedImageError::AmbiguousImplicitGroup);
}
if let Some(offset) = data_file_offset {
offset
.checked_add(data_len)
.ok_or(EncodedImageError::SizeOverflow)?;
}
let metadata = GroupMetadata {
surface,
codings: CodingRecords::Wire(
CodingTable::open(codings).map_err(EncodedImageError::Codings)?,
),
records: groups.map_or(GroupRecords::Implicit, GroupRecords::Wire),
indexes: indexes.unwrap_or(&[]),
data_len,
file_offset: data_file_offset,
data_offset: 0,
};
metadata.validate_tables()?;
Ok(Self { metadata })
}
pub(super) const fn from_metadata(metadata: GroupMetadata<'a>) -> Self {
Self { metadata }
}
pub const fn surface(self) -> SurfaceDescriptor {
self.metadata.surface
}
pub fn group_count(self) -> usize {
self.metadata.group_count()
}
pub fn validate_groups(self, budget: &mut CoverageBudget) -> Result<(), EncodedImageError> {
self.metadata.validate_groups(budget)
}
pub fn input_alignment(self) -> Result<ByteAlignment, EncodedImageError> {
self.metadata.input_alignment()
}
pub fn group(self, index: usize) -> Result<ImageGroupLayout<'a>, EncodedImageError> {
let record = self.metadata.record(index)?;
let layout = self.metadata.resolve_record(index, record)?.0;
Ok(ImageGroupLayout {
index,
base: record.data_range().start,
layout,
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct ImageGroupLayout<'a> {
index: usize,
base: u32,
layout: GroupLayout<'a>,
}
impl<'a> ImageGroupLayout<'a> {
pub const fn surface(self) -> SurfaceDescriptor {
self.layout.surface
}
pub const fn planes(self) -> GroupPlanes {
self.layout.planes
}
pub const fn coding(self) -> CodingRecord<'a> {
self.layout.coding
}
pub const fn len(self) -> usize {
self.layout.selection.len()
}
pub const fn is_empty(self) -> bool {
self.layout.selection.is_empty()
}
pub const fn input_alignment(self) -> ByteAlignment {
self.layout.input_alignment
}
pub fn unit_range(self, ordinal: usize) -> Option<Range<u32>> {
let range = self.layout.index.get(ordinal)?;
Some(self.base + range.start..self.base + range.end)
}
pub fn unit_region(self, ordinal: usize) -> Option<Region> {
self.layout
.grid
.get(self.layout.selection.get(ordinal)? as usize)
}
pub fn units_in(self, region: Region) -> Result<impl Iterator<Item = usize> + 'a, RegionError> {
Ok(
RegionCells::new(self.layout.grid, self.layout.selection, region)?
.map(move |cell| self.layout.selection.position(cell).expect("selected cell")),
)
}
pub fn unit(
self,
ordinal: usize,
bytes: &'a [u8],
) -> Result<DecodeUnitRef<'a>, EncodedImageError> {
self.layout
.bind_unit(ordinal, bytes)
.ok_or(EncodedImageError::UnitOutOfBounds {
group: self.index,
ordinal,
})?
.map_err(|error| EncodedImageError::Group {
index: self.index,
error: EncodedGroupError::Group(error),
})
}
}