mttf 0.1.7

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

use std::ops::Deref;
use std::fmt::{ Debug, Formatter, Result as FmtResult };
use bytemuck::{ Zeroable, Pod };

use super::ReadError;
use super::core::*;

// Version 0.5

#[derive(Clone, Copy, Zeroable, Pod)]
#[repr(transparent)]
pub struct MaximumProfile0([u8; 6]);

impl<'a> RandomAccess<'a> for &'a MaximumProfile0 {
	fn bytes(&self) -> &'a [u8] { &self.0 }
}

impl MaximumProfile0 {
	pub fn version(&self) -> Version16Dot16 { self.version16dot16(0) }
	pub fn num_glyphs(&self) -> u16 { self.uint16(4) }
}

impl Debug for MaximumProfile0 {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("MaximumProfile0")
			.field("version", &self.version())
			.field("num_glyphs", &self.num_glyphs())
			.finish()
	}
}

// Version 1.0

#[derive(Clone, Copy, Zeroable, Pod)]
#[repr(transparent)]
pub struct MaximumProfile1([u8; 32]);

impl<'a> RandomAccess<'a> for &'a MaximumProfile1 {
	fn bytes(&self) -> &'a [u8] { &self.0 }
}

impl AsRef<MaximumProfile0> for MaximumProfile1 {
	fn as_ref(&self) -> &MaximumProfile0 { bytemuck::from_bytes(&self.0[0..6]) }
}

impl Deref for MaximumProfile1 {
	type Target = MaximumProfile0;
	fn deref(&self) -> &Self::Target { self.as_ref() }
}

impl MaximumProfile1 {
	pub fn max_points(&self) -> u16 { self.uint16(6) }
	pub fn max_contours(&self) -> u16 { self.uint16(8) }
	pub fn max_composite_points(&self) -> u16 { self.uint16(10) }
	pub fn max_composite_contours(&self) -> u16 { self.uint16(12) }
	pub fn max_zones(&self) -> u16 { self.uint16(14) }
	pub fn max_twilight_points(&self) -> u16 { self.uint16(16) }
	pub fn max_storage(&self) -> u16 { self.uint16(18) }
	pub fn max_function_defs(&self) -> u16 { self.uint16(20) }
	pub fn max_instruction_defs(&self) -> u16 { self.uint16(22) }
	pub fn max_stack_elements(&self) -> u16 { self.uint16(24) }
	pub fn max_size_of_instructions(&self) -> u16 { self.uint16(26) }
	pub fn max_component_elements(&self) -> u16 { self.uint16(28) }
	pub fn max_component_depth(&self) -> u16 { self.uint16(30) }
}

impl Debug for MaximumProfile1 {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		f.debug_struct("MaximumProfile1")
			.field("version", &self.version())
			.field("num_glyphs", &self.num_glyphs())
			.field("max_points", &self.max_points())
			.field("max_contours", &self.max_contours())
			.field("max_composite_points", &self.max_composite_points())
			.field("max_composite_contours", &self.max_composite_contours())
			.field("max_zones", &self.max_zones())
			.field("max_twilight_points", &self.max_twilight_points())
			.field("max_storage", &self.max_storage())
			.field("max_function_defs", &self.max_function_defs())
			.field("max_instruction_defs", &self.max_instruction_defs())
			.field("max_stack_elements", &self.max_stack_elements())
			.field("max_size_of_instructions", &self.max_size_of_instructions())
			.field("max_component_elements", &self.max_component_elements())
			.field("max_component_depth", &self.max_component_depth())
			.finish()
	}
}

// Generic

#[derive(Clone, Copy)]
pub enum MaximumProfile<'a> {
	Version0_5(&'a MaximumProfile0),
	Version1_0(&'a MaximumProfile1),
}

impl<'a> RandomAccess<'a> for MaximumProfile<'a> {
	fn bytes(&self) -> &'a [u8] {
		match self {
			Self::Version0_5(x) => x.bytes(),
			Self::Version1_0(x) => x.bytes(),
		}
	}
}

impl<'a> Deref for MaximumProfile<'a> {
	type Target = MaximumProfile0;
	fn deref(&self) -> &Self::Target {
		match self {
			Self::Version0_5(x) => x,
			Self::Version1_0(x) => x,
		}
	}
}

impl<'a> Debug for MaximumProfile<'a> {
	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
		match self {
			Self::Version0_5(x) => x.fmt(f),
			Self::Version1_0(x) => x.fmt(f),
		}
	}
}

impl<'a> TryFrom<&'a [u8]> for MaximumProfile<'a> {
	type Error = ReadError;
	fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
		if value.len() < 6 { return Err(ReadError::UnexpectedEof); }
		match value.version16dot16(0) {
			Version16Dot16(0x0000, 0x5000) => Ok(Self::Version0_5(bytemuck::from_bytes(value))),
			Version16Dot16(0x0001, 0x0000) => {
				if value.as_ref().len() < 32 { return Err(ReadError::UnexpectedEof); }
				Ok(Self::Version1_0(bytemuck::from_bytes(value)))
			},
			x => Err(ReadError::UnsupportedTableVersion16Dot16(x))
		}
	}
}