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> { 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 { 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)), } } } // Iterator #[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>; fn next(&mut self) -> Option { 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) { let len = match self { Self::Short { array, .. } => array.len(), Self::Long { array, .. } => array.len(), }; (len, Some(len)) } } impl<'a> ExactSizeIterator for Iter<'a> {}