// 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 Cmap<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.encoding_records_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 TopLevelTable for Cmap<'_> {
    /// `cmap`
    const TAG: Tag = Tag::new(b"cmap");
}

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

/// [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#overview)
#[derive(Clone)]
pub struct Cmap<'a> {
    data: FontData<'a>,
}

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

    /// Table version number (0).
    pub fn version(&self) -> u16 {
        let range = self.version_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Number of encoding tables that follow.
    pub fn num_tables(&self) -> u16 {
        let range = self.num_tables_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    pub fn encoding_records(&self) -> &'a [EncodingRecord] {
        let range = self.encoding_records_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

    pub fn encoding_records_byte_range(&self) -> Range<usize> {
        let num_tables = self.num_tables();
        let start = self.num_tables_byte_range().end;
        let end =
            start + (transforms::to_usize(num_tables)).saturating_mul(EncodingRecord::RAW_BYTE_LEN);
        start..end
    }
}

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

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

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap<'a> {
    fn type_name(&self) -> &str {
        "Cmap"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("version", self.version())),
            1usize => Some(Field::new("num_tables", self.num_tables())),
            2usize => Some(Field::new(
                "encoding_records",
                traversal::FieldType::array_of_records(
                    stringify!(EncodingRecord),
                    self.encoding_records(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

/// [Encoding Record](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#encoding-records-and-encodings)
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct EncodingRecord {
    /// Platform ID.
    pub platform_id: BigEndian<PlatformId>,
    /// Platform-specific encoding ID.
    pub encoding_id: BigEndian<u16>,
    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
    /// encoding.
    pub subtable_offset: BigEndian<Offset32>,
}

impl EncodingRecord {
    /// Platform ID.
    pub fn platform_id(&self) -> PlatformId {
        self.platform_id.get()
    }

    /// Platform-specific encoding ID.
    pub fn encoding_id(&self) -> u16 {
        self.encoding_id.get()
    }

    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
    /// encoding.
    pub fn subtable_offset(&self) -> Offset32 {
        self.subtable_offset.get()
    }

    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
    /// encoding.
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn subtable<'a>(&self, data: FontData<'a>) -> Result<CmapSubtable<'a>, ReadError> {
        self.subtable_offset().resolve(data)
    }
}

impl FixedSize for EncodingRecord {
    const RAW_BYTE_LEN: usize =
        PlatformId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for EncodingRecord {
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
        RecordResolver {
            name: "EncodingRecord",
            get_field: Box::new(move |idx, _data| match idx {
                0usize => Some(Field::new("platform_id", self.platform_id())),
                1usize => Some(Field::new("encoding_id", self.encoding_id())),
                2usize => Some(Field::new(
                    "subtable_offset",
                    FieldType::offset(self.subtable_offset(), self.subtable(_data)),
                )),
                _ => None,
            }),
            data,
        }
    }
}

/// <https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#platform-ids>
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u16)]
#[allow(clippy::manual_non_exhaustive)]
pub enum PlatformId {
    #[default]
    Unicode = 0,
    Macintosh = 1,
    ISO = 2,
    Windows = 3,
    Custom = 4,
    #[doc(hidden)]
    /// If font data is malformed we will map unknown values to this variant
    Unknown,
}

impl PlatformId {
    /// Create from a raw scalar.
    ///
    /// This will never fail; unknown values will be mapped to the `Unknown` variant
    pub fn new(raw: u16) -> Self {
        match raw {
            0 => Self::Unicode,
            1 => Self::Macintosh,
            2 => Self::ISO,
            3 => Self::Windows,
            4 => Self::Custom,
            _ => Self::Unknown,
        }
    }
}

impl font_types::Scalar for PlatformId {
    type Raw = <u16 as font_types::Scalar>::Raw;
    fn to_raw(self) -> Self::Raw {
        (self as u16).to_raw()
    }
    fn from_raw(raw: Self::Raw) -> Self {
        let t = <u16>::from_raw(raw);
        Self::new(t)
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> From<PlatformId> for FieldType<'a> {
    fn from(src: PlatformId) -> FieldType<'a> {
        (src as u16).into()
    }
}

/// The different cmap subtable formats.
#[derive(Clone)]
pub enum CmapSubtable<'a> {
    Format0(Cmap0<'a>),
    Format2(Cmap2<'a>),
    Format4(Cmap4<'a>),
    Format6(Cmap6<'a>),
    Format8(Cmap8<'a>),
    Format10(Cmap10<'a>),
    Format12(Cmap12<'a>),
    Format13(Cmap13<'a>),
    Format14(Cmap14<'a>),
}

impl Default for CmapSubtable<'_> {
    fn default() -> Self {
        Self::Format0(Default::default())
    }
}

impl<'a> CmapSubtable<'a> {
    ///Return the `FontData` used to resolve offsets for this table.
    pub fn offset_data(&self) -> FontData<'a> {
        match self {
            Self::Format0(item) => item.offset_data(),
            Self::Format2(item) => item.offset_data(),
            Self::Format4(item) => item.offset_data(),
            Self::Format6(item) => item.offset_data(),
            Self::Format8(item) => item.offset_data(),
            Self::Format10(item) => item.offset_data(),
            Self::Format12(item) => item.offset_data(),
            Self::Format13(item) => item.offset_data(),
            Self::Format14(item) => item.offset_data(),
        }
    }

    /// Format number is set to 0.
    pub fn format(&self) -> u16 {
        match self {
            Self::Format0(item) => item.format(),
            Self::Format2(item) => item.format(),
            Self::Format4(item) => item.format(),
            Self::Format6(item) => item.format(),
            Self::Format8(item) => item.format(),
            Self::Format10(item) => item.format(),
            Self::Format12(item) => item.format(),
            Self::Format13(item) => item.format(),
            Self::Format14(item) => item.format(),
        }
    }
}

impl<'a> FontRead<'a> for CmapSubtable<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u16 = data.read_at(0usize)?;
        match format {
            Cmap0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
            Cmap2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
            Cmap4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
            Cmap6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
            Cmap8::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
            Cmap10::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
            Cmap12::FORMAT => Ok(Self::Format12(FontRead::read(data)?)),
            Cmap13::FORMAT => Ok(Self::Format13(FontRead::read(data)?)),
            Cmap14::FORMAT => Ok(Self::Format14(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl<'a> MinByteRange<'a> for CmapSubtable<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Format0(item) => item.min_byte_range(),
            Self::Format2(item) => item.min_byte_range(),
            Self::Format4(item) => item.min_byte_range(),
            Self::Format6(item) => item.min_byte_range(),
            Self::Format8(item) => item.min_byte_range(),
            Self::Format10(item) => item.min_byte_range(),
            Self::Format12(item) => item.min_byte_range(),
            Self::Format13(item) => item.min_byte_range(),
            Self::Format14(item) => item.min_byte_range(),
        }
    }
    fn min_table_bytes(&self) -> &'a [u8] {
        match self {
            Self::Format0(item) => item.min_table_bytes(),
            Self::Format2(item) => item.min_table_bytes(),
            Self::Format4(item) => item.min_table_bytes(),
            Self::Format6(item) => item.min_table_bytes(),
            Self::Format8(item) => item.min_table_bytes(),
            Self::Format10(item) => item.min_table_bytes(),
            Self::Format12(item) => item.min_table_bytes(),
            Self::Format13(item) => item.min_table_bytes(),
            Self::Format14(item) => item.min_table_bytes(),
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> CmapSubtable<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Format0(table) => table,
            Self::Format2(table) => table,
            Self::Format4(table) => table,
            Self::Format6(table) => table,
            Self::Format8(table) => table,
            Self::Format10(table) => table,
            Self::Format12(table) => table,
            Self::Format13(table) => table,
            Self::Format14(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for CmapSubtable<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.dyn_inner().fmt(f)
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for CmapSubtable<'a> {
    fn type_name(&self) -> &str {
        self.dyn_inner().type_name()
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        self.dyn_inner().get_field(idx)
    }
}

impl Format<u16> for Cmap0<'_> {
    const FORMAT: u16 = 0;
}

impl<'a> MinByteRange<'a> for Cmap0<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.glyph_id_array_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<'a> FontRead<'a> for Cmap0<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table): Byte encoding table
#[derive(Clone)]
pub struct Cmap0<'a> {
    data: FontData<'a>,
}

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

    /// Format number is set to 0.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// This is the length in bytes of the subtable.
    pub fn length(&self) -> u16 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u16 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// An array that maps character codes to glyph index values.
    pub fn glyph_id_array(&self) -> &'a [u8] {
        let range = self.glyph_id_array_byte_range();
        self.data.read_array(range).ok().unwrap()
    }

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

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

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

    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
        let start = self.language_byte_range().end;
        let end = start + (256_usize).saturating_mul(u8::RAW_BYTE_LEN);
        start..end
    }
}

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

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

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap0<'a> {
    fn type_name(&self) -> &str {
        "Cmap0"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap0<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

impl Format<u16> for Cmap2<'_> {
    const FORMAT: u16 = 2;
}

impl<'a> MinByteRange<'a> for Cmap2<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.sub_header_keys_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<'a> FontRead<'a> for Cmap2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table): High-byte mapping through table
#[derive(Clone)]
pub struct Cmap2<'a> {
    data: FontData<'a>,
}

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

    /// Format number is set to 2.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// This is the length in bytes of the subtable.
    pub fn length(&self) -> u16 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u16 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array that maps high bytes to subHeaders: value is subHeader
    /// index × 8.
    pub fn sub_header_keys(&self) -> &'a [BigEndian<u16>] {
        let range = self.sub_header_keys_byte_range();
        self.data.read_array(range).ok().unwrap()
    }

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

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

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

    pub fn sub_header_keys_byte_range(&self) -> Range<usize> {
        let start = self.language_byte_range().end;
        let end = start + (256_usize).saturating_mul(u16::RAW_BYTE_LEN);
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap2<'a> {
    fn type_name(&self) -> &str {
        "Cmap2"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("sub_header_keys", self.sub_header_keys())),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap2<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

/// Part of [Cmap2]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct SubHeader {
    /// First valid low byte for this SubHeader.
    pub first_code: BigEndian<u16>,
    /// Number of valid low bytes for this SubHeader.
    pub entry_count: BigEndian<u16>,
    /// See text below.
    pub id_delta: BigEndian<i16>,
    /// See text below.
    pub id_range_offset: BigEndian<u16>,
}

