use crate::fonts::tables::OffsetSubtable;
use crate::fonts::FontError;
use std::marker::PhantomData;
use std::mem;
pub(in crate::fonts) struct Position<T> {
byte_position: u32,
ty: PhantomData<T>,
}
pub(in crate::fonts) struct Slice<T> {
start: Position<T>,
count: u32,
}
pub(in crate::fonts) struct SliceIter<T> {
start: Position<T>,
end: Position<T>,
}
impl Position<OffsetSubtable> {
pub(in crate::fonts) fn initial() -> Self {
Position {
byte_position: 0,
ty: PhantomData,
}
}
}
impl<T> Position<T> {
pub(in crate::fonts) fn cast<U>(self) -> Position<U> {
Position {
byte_position: self.byte_position,
ty: PhantomData,
}
}
pub(in crate::fonts) fn offset_bytes<U, O: Into<u32>>(self, by: O) -> Position<U> {
Position {
byte_position: self.byte_position + by.into(),
ty: PhantomData,
}
}
pub(in crate::fonts) fn offset<O: Into<u32>>(self, by: O) -> Position<T> {
self.offset_bytes(mem::size_of::<T>() as u32 * by.into())
}
pub(in crate::fonts) fn followed_by<U>(self) -> Position<U> {
self.offset_bytes(mem::size_of::<T>() as u32)
}
pub(in crate::fonts) fn read_from(self, bytes: &[u8]) -> Result<T, FontError>
where
T: ReadFromBytes,
{
T::read_from(
bytes
.get(self.byte_position as usize..)
.ok_or(FontError::OffsetBeyondEof)?,
)
}
}
pub(in crate::fonts) trait ReadFromBytes: Sized {
fn read_from(bytes: &[u8]) -> Result<Self, FontError>;
}
macro_rules! byte_arrays {
( $( $size: expr ),+ ) => {
$(
impl ReadFromBytes for [u8; $size] {
fn read_from(bytes: &[u8]) -> Result<Self, FontError> {
let bytes = bytes.get(..$size).ok_or(FontError::OffsetPlusLengthBeyondEof)?;
let ptr = bytes.as_ptr() as *const [u8; $size];
unsafe {
Ok(*ptr)
}
}
}
)+
}
}
byte_arrays!(2, 4);
fn i16_from_bytes(bytes: [u8; 2]) -> i16 {
unsafe { mem::transmute(bytes) }
}
fn u16_from_bytes(bytes: [u8; 2]) -> u16 {
unsafe { mem::transmute(bytes) }
}
fn u32_from_bytes(bytes: [u8; 4]) -> u32 {
unsafe { mem::transmute(bytes) }
}
impl ReadFromBytes for i16 {
fn read_from(bytes: &[u8]) -> Result<Self, FontError> {
Ok(i16::from_be(i16_from_bytes(ReadFromBytes::read_from(
bytes,
)?)))
}
}
impl ReadFromBytes for u16 {
fn read_from(bytes: &[u8]) -> Result<Self, FontError> {
Ok(u16::from_be(u16_from_bytes(ReadFromBytes::read_from(
bytes,
)?)))
}
}
impl ReadFromBytes for u32 {
fn read_from(bytes: &[u8]) -> Result<Self, FontError> {
Ok(u32::from_be(u32_from_bytes(ReadFromBytes::read_from(
bytes,
)?)))
}
}
impl<T, Src, Dst> ReadFromBytes for euclid::TypedScale<T, Src, Dst>
where
T: ReadFromBytes,
{
fn read_from(bytes: &[u8]) -> Result<Self, FontError> {
ReadFromBytes::read_from(bytes).map(euclid::TypedScale::new)
}
}
impl<T, Unit> ReadFromBytes for euclid::Length<T, Unit>
where
T: ReadFromBytes,
{
fn read_from(bytes: &[u8]) -> Result<Self, FontError> {
ReadFromBytes::read_from(bytes).map(euclid::Length::new)
}
}
impl Slice<u8> {
pub(in crate::fonts) fn read_from<'a>(&self, bytes: &'a [u8]) -> Result<&'a [u8], FontError> {
bytes
.get(self.start.byte_position as usize..)
.ok_or(FontError::OffsetBeyondEof)?
.get(..self.count as usize)
.ok_or(FontError::OffsetPlusLengthBeyondEof)
}
}
impl<T> Slice<T> {
pub(in crate::fonts) fn new<C: Into<u32>>(start: Position<T>, count: C) -> Self {
Slice {
start,
count: count.into(),
}
}
pub(in crate::fonts) fn count(&self) -> u32 {
self.count
}
pub(in crate::fonts) fn get_unchecked(&self, index: u32) -> Position<T> {
self.start.offset(index)
}
#[inline]
pub(in crate::fonts) fn binary_search_by_key<V, F>(
&self,
value: &V,
mut f: F,
) -> Result<Option<Position<T>>, FontError>
where
F: FnMut(Position<T>) -> Result<V, FontError>,
V: Ord,
{
binary_search(self.count, |index| {
Ok(f(self.get_unchecked(index))?.cmp(value))
})
.map(|opt| opt.map(|index| self.get_unchecked(index)))
}
}
pub(in crate::fonts) fn binary_search<F, E>(mut size: u32, mut f: F) -> Result<Option<u32>, E>
where
F: FnMut(u32) -> Result<::std::cmp::Ordering, E>,
{
use std::cmp::Ordering::*;
if size == 0 {
return Ok(None);
}
let mut base: u32 = 0;
while size > 1 {
let half = size / 2;
let mid = base + half;
let cmp = f(mid)?;
base = if cmp == Greater { base } else { mid };
size -= half;
}
let cmp = f(base)?;
if cmp == Equal {
Ok(Some(base))
} else {
Ok(None)
}
}
impl<T> Copy for Position<T> {}
impl<T> Clone for Position<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> PartialEq for Position<T> {
fn eq(&self, other: &Self) -> bool {
self.byte_position == other.byte_position
}
}
impl<T> Copy for Slice<T> {}
impl<T> Clone for Slice<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> IntoIterator for Slice<T> {
type Item = Position<T>;
type IntoIter = SliceIter<T>;
fn into_iter(self) -> SliceIter<T> {
SliceIter {
start: self.start,
end: self.get_unchecked(self.count),
}
}
}
impl<T> Iterator for SliceIter<T> {
type Item = Position<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.start != self.end {
let next = self.start;
self.start = next.followed_by();
Some(next)
} else {
None
}
}
}
impl<T> DoubleEndedIterator for SliceIter<T> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.start != self.end {
let next = self.end;
let byte_position = next.byte_position - mem::size_of::<T>() as u32;
self.end = Position {
byte_position,
ty: PhantomData,
};
Some(next)
} else {
None
}
}
}