read-fonts 0.44.0

Reading OpenType font files.
Documentation
// THIS FILE IS AUTOGENERATED.
// Any changes to this file will be overwritten.
// For more information about how codegen works, see font-codegen/README.md

#[allow(unused_imports)]
use crate::codegen_prelude::*;

impl<'a> MinByteRange<'a> for PositionedTable<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.pairs_byte_range().end
    }
    fn min_table_bytes(&self) -> &'a [u8] {
        let range = self.min_byte_range();
        self.data.as_bytes().get(range).unwrap_or_default()
    }
}

impl ReadArgs for PositionedTable<'_> {
    type Args = ();
}

impl<'a> FontRead<'a> for PositionedTable<'a> {
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// Holds a positioned record directly, and an array of records that hold them.
#[derive(Clone)]
pub struct PositionedTable<'a> {
    data: FontData<'a>,
}

#[allow(clippy::needless_lifetimes)]
impl<'a> PositionedTable<'a> {
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
    basic_table_impls!(impl_the_methods);

    /// The size of each [Positioned] record in this table, in bytes.
    pub fn positioned_size(&self) -> u16 {
        let range = self.positioned_size_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// A positioned record read straight from a table field.
    pub fn solo(&self) -> Positioned<'a> {
        let range = self.solo_byte_range();
        Positioned::read_at(self.data, range.start, self.positioned_size()).unwrap_or_default()
    }

    pub fn pair_count(&self) -> u16 {
        let range = self.pair_count_byte_range();
        self.data.read_at(range.start).ok().unwrap_or_default()
    }

    /// An array of records that are positioned by containment.
    pub fn pairs(&self) -> ComputedArray<'a, PositionedPair<'a>> {
        let range = self.pairs_byte_range();
        ComputedArray::new(self.data, range, self.positioned_size()).unwrap_or_default()
    }

    pub fn positioned_size_byte_range(&self) -> Range<usize> {
        let start = 0;
        let end = start + u16::RAW_BYTE_LEN;
        start..end
    }

    pub fn solo_byte_range(&self) -> Range<usize> {
        let start = self.positioned_size_byte_range().end;
        let end =
            start + <Positioned as ComputeSize>::compute_size(self.positioned_size()).unwrap_or(0);
        start..end
    }

    pub fn pair_count_byte_range(&self) -> Range<usize> {
        let start = self.solo_byte_range().end;
        let end = start + u16::RAW_BYTE_LEN;
        start..end
    }

    pub fn pairs_byte_range(&self) -> Range<usize> {
        let pair_count = self.pair_count();
        let start = self.pair_count_byte_range().end;
        let end = start
            + (transforms::to_usize(pair_count)).saturating_mul(
                <PositionedPair as ComputeSize>::compute_size(self.positioned_size()).unwrap_or(0),
            );
        start..end
    }
}

const _: () = assert!(FontData::default_data_long_enough(
    PositionedTable::MIN_SIZE
));

impl Default for PositionedTable<'_> {
    fn default() -> Self {
        Self {
            data: FontData::default_table_data(),
        }
    }
}

/// Positioned because it contains positioned fields.
#[derive(Clone, Debug)]
pub struct PositionedPair<'a> {
    /// A plain scalar, to check the following fields are still located
    /// correctly.
    pub tag: BigEndian<u16>,
    pub first: Positioned<'a>,
    pub second: Positioned<'a>,
}

impl<'a> PositionedPair<'a> {
    /// A plain scalar, to check the following fields are still located
    /// correctly.
    pub fn tag(&self) -> u16 {
        self.tag.get()
    }

    pub fn first(&self) -> &Positioned<'a> {
        &self.first
    }

    pub fn second(&self) -> &Positioned<'a> {
        &self.second
    }
}

impl ReadArgs for PositionedPair<'_> {
    type Args = u16;
}

impl ComputeSize for PositionedPair<'_> {
    #[allow(clippy::needless_question_mark)]
    fn compute_size(args: u16) -> Result<usize, ReadError> {
        let positioned_size = args;
        let mut result = 0usize;
        result = result
            .checked_add(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        result = result
            .checked_add(<Positioned as ComputeSize>::compute_size(positioned_size).unwrap_or(0))
            .ok_or(ReadError::OutOfBounds)?;
        result = result
            .checked_add(<Positioned as ComputeSize>::compute_size(positioned_size).unwrap_or(0))
            .ok_or(ReadError::OutOfBounds)?;
        Ok(result)
    }
}

