// 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 OtKern<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.subtable_data_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 OtKern<'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 })
    }
}

/// The OpenType [kerning](https://learn.microsoft.com/en-us/typography/opentype/spec/kern) table.
#[derive(Clone)]
pub struct OtKern<'a> {
    data: FontData<'a>,
}

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

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

    /// Number of subtables in the kerning table.
    pub fn n_tables(&self) -> u16 {
        let range = self.n_tables_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Data for subtables, immediately following the header.
    pub fn subtable_data(&self) -> &'a [u8] {
        let range = self.subtable_data_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

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

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

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

impl<'a> MinByteRange<'a> for AatKern<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.subtable_data_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 AatKern<'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 })
    }
}

/// The Apple Advanced Typography [kerning](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html) table.
#[derive(Clone)]
pub struct AatKern<'a> {
    data: FontData<'a>,
}

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

    /// The version number of the kerning table (0x00010000 for the current version).
    pub fn version(&self) -> MajorMinor {
        let range = self.version_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The number of subtables included in the kerning table.
    pub fn n_tables(&self) -> u32 {
        let range = self.n_tables_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Data for subtables, immediately following the header.    
    pub fn subtable_data(&self) -> &'a [u8] {
        let range = self.subtable_data_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

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

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

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

impl<'a> MinByteRange<'a> for OtSubtable<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.data_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 OtSubtable<'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 })
    }
}

/// A subtable in an OT `kern` table.
#[derive(Clone)]
pub struct OtSubtable<'a> {
    data: FontData<'a>,
}

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

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

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

    /// Circumstances under which this table is used.
    pub fn coverage(&self) -> u16 {
        let range = self.coverage_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Subtable specific data.
    pub fn data(&self) -> &'a [u8] {
        let range = self.data_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

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

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

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

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

impl<'a> MinByteRange<'a> for AatSubtable<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.data_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 AatSubtable<'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 })
    }
}

/// A subtable in an AAT `kern` table.
#[derive(Clone)]
pub struct AatSubtable<'a> {
    data: FontData<'a>,
}

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

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

    /// Circumstances under which this table is used.
    pub fn coverage(&self) -> u16 {
        let range = self.coverage_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The tuple index (used for variations fonts). This value specifies which tuple this subtable covers.
    pub fn tuple_index(&self) -> u16 {
        let range = self.tuple_index_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Subtable specific data.
    pub fn data(&self) -> &'a [u8] {
        let range = self.data_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

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

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

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

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

impl<'a> MinByteRange<'a> for Subtable0<'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<'a> FontRead<'a> for Subtable0<'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 })
    }
}

