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