use std::ops::Range;
use std::fmt::{ Debug, Formatter, Result as FmtResult };
use super::ReadError;
use super::core::*;
use super::head::IndexToLocationFormat;
#[derive(Clone, Copy)]
pub enum IndexToLocationTable<'a> {
Short(U16Array<'a>),
Long(U32Array<'a>),
}
impl<'a> RandomAccess<'a> for IndexToLocationTable<'a> {
fn bytes(&self) -> &'a [u8] {
match self {
Self::Short(x) => x.bytes(),
Self::Long(x) => x.bytes(),
}
}
}
impl<'a> IndexToLocationTable<'a> {
pub fn map(&self, index: u32) -> Option<Range<u32>> {
match self {
Self::Short(x) => {
let start = (x.get(index as usize) as u32) << 1;
let stop = (x.get(index as usize + 1) as u32) << 1;
if start == stop { None } else { Some(start..stop) }
},
Self::Long(x) => {
let start = x.get(index as usize);
let stop = x.get(index as usize + 1);
if start == stop { None } else { Some(start..stop) }
},
}
}
pub fn iter(&self) -> Iter<'a> {
match self {
Self::Short(x) => Iter::Short { array: *x, index: 0 },
Self::Long(x) => Iter::Long { array: *x, index: 0 },
}
}
}
impl<'a> Debug for IndexToLocationTable<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_list()
.entries(self.iter())
.finish()
}
}
impl<'a> IndexToLocationTable<'a> {
pub fn try_from(data: &'a [u8], index_to_location_format: IndexToLocationFormat, num_glyphs: u16) -> Result<Self, ReadError> {
match index_to_location_format {
IndexToLocationFormat::Offset16 => {
let size = num_glyphs as usize * 2 + 2;
if data.len() < size { return Err(ReadError::UnexpectedEof); }
Ok(Self::Short(data.uint16_array(0, num_glyphs as usize + 1)))
},
IndexToLocationFormat::Offset32 => {
let size = num_glyphs as usize * 4 + 4;
if data.len() < size { return Err(ReadError::UnexpectedEof); }
Ok(Self::Long(data.uint32_array(0, num_glyphs as usize + 1)))
},
x => Err(ReadError::UnsupportedIndexToLocationFormat(x)),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Iter<'a> {
Short {
array: U16Array<'a>,
index: usize,
},
Long {
array: U32Array<'a>,
index: usize,
},
}
impl<'a> Iterator for Iter<'a> {
type Item = Option<Range<u32>>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Short { array, index } => {
if *index + 1 < array.len() {
let start = (array.get(*index) as u32) << 1;
let stop = (array.get(*index + 1) as u32) << 1;
*index += 1;
Some(if start == stop { None } else { Some(start..stop) })
} else { None }
},
Self::Long { array, index } => {
if *index + 1 < array.len() {
let start = array.get(*index);
let stop = array.get(*index + 1);
*index += 1;
Some(if start == stop { None } else { Some(start..stop) })
} else { None }
},
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = match self {
Self::Short { array, .. } => array.len(),
Self::Long { array, .. } => array.len(),
};
(len, Some(len))
}
}
impl<'a> ExactSizeIterator for Iter<'a> {}