/// The type 0 `kern` subtable.
#[derive(Clone)]
pub struct Subtable0<'a> {
    data: FontData<'a>,
}

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

    /// The number of kerning pairs in this subtable.
    pub fn n_pairs(&self) -> u16 {
        let range = self.n_pairs_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The largest power of two less than or equal to the value of nPairs, multiplied by the size in bytes of an entry in the subtable.
    pub fn search_range(&self) -> u16 {
        let range = self.search_range_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// This is calculated as log2 of the largest power of two less than or equal to the value of nPairs. This value indicates how many iterations of the search loop have to be made. For example, in a list of eight items, there would be three iterations of the loop.
    pub fn entry_selector(&self) -> u16 {
        let range = self.entry_selector_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The value of nPairs minus the largest power of two less than or equal to nPairs. This is multiplied by the size in bytes of an entry in the table.
    pub fn range_shift(&self) -> u16 {
        let range = self.range_shift_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Kerning records.
    pub fn pairs(&self) -> &'a [Subtable0Pair] {
        let range = self.pairs_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

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

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

    pub fn pairs_byte_range(&self) -> Range<usize> {
        let n_pairs = self.n_pairs();
        let start = self.range_shift_byte_range().end;
        start..start + (n_pairs as usize).saturating_mul(Subtable0Pair::RAW_BYTE_LEN)
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Subtable0<'a> {
    fn type_name(&self) -> &str {
        "Subtable0"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("n_pairs", self.n_pairs())),
            1usize => Some(Field::new("search_range", self.search_range())),
            2usize => Some(Field::new("entry_selector", self.entry_selector())),
            3usize => Some(Field::new("range_shift", self.range_shift())),
            4usize => Some(Field::new(
                "pairs",
                traversal::FieldType::array_of_records(
                    stringify!(Subtable0Pair),
                    self.pairs(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

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

impl<'a> MinByteRange<'a> for Subtable2ClassTable<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.offsets_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 Subtable2ClassTable<'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 })
    }
}

/// Class table for the type 2 `kern` subtable.
#[derive(Clone)]
pub struct Subtable2ClassTable<'a> {
    data: FontData<'a>,
}

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

    /// First glyph in class range.
    pub fn first_glyph(&self) -> GlyphId16 {
        let range = self.first_glyph_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Number of glyph in class range.
    pub fn n_glyphs(&self) -> u16 {
        let range = self.n_glyphs_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The offsets array for all of the glyphs in the range.
    pub fn offsets(&self) -> &'a [BigEndian<u16>] {
        let range = self.offsets_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

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

    pub fn offsets_byte_range(&self) -> Range<usize> {
        let n_glyphs = self.n_glyphs();
        let start = self.n_glyphs_byte_range().end;
        start..start + (n_glyphs as usize).saturating_mul(u16::RAW_BYTE_LEN)
    }
}

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

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

impl<'a> MinByteRange<'a> for Subtable3<'a> {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.kern_index_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 Subtable3<'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 })
    }
}

/// The type 3 'kern' subtable.
#[derive(Clone)]
pub struct Subtable3<'a> {
    data: FontData<'a>,
}

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

    /// The number of glyphs in this font.
    pub fn glyph_count(&self) -> u16 {
        let range = self.glyph_count_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The number of kerning values.
    pub fn kern_value_count(&self) -> u8 {
        let range = self.kern_value_count_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The number of left-hand classes.
    pub fn left_class_count(&self) -> u8 {
        let range = self.left_class_count_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The number of right-hand classes.
    pub fn right_class_count(&self) -> u8 {
        let range = self.right_class_count_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// Set to zero (reserved for future use).
    pub fn flags(&self) -> u8 {
        let range = self.flags_byte_range();
        self.data.read_at(range.start).ok().unwrap()
    }

    /// The kerning values.
    pub fn kern_value(&self) -> &'a [BigEndian<i16>] {
        let range = self.kern_value_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

    /// The left-hand classes.
    pub fn left_class(&self) -> &'a [u8] {
        let range = self.left_class_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

    /// The right-hand classes.
    pub fn right_class(&self) -> &'a [u8] {
        let range = self.right_class_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

    /// The indices into the kernValue array.
    pub fn kern_index(&self) -> &'a [u8] {
        let range = self.kern_index_byte_range();
        self.data.read_array(range).ok().unwrap_or_default()
    }

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

    pub fn kern_value_count_byte_range(&self) -> Range<usize> {
        let start = self.glyph_count_byte_range().end;
        start..start + u8::RAW_BYTE_LEN
    }

    pub fn left_class_count_byte_range(&self) -> Range<usize> {
        let start = self.kern_value_count_byte_range().end;
        start..start + u8::RAW_BYTE_LEN
    }

    pub fn right_class_count_byte_range(&self) -> Range<usize> {
        let start = self.left_class_count_byte_range().end;
        start..start + u8::RAW_BYTE_LEN
    }

    pub fn flags_byte_range(&self) -> Range<usize> {
        let start = self.right_class_count_byte_range().end;
        start..start + u8::RAW_BYTE_LEN
    }

    pub fn kern_value_byte_range(&self) -> Range<usize> {
        let kern_value_count = self.kern_value_count();
        let start = self.flags_byte_range().end;
        start..start + (kern_value_count as usize).saturating_mul(i16::RAW_BYTE_LEN)
    }

    pub fn left_class_byte_range(&self) -> Range<usize> {
        let glyph_count = self.glyph_count();
        let start = self.kern_value_byte_range().end;
        start..start + (glyph_count as usize).saturating_mul(u8::RAW_BYTE_LEN)
    }

    pub fn right_class_byte_range(&self) -> Range<usize> {
        let glyph_count = self.glyph_count();
        let start = self.left_class_byte_range().end;
        start..start + (glyph_count as usize).saturating_mul(u8::RAW_BYTE_LEN)
    }

    pub fn kern_index_byte_range(&self) -> Range<usize> {
        let left_class_count = self.left_class_count();
        let right_class_count = self.right_class_count();
        let start = self.right_class_byte_range().end;
        start
            ..start
                + (transforms::add_multiply(left_class_count, 0_usize, right_class_count))
                    .saturating_mul(u8::RAW_BYTE_LEN)
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Subtable3<'a> {
    fn type_name(&self) -> &str {
        "Subtable3"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("glyph_count", self.glyph_count())),
            1usize => Some(Field::new("kern_value_count", self.kern_value_count())),
            2usize => Some(Field::new("left_class_count", self.left_class_count())),
            3usize => Some(Field::new("right_class_count", self.right_class_count())),
            4usize => Some(Field::new("flags", self.flags())),
            5usize => Some(Field::new("kern_value", self.kern_value())),
            6usize => Some(Field::new("left_class", self.left_class())),
            7usize => Some(Field::new("right_class", self.right_class())),
            8usize => Some(Field::new("kern_index", self.kern_index())),
            _ => None,
        }
    }
}

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