impl<'a> FontReadAt<'a> for PositionedPair<'a> {
    fn read_at(data: FontData<'a>, offset: usize, args: u16) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance_by(offset);
        let positioned_size = args;
        Ok(Self {
            tag: cursor.read_be()?,
            first: cursor.read_at_with_args(positioned_size)?,
            second: cursor.read_at_with_args(positioned_size)?,
        })
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> PositionedPair<'a> {
    /// A constructor that requires additional arguments.
    ///
    /// This type requires some external state in order to be
    /// parsed.
    pub fn read(
        data: FontData<'a>,
        offset: usize,
        positioned_size: u16,
    ) -> Result<Self, ReadError> {
        let args = positioned_size;
        Self::read_at(data, offset, args)
    }
}

impl<'a> MinByteRange<'a> for NestedPositionedTable<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.groups_byte_range().end
    }
    fn min_table_bytes(&self) -> &'a [u8] {
        let range = self.min_byte_range();
        self.data.as_bytes().get(range).unwrap_or_default()
    }
}

impl ReadArgs for NestedPositionedTable<'_> {
    type Args = ();
}

impl<'a> FontRead<'a> for NestedPositionedTable<'a> {
    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// Exercises the nesting case: a table of groups, each holding an array of
/// records that are themselves positioned.
#[derive(Clone)]
pub struct NestedPositionedTable<'a> {
    data: FontData<'a>,
}

#[allow(clippy::needless_lifetimes)]
impl<'a> NestedPositionedTable<'a> {
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
    basic_table_impls!(impl_the_methods);

    /// The size of each [Positioned] record in this table, in bytes.
    pub fn positioned_size(&self) -> u16 {
        let range = self.positioned_size_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The number of pairs in every group.
    pub fn pairs_per_group(&self) -> u16 {
        let range = self.pairs_per_group_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    pub fn group_count(&self) -> u16 {
        let range = self.group_count_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    pub fn groups(&self) -> ComputedArray<'a, PositionedGroup<'a>> {
        let range = self.groups_byte_range();
        ComputedArray::new(
            self.data,
            range,
            (self.pairs_per_group(), self.positioned_size()),
        )
        .unwrap_or_default()
    }

    pub fn positioned_size_byte_range(&self) -> Range<usize> {
        let start = 0;
        let end = start + u16::RAW_BYTE_LEN;
        start..end
    }

    pub fn pairs_per_group_byte_range(&self) -> Range<usize> {
        let start = self.positioned_size_byte_range().end;
        let end = start + u16::RAW_BYTE_LEN;
        start..end
    }

    pub fn group_count_byte_range(&self) -> Range<usize> {
        let start = self.pairs_per_group_byte_range().end;
        let end = start + u16::RAW_BYTE_LEN;
        start..end
    }

    pub fn groups_byte_range(&self) -> Range<usize> {
        let group_count = self.group_count();
        let start = self.group_count_byte_range().end;
        let end = start
            + (transforms::to_usize(group_count)).saturating_mul(
                <PositionedGroup as ComputeSize>::compute_size((
                    self.pairs_per_group(),
                    self.positioned_size(),
                ))
                .unwrap_or(0),
            );
        start..end
    }
}

const _: () = assert!(FontData::default_data_long_enough(
    NestedPositionedTable::MIN_SIZE
));

impl Default for NestedPositionedTable<'_> {
    fn default() -> Self {
        Self {
            data: FontData::default_table_data(),
        }
    }
}

/// Positioned only because it contains an array of positioned records; it has
/// no positioned field of its own.
#[derive(Clone, Debug)]
pub struct PositionedGroup<'a> {
    pub pairs: ComputedArray<'a, PositionedPair<'a>>,
}

impl<'a> PositionedGroup<'a> {
    pub fn pairs(&self) -> &ComputedArray<'a, PositionedPair<'a>> {
        &self.pairs
    }
}

impl ReadArgs for PositionedGroup<'_> {
    type Args = (u16, u16);
}

impl ComputeSize for PositionedGroup<'_> {
    #[allow(clippy::needless_question_mark)]
    fn compute_size(args: (u16, u16)) -> Result<usize, ReadError> {
        let (pairs_per_group, positioned_size) = args;
        Ok((transforms::to_usize(pairs_per_group)).saturating_mul(
            <PositionedPair as ComputeSize>::compute_size(positioned_size).unwrap_or(0),
        ))
    }
}

impl<'a> FontReadAt<'a> for PositionedGroup<'a> {
    fn read_at(data: FontData<'a>, offset: usize, args: (u16, u16)) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance_by(offset);
        let (pairs_per_group, positioned_size) = args;
        Ok(Self {
            pairs: cursor
                .read_computed_array(transforms::to_usize(pairs_per_group), positioned_size)?,
        })
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> PositionedGroup<'a> {
    /// A constructor that requires additional arguments.
    ///
    /// This type requires some external state in order to be
    /// parsed.
    pub fn read(
        data: FontData<'a>,
        offset: usize,
        pairs_per_group: u16,
        positioned_size: u16,
    ) -> Result<Self, ReadError> {
        let args = (pairs_per_group, positioned_size);
        Self::read_at(data, offset, args)
    }
}