mttf 0.1.7

A library for working with TrueType fonts. Most parts are zero-allocation.
Documentation

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)),
		}
	}
}

// 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<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> {}