impl SubHeader {
    /// First valid low byte for this SubHeader.
    pub fn first_code(&self) -> u16 {
        self.first_code.get()
    }

    /// Number of valid low bytes for this SubHeader.
    pub fn entry_count(&self) -> u16 {
        self.entry_count.get()
    }

    /// See text below.
    pub fn id_delta(&self) -> i16 {
        self.id_delta.get()
    }

    /// See text below.
    pub fn id_range_offset(&self) -> u16 {
        self.id_range_offset.get()
    }
}

impl FixedSize for SubHeader {
    const RAW_BYTE_LEN: usize =
        u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for SubHeader {
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
        RecordResolver {
            name: "SubHeader",
            get_field: Box::new(move |idx, _data| match idx {
                0usize => Some(Field::new("first_code", self.first_code())),
                1usize => Some(Field::new("entry_count", self.entry_count())),
                2usize => Some(Field::new("id_delta", self.id_delta())),
                3usize => Some(Field::new("id_range_offset", self.id_range_offset())),
                _ => None,
            }),
            data,
        }
    }
}

impl Format<u16> for Cmap4<'_> {
    const FORMAT: u16 = 4;
}

impl<'a> MinByteRange<'a> for Cmap4<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.glyph_id_array_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<'a> FontRead<'a> for Cmap4<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values): Segment mapping to delta values
#[derive(Clone)]
pub struct Cmap4<'a> {
    data: FontData<'a>,
}

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

    /// Format number is set to 4.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// This is the length in bytes of the subtable.
    pub fn length(&self) -> u16 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u16 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// 2 × segCount.
    pub fn seg_count_x2(&self) -> u16 {
        let range = self.seg_count_x2_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Maximum power of 2 less than or equal to segCount, times 2
    /// ((2**floor(log2(segCount))) * 2, where “**” is an
    /// exponentiation operator)
    pub fn search_range(&self) -> u16 {
        let range = self.search_range_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Log2 of the maximum power of 2 less than or equal to numTables
    /// (log2(searchRange/2), which is equal to floor(log2(segCount)))
    pub fn entry_selector(&self) -> u16 {
        let range = self.entry_selector_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// segCount times 2, minus searchRange ((segCount * 2) -
    /// searchRange)
    pub fn range_shift(&self) -> u16 {
        let range = self.range_shift_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// End characterCode for each segment, last=0xFFFF.
    pub fn end_code(&self) -> &'a [BigEndian<u16>] {
        let range = self.end_code_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

    /// Start character code for each segment.
    pub fn start_code(&self) -> &'a [BigEndian<u16>] {
        let range = self.start_code_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

    /// Delta for all character codes in segment.
    pub fn id_delta(&self) -> &'a [BigEndian<i16>] {
        let range = self.id_delta_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

    /// Offsets into glyphIdArray or 0
    pub fn id_range_offsets(&self) -> &'a [BigEndian<u16>] {
        let range = self.id_range_offsets_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

    /// Glyph index array (arbitrary length)
    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
        let range = self.glyph_id_array_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

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

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

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

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

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

    pub fn end_code_byte_range(&self) -> Range<usize> {
        let seg_count_x2 = self.seg_count_x2();
        let start = self.range_shift_byte_range().end;
        let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
        start..end
    }

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

    pub fn start_code_byte_range(&self) -> Range<usize> {
        let seg_count_x2 = self.seg_count_x2();
        let start = self.reserved_pad_byte_range().end;
        let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
        start..end
    }

    pub fn id_delta_byte_range(&self) -> Range<usize> {
        let seg_count_x2 = self.seg_count_x2();
        let start = self.start_code_byte_range().end;
        let end = start + (transforms::half(seg_count_x2)).saturating_mul(i16::RAW_BYTE_LEN);
        start..end
    }

    pub fn id_range_offsets_byte_range(&self) -> Range<usize> {
        let seg_count_x2 = self.seg_count_x2();
        let start = self.id_delta_byte_range().end;
        let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
        start..end
    }

    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
        let start = self.id_range_offsets_byte_range().end;
        let end =
            start + self.data.len().saturating_sub(start) / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap4<'a> {
    fn type_name(&self) -> &str {
        "Cmap4"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("seg_count_x2", self.seg_count_x2())),
            4usize => Some(Field::new("search_range", self.search_range())),
            5usize => Some(Field::new("entry_selector", self.entry_selector())),
            6usize => Some(Field::new("range_shift", self.range_shift())),
            7usize => Some(Field::new("end_code", self.end_code())),
            8usize => Some(Field::new("start_code", self.start_code())),
            9usize => Some(Field::new("id_delta", self.id_delta())),
            10usize => Some(Field::new("id_range_offsets", self.id_range_offsets())),
            11usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap4<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

impl Format<u16> for Cmap6<'_> {
    const FORMAT: u16 = 6;
}

impl<'a> MinByteRange<'a> for Cmap6<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.glyph_id_array_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<'a> FontRead<'a> for Cmap6<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping): Trimmed table mapping
#[derive(Clone)]
pub struct Cmap6<'a> {
    data: FontData<'a>,
}

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

    /// Format number is set to 6.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// This is the length in bytes of the subtable.
    pub fn length(&self) -> u16 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u16 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// First character code of subrange.
    pub fn first_code(&self) -> u16 {
        let range = self.first_code_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Number of character codes in subrange.
    pub fn entry_count(&self) -> u16 {
        let range = self.entry_count_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array of glyph index values for character codes in the range.
    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
        let range = self.glyph_id_array_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

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

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

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

    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
        let entry_count = self.entry_count();
        let start = self.entry_count_byte_range().end;
        let end = start + (transforms::to_usize(entry_count)).saturating_mul(u16::RAW_BYTE_LEN);
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap6<'a> {
    fn type_name(&self) -> &str {
        "Cmap6"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("first_code", self.first_code())),
            4usize => Some(Field::new("entry_count", self.entry_count())),
            5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap6<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

impl Format<u16> for Cmap8<'_> {
    const FORMAT: u16 = 8;
}

impl<'a> MinByteRange<'a> for Cmap8<'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<'a> FontRead<'a> for Cmap8<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 8](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-8-mixed-16-bit-and-32-bit-coverage): mixed 16-bit and 32-bit coverage
#[derive(Clone)]
pub struct Cmap8<'a> {
    data: FontData<'a>,
}

#[allow(clippy::needless_lifetimes)]
impl<'a> Cmap8<'a> {
    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
        + u16::RAW_BYTE_LEN
        + u32::RAW_BYTE_LEN
        + u32::RAW_BYTE_LEN
        + u8::RAW_BYTE_LEN * 8192_usize
        + u32::RAW_BYTE_LEN);
    basic_table_impls!(impl_the_methods);

    /// Subtable format; set to 8.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Byte length of this subtable (including the header)
    pub fn length(&self) -> u32 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u32 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Tightly packed array of bits (8K bytes total) indicating
    /// whether the particular 16-bit (index) value is the start of a
    /// 32-bit character code
    pub fn is32(&self) -> &'a [u8] {
        let range = self.is32_byte_range();
        self.data.read_array(range).ok().unwrap()
    }

    /// Number of groupings which follow
    pub fn num_groups(&self) -> u32 {
        let range = self.num_groups_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array of SequentialMapGroup records.
    pub fn groups(&self) -> &'a [SequentialMapGroup] {
        let range = self.groups_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

    pub fn length_byte_range(&self) -> Range<usize> {
        let start = self.reserved_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn language_byte_range(&self) -> Range<usize> {
        let start = self.length_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn is32_byte_range(&self) -> Range<usize> {
        let start = self.language_byte_range().end;
        let end = start + (8192_usize).saturating_mul(u8::RAW_BYTE_LEN);
        start..end
    }

    pub fn num_groups_byte_range(&self) -> Range<usize> {
        let start = self.is32_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn groups_byte_range(&self) -> Range<usize> {
        let num_groups = self.num_groups();
        let start = self.num_groups_byte_range().end;
        let end = start
            + (transforms::to_usize(num_groups)).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN);
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap8<'a> {
    fn type_name(&self) -> &str {
        "Cmap8"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("is32", self.is32())),
            4usize => Some(Field::new("num_groups", self.num_groups())),
            5usize => Some(Field::new(
                "groups",
                traversal::FieldType::array_of_records(
                    stringify!(SequentialMapGroup),
                    self.groups(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap8<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

/// Used in [Cmap8] and [Cmap12]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct SequentialMapGroup {
    /// First character code in this group; note that if this group is
    /// for one or more 16-bit character codes (which is determined
    /// from the is32 array), this 32-bit value will have the high
    /// 16-bits set to zero
    pub start_char_code: BigEndian<u32>,
    /// Last character code in this group; same condition as listed
    /// above for the startCharCode
    pub end_char_code: BigEndian<u32>,
    /// Glyph index corresponding to the starting character code
    pub start_glyph_id: BigEndian<u32>,
}

impl SequentialMapGroup {
    /// First character code in this group; note that if this group is
    /// for one or more 16-bit character codes (which is determined
    /// from the is32 array), this 32-bit value will have the high
    /// 16-bits set to zero
    pub fn start_char_code(&self) -> u32 {
        self.start_char_code.get()
    }

    /// Last character code in this group; same condition as listed
    /// above for the startCharCode
    pub fn end_char_code(&self) -> u32 {
        self.end_char_code.get()
    }

    /// Glyph index corresponding to the starting character code
    pub fn start_glyph_id(&self) -> u32 {
        self.start_glyph_id.get()
    }
}

impl FixedSize for SequentialMapGroup {
    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for SequentialMapGroup {
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
        RecordResolver {
            name: "SequentialMapGroup",
            get_field: Box::new(move |idx, _data| match idx {
                0usize => Some(Field::new("start_char_code", self.start_char_code())),
                1usize => Some(Field::new("end_char_code", self.end_char_code())),
                2usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
                _ => None,
            }),
            data,
        }
    }
}

impl Format<u16> for Cmap10<'_> {
    const FORMAT: u16 = 10;
}

impl<'a> MinByteRange<'a> for Cmap10<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.glyph_id_array_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<'a> FontRead<'a> for Cmap10<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array): Tr
#[derive(Clone)]
pub struct Cmap10<'a> {
    data: FontData<'a>,
}

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

    /// Subtable format; set to 10.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Byte length of this subtable (including the header)
    pub fn length(&self) -> u32 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u32 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// First character code covered
    pub fn start_char_code(&self) -> u32 {
        let range = self.start_char_code_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Number of character codes covered
    pub fn num_chars(&self) -> u32 {
        let range = self.num_chars_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array of glyph indices for the character codes covered
    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
        let range = self.glyph_id_array_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

    pub fn length_byte_range(&self) -> Range<usize> {
        let start = self.reserved_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn language_byte_range(&self) -> Range<usize> {
        let start = self.length_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn start_char_code_byte_range(&self) -> Range<usize> {
        let start = self.language_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn num_chars_byte_range(&self) -> Range<usize> {
        let start = self.start_char_code_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
        let num_chars = self.num_chars();
        let start = self.num_chars_byte_range().end;
        let end = start + (transforms::to_usize(num_chars)).saturating_mul(u16::RAW_BYTE_LEN);
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap10<'a> {
    fn type_name(&self) -> &str {
        "Cmap10"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("start_char_code", self.start_char_code())),
            4usize => Some(Field::new("num_chars", self.num_chars())),
            5usize => Some(Field::new("glyph_id_array", self.glyph_id_array())),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap10<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

impl Format<u16> for Cmap12<'_> {
    const FORMAT: u16 = 12;
}

impl<'a> MinByteRange<'a> for Cmap12<'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<'a> FontRead<'a> for Cmap12<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage): Segmented coverage
#[derive(Clone)]
pub struct Cmap12<'a> {
    data: FontData<'a>,
}

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

    /// Subtable format; set to 12.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Byte length of this subtable (including the header)
    pub fn length(&self) -> u32 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u32 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Number of groupings which follow
    pub fn num_groups(&self) -> u32 {
        let range = self.num_groups_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array of SequentialMapGroup records.
    pub fn groups(&self) -> &'a [SequentialMapGroup] {
        let range = self.groups_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

    pub fn length_byte_range(&self) -> Range<usize> {
        let start = self.reserved_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn language_byte_range(&self) -> Range<usize> {
        let start = self.length_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn num_groups_byte_range(&self) -> Range<usize> {
        let start = self.language_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn groups_byte_range(&self) -> Range<usize> {
        let num_groups = self.num_groups();
        let start = self.num_groups_byte_range().end;
        let end = start
            + (transforms::to_usize(num_groups)).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN);
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap12<'a> {
    fn type_name(&self) -> &str {
        "Cmap12"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("num_groups", self.num_groups())),
            4usize => Some(Field::new(
                "groups",
                traversal::FieldType::array_of_records(
                    stringify!(SequentialMapGroup),
                    self.groups(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap12<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

impl Format<u16> for Cmap13<'_> {
    const FORMAT: u16 = 13;
}

impl<'a> MinByteRange<'a> for Cmap13<'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<'a> FontRead<'a> for Cmap13<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings): Many-to-one range mappings
#[derive(Clone)]
pub struct Cmap13<'a> {
    data: FontData<'a>,
}

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

    /// Subtable format; set to 13.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Byte length of this subtable (including the header)
    pub fn length(&self) -> u32 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// For requirements on use of the language field, see “Use of
    /// the language field in 'cmap' subtables” in this document.
    pub fn language(&self) -> u32 {
        let range = self.language_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Number of groupings which follow
    pub fn num_groups(&self) -> u32 {
        let range = self.num_groups_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array of ConstantMapGroup records.
    pub fn groups(&self) -> &'a [ConstantMapGroup] {
        let range = self.groups_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

    pub fn length_byte_range(&self) -> Range<usize> {
        let start = self.reserved_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn language_byte_range(&self) -> Range<usize> {
        let start = self.length_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn num_groups_byte_range(&self) -> Range<usize> {
        let start = self.language_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn groups_byte_range(&self) -> Range<usize> {
        let num_groups = self.num_groups();
        let start = self.num_groups_byte_range().end;
        let end = start
            + (transforms::to_usize(num_groups)).saturating_mul(ConstantMapGroup::RAW_BYTE_LEN);
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap13<'a> {
    fn type_name(&self) -> &str {
        "Cmap13"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new("language", self.language())),
            3usize => Some(Field::new("num_groups", self.num_groups())),
            4usize => Some(Field::new(
                "groups",
                traversal::FieldType::array_of_records(
                    stringify!(ConstantMapGroup),
                    self.groups(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap13<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

/// Part of [Cmap13]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct ConstantMapGroup {
    /// First character code in this group
    pub start_char_code: BigEndian<u32>,
    /// Last character code in this group
    pub end_char_code: BigEndian<u32>,
    /// Glyph index to be used for all the characters in the group’s
    /// range.
    pub glyph_id: BigEndian<u32>,
}

impl ConstantMapGroup {
    /// First character code in this group
    pub fn start_char_code(&self) -> u32 {
        self.start_char_code.get()
    }

    /// Last character code in this group
    pub fn end_char_code(&self) -> u32 {
        self.end_char_code.get()
    }

    /// Glyph index to be used for all the characters in the group’s
    /// range.
    pub fn glyph_id(&self) -> u32 {
        self.glyph_id.get()
    }
}

impl FixedSize for ConstantMapGroup {
    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for ConstantMapGroup {
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
        RecordResolver {
            name: "ConstantMapGroup",
            get_field: Box::new(move |idx, _data| match idx {
                0usize => Some(Field::new("start_char_code", self.start_char_code())),
                1usize => Some(Field::new("end_char_code", self.end_char_code())),
                2usize => Some(Field::new("glyph_id", self.glyph_id())),
                _ => None,
            }),
            data,
        }
    }
}

impl Format<u16> for Cmap14<'_> {
    const FORMAT: u16 = 14;
}

impl<'a> MinByteRange<'a> for Cmap14<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.var_selector_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<'a> FontRead<'a> for Cmap14<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [cmap Format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences): Unicode Variation Sequences
#[derive(Clone)]
pub struct Cmap14<'a> {
    data: FontData<'a>,
}

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

    /// Subtable format. Set to 14.
    pub fn format(&self) -> u16 {
        let range = self.format_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Byte length of this subtable (including this header)
    pub fn length(&self) -> u32 {
        let range = self.length_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Number of variation Selector Records
    pub fn num_var_selector_records(&self) -> u32 {
        let range = self.num_var_selector_records_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array of VariationSelector records.
    pub fn var_selector(&self) -> &'a [VariationSelector] {
        let range = self.var_selector_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

    pub fn length_byte_range(&self) -> Range<usize> {
        let start = self.format_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn num_var_selector_records_byte_range(&self) -> Range<usize> {
        let start = self.length_byte_range().end;
        let end = start + u32::RAW_BYTE_LEN;
        start..end
    }

    pub fn var_selector_byte_range(&self) -> Range<usize> {
        let num_var_selector_records = self.num_var_selector_records();
        let start = self.num_var_selector_records_byte_range().end;
        let end = start
            + (transforms::to_usize(num_var_selector_records))
                .saturating_mul(VariationSelector::RAW_BYTE_LEN);
        start..end
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Cmap14<'a> {
    fn type_name(&self) -> &str {
        "Cmap14"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("length", self.length())),
            2usize => Some(Field::new(
                "num_var_selector_records",
                self.num_var_selector_records(),
            )),
            3usize => Some(Field::new(
                "var_selector",
                traversal::FieldType::array_of_records(
                    stringify!(VariationSelector),
                    self.var_selector(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for Cmap14<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

/// Part of [Cmap14]
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct VariationSelector {
    /// Variation selector
    pub var_selector: BigEndian<Uint24>,
    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
    /// Table. May be NULL.
    pub default_uvs_offset: BigEndian<Nullable<Offset32>>,
    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
    /// UVS Table. May be NULL.
    pub non_default_uvs_offset: BigEndian<Nullable<Offset32>>,
}

impl VariationSelector {
    /// Variation selector
    pub fn var_selector(&self) -> Uint24 {
        self.var_selector.get()
    }

    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
    /// Table. May be NULL.
    pub fn default_uvs_offset(&self) -> Nullable<Offset32> {
        self.default_uvs_offset.get()
    }

    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
    /// Table. May be NULL.
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn default_uvs<'a>(&self, data: FontData<'a>) -> Option<Result<DefaultUvs<'a>, ReadError>> {
        self.default_uvs_offset().resolve(data)
    }

    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
    /// UVS Table. May be NULL.
    pub fn non_default_uvs_offset(&self) -> Nullable<Offset32> {
        self.non_default_uvs_offset.get()
    }

    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
    /// UVS Table. May be NULL.
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn non_default_uvs<'a>(
        &self,
        data: FontData<'a>,
    ) -> Option<Result<NonDefaultUvs<'a>, ReadError>> {
        self.non_default_uvs_offset().resolve(data)
    }
}

impl FixedSize for VariationSelector {
    const RAW_BYTE_LEN: usize =
        Uint24::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for VariationSelector {
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
        RecordResolver {
            name: "VariationSelector",
            get_field: Box::new(move |idx, _data| match idx {
                0usize => Some(Field::new("var_selector", self.var_selector())),
                1usize => Some(Field::new(
                    "default_uvs_offset",
                    FieldType::offset(self.default_uvs_offset(), self.default_uvs(_data)),
                )),
                2usize => Some(Field::new(
                    "non_default_uvs_offset",
                    FieldType::offset(self.non_default_uvs_offset(), self.non_default_uvs(_data)),
                )),
                _ => None,
            }),
            data,
        }
    }
}

impl<'a> MinByteRange<'a> for DefaultUvs<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.ranges_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<'a> FontRead<'a> for DefaultUvs<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [Default UVS table](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#default-uvs-table)
#[derive(Clone)]
pub struct DefaultUvs<'a> {
    data: FontData<'a>,
}

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

    /// Number of Unicode character ranges.
    pub fn num_unicode_value_ranges(&self) -> u32 {
        let range = self.num_unicode_value_ranges_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Array of UnicodeRange records.
    pub fn ranges(&self) -> &'a [UnicodeRange] {
        let range = self.ranges_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

    pub fn ranges_byte_range(&self) -> Range<usize> {
        let num_unicode_value_ranges = self.num_unicode_value_ranges();
        let start = self.num_unicode_value_ranges_byte_range().end;
        let end = start
            + (transforms::to_usize(num_unicode_value_ranges))
                .saturating_mul(UnicodeRange::RAW_BYTE_LEN);
        start..end
    }
}

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

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

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for DefaultUvs<'a> {
    fn type_name(&self) -> &str {
        "DefaultUvs"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "num_unicode_value_ranges",
                self.num_unicode_value_ranges(),
            )),
            1usize => Some(Field::new(
                "ranges",
                traversal::FieldType::array_of_records(
                    stringify!(UnicodeRange),
                    self.ranges(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for DefaultUvs<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

impl<'a> MinByteRange<'a> for NonDefaultUvs<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.uvs_mapping_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<'a> FontRead<'a> for NonDefaultUvs<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        #[allow(clippy::absurd_extreme_comparisons)]
        if data.len() < Self::MIN_SIZE {
            return Err(ReadError::OutOfBounds);
        }
        Ok(Self { data })
    }
}

/// [Non-Default UVS table](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#non-default-uvs-table)
#[derive(Clone)]
pub struct NonDefaultUvs<'a> {
    data: FontData<'a>,
}

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

    pub fn num_uvs_mappings(&self) -> u32 {
        let range = self.num_uvs_mappings_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    pub fn uvs_mapping(&self) -> &'a [UvsMapping] {
        let range = self.uvs_mapping_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

    pub fn uvs_mapping_byte_range(&self) -> Range<usize> {
        let num_uvs_mappings = self.num_uvs_mappings();
        let start = self.num_uvs_mappings_byte_range().end;
        let end = start
            + (transforms::to_usize(num_uvs_mappings)).saturating_mul(UvsMapping::RAW_BYTE_LEN);
        start..end
    }
}

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

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

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for NonDefaultUvs<'a> {
    fn type_name(&self) -> &str {
        "NonDefaultUvs"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("num_uvs_mappings", self.num_uvs_mappings())),
            1usize => Some(Field::new(
                "uvs_mapping",
                traversal::FieldType::array_of_records(
                    stringify!(UvsMapping),
                    self.uvs_mapping(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
#[allow(clippy::needless_lifetimes)]
impl<'a> std::fmt::Debug for NonDefaultUvs<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (self as &dyn SomeTable<'a>).fmt(f)
    }
}

/// Part of [Cmap14]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct UvsMapping {
    /// Base Unicode value of the UVS
    pub unicode_value: BigEndian<Uint24>,
    /// Glyph ID of the UVS
    pub glyph_id: BigEndian<u16>,
}

impl UvsMapping {
    /// Base Unicode value of the UVS
    pub fn unicode_value(&self) -> Uint24 {
        self.unicode_value.get()
    }

    /// Glyph ID of the UVS
    pub fn glyph_id(&self) -> u16 {
        self.glyph_id.get()
    }
}

impl FixedSize for UvsMapping {
    const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for UvsMapping {
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
        RecordResolver {
            name: "UvsMapping",
            get_field: Box::new(move |idx, _data| match idx {
                0usize => Some(Field::new("unicode_value", self.unicode_value())),
                1usize => Some(Field::new("glyph_id", self.glyph_id())),
                _ => None,
            }),
            data,
        }
    }
}

/// Part of [Cmap14]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct UnicodeRange {
    /// First value in this range
    pub start_unicode_value: BigEndian<Uint24>,
    /// Number of additional values in this range
    pub additional_count: u8,
}

impl UnicodeRange {
    /// First value in this range
    pub fn start_unicode_value(&self) -> Uint24 {
        self.start_unicode_value.get()
    }

    /// Number of additional values in this range
    pub fn additional_count(&self) -> u8 {
        self.additional_count
    }
}

impl FixedSize for UnicodeRange {
    const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeRecord<'a> for UnicodeRange {
    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
        RecordResolver {
            name: "UnicodeRange",
            get_field: Box::new(move |idx, _data| match idx {
                0usize => Some(Field::new(
                    "start_unicode_value",
                    self.start_unicode_value(),
                )),
                1usize => Some(Field::new("additional_count", self.additional_count())),
                _ => None,
            }),
            data,
        }
    }
}
