// 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::*;

/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ScriptListMarker {
    script_records_byte_len: usize,
}

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

    pub fn script_records_byte_range(&self) -> Range<usize> {
        let start = self.script_count_byte_range().end;
        start..start + self.script_records_byte_len
    }
}

impl MinByteRange for ScriptListMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.script_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for ScriptList<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let script_count: u16 = cursor.read()?;
        let script_records_byte_len = (script_count as usize)
            .checked_mul(ScriptRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(script_records_byte_len);
        cursor.finish(ScriptListMarker {
            script_records_byte_len,
        })
    }
}

/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
pub type ScriptList<'a> = TableRef<'a, ScriptListMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ScriptList<'a> {
    /// Number of ScriptRecords
    pub fn script_count(&self) -> u16 {
        let range = self.shape.script_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of ScriptRecords, listed alphabetically by script tag
    pub fn script_records(&self) -> &'a [ScriptRecord] {
        let range = self.shape.script_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct ScriptRecord {
    /// 4-byte script tag identifier
    pub script_tag: BigEndian<Tag>,
    /// Offset to Script table, from beginning of ScriptList
    pub script_offset: BigEndian<Offset16>,
}

impl ScriptRecord {
    /// 4-byte script tag identifier
    pub fn script_tag(&self) -> Tag {
        self.script_tag.get()
    }

    /// Offset to Script table, from beginning of ScriptList
    pub fn script_offset(&self) -> Offset16 {
        self.script_offset.get()
    }

    /// Offset to Script table, from beginning of ScriptList
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn script<'a>(&self, data: FontData<'a>) -> Result<Script<'a>, ReadError> {
        self.script_offset().resolve(data)
    }
}

impl FixedSize for ScriptRecord {
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
}

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

/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ScriptMarker {
    lang_sys_records_byte_len: usize,
}

impl ScriptMarker {
    pub fn default_lang_sys_offset_byte_range(&self) -> Range<usize> {
        let start = 0;
        start..start + Offset16::RAW_BYTE_LEN
    }

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

    pub fn lang_sys_records_byte_range(&self) -> Range<usize> {
        let start = self.lang_sys_count_byte_range().end;
        start..start + self.lang_sys_records_byte_len
    }
}

impl MinByteRange for ScriptMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.lang_sys_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for Script<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<Offset16>();
        let lang_sys_count: u16 = cursor.read()?;
        let lang_sys_records_byte_len = (lang_sys_count as usize)
            .checked_mul(LangSysRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(lang_sys_records_byte_len);
        cursor.finish(ScriptMarker {
            lang_sys_records_byte_len,
        })
    }
}

/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
pub type Script<'a> = TableRef<'a, ScriptMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> Script<'a> {
    /// Offset to default LangSys table, from beginning of Script table
    /// — may be NULL
    pub fn default_lang_sys_offset(&self) -> Nullable<Offset16> {
        let range = self.shape.default_lang_sys_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`default_lang_sys_offset`][Self::default_lang_sys_offset].
    pub fn default_lang_sys(&self) -> Option<Result<LangSys<'a>, ReadError>> {
        let data = self.data;
        self.default_lang_sys_offset().resolve(data)
    }

    /// Number of LangSysRecords for this script — excluding the
    /// default LangSys
    pub fn lang_sys_count(&self) -> u16 {
        let range = self.shape.lang_sys_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of LangSysRecords, listed alphabetically by LangSys tag
    pub fn lang_sys_records(&self) -> &'a [LangSysRecord] {
        let range = self.shape.lang_sys_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Script<'a> {
    fn type_name(&self) -> &str {
        "Script"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "default_lang_sys_offset",
                FieldType::offset(self.default_lang_sys_offset(), self.default_lang_sys()),
            )),
            1usize => Some(Field::new("lang_sys_count", self.lang_sys_count())),
            2usize => Some(Field::new(
                "lang_sys_records",
                traversal::FieldType::array_of_records(
                    stringify!(LangSysRecord),
                    self.lang_sys_records(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

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

#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct LangSysRecord {
    /// 4-byte LangSysTag identifier
    pub lang_sys_tag: BigEndian<Tag>,
    /// Offset to LangSys table, from beginning of Script table
    pub lang_sys_offset: BigEndian<Offset16>,
}

impl LangSysRecord {
    /// 4-byte LangSysTag identifier
    pub fn lang_sys_tag(&self) -> Tag {
        self.lang_sys_tag.get()
    }

    /// Offset to LangSys table, from beginning of Script table
    pub fn lang_sys_offset(&self) -> Offset16 {
        self.lang_sys_offset.get()
    }

    /// Offset to LangSys table, from beginning of Script table
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn lang_sys<'a>(&self, data: FontData<'a>) -> Result<LangSys<'a>, ReadError> {
        self.lang_sys_offset().resolve(data)
    }
}

impl FixedSize for LangSysRecord {
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
}

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

/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct LangSysMarker {
    feature_indices_byte_len: usize,
}

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

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

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

    pub fn feature_indices_byte_range(&self) -> Range<usize> {
        let start = self.feature_index_count_byte_range().end;
        start..start + self.feature_indices_byte_len
    }
}

impl MinByteRange for LangSysMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.feature_indices_byte_range().end
    }
}

impl<'a> FontRead<'a> for LangSys<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        let feature_index_count: u16 = cursor.read()?;
        let feature_indices_byte_len = (feature_index_count as usize)
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(feature_indices_byte_len);
        cursor.finish(LangSysMarker {
            feature_indices_byte_len,
        })
    }
}

/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
pub type LangSys<'a> = TableRef<'a, LangSysMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> LangSys<'a> {
    /// Index of a feature required for this language system; if no
    /// required features = 0xFFFF
    pub fn required_feature_index(&self) -> u16 {
        let range = self.shape.required_feature_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of feature index values for this language system —
    /// excludes the required feature
    pub fn feature_index_count(&self) -> u16 {
        let range = self.shape.feature_index_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of indices into the FeatureList, in arbitrary order
    pub fn feature_indices(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.feature_indices_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureListMarker {
    feature_records_byte_len: usize,
}

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

    pub fn feature_records_byte_range(&self) -> Range<usize> {
        let start = self.feature_count_byte_range().end;
        start..start + self.feature_records_byte_len
    }
}

impl MinByteRange for FeatureListMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.feature_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for FeatureList<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let feature_count: u16 = cursor.read()?;
        let feature_records_byte_len = (feature_count as usize)
            .checked_mul(FeatureRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(feature_records_byte_len);
        cursor.finish(FeatureListMarker {
            feature_records_byte_len,
        })
    }
}

/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
pub type FeatureList<'a> = TableRef<'a, FeatureListMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> FeatureList<'a> {
    /// Number of FeatureRecords in this table
    pub fn feature_count(&self) -> u16 {
        let range = self.shape.feature_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of FeatureRecords — zero-based (first feature has
    /// FeatureIndex = 0), listed alphabetically by feature tag
    pub fn feature_records(&self) -> &'a [FeatureRecord] {
        let range = self.shape.feature_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Part of [FeatureList]
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FeatureRecord {
    /// 4-byte feature identification tag
    pub feature_tag: BigEndian<Tag>,
    /// Offset to Feature table, from beginning of FeatureList
    pub feature_offset: BigEndian<Offset16>,
}

impl FeatureRecord {
    /// 4-byte feature identification tag
    pub fn feature_tag(&self) -> Tag {
        self.feature_tag.get()
    }

    /// Offset to Feature table, from beginning of FeatureList
    pub fn feature_offset(&self) -> Offset16 {
        self.feature_offset.get()
    }

    /// Offset to Feature table, from beginning of FeatureList
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
        let args = self.feature_tag();
        self.feature_offset().resolve_with_args(data, &args)
    }
}

impl FixedSize for FeatureRecord {
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
}

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

/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureMarker {
    feature_tag: Tag,
    lookup_list_indices_byte_len: usize,
}

impl FeatureMarker {
    pub fn feature_params_offset_byte_range(&self) -> Range<usize> {
        let start = 0;
        start..start + Offset16::RAW_BYTE_LEN
    }

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

    pub fn lookup_list_indices_byte_range(&self) -> Range<usize> {
        let start = self.lookup_index_count_byte_range().end;
        start..start + self.lookup_list_indices_byte_len
    }
}

impl MinByteRange for FeatureMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.lookup_list_indices_byte_range().end
    }
}

impl ReadArgs for Feature<'_> {
    type Args = Tag;
}

impl<'a> FontReadWithArgs<'a> for Feature<'a> {
    fn read_with_args(data: FontData<'a>, args: &Tag) -> Result<Self, ReadError> {
        let feature_tag = *args;
        let mut cursor = data.cursor();
        cursor.advance::<Offset16>();
        let lookup_index_count: u16 = cursor.read()?;
        let lookup_list_indices_byte_len = (lookup_index_count as usize)
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(lookup_list_indices_byte_len);
        cursor.finish(FeatureMarker {
            feature_tag,
            lookup_list_indices_byte_len,
        })
    }
}

impl<'a> Feature<'a> {
    /// A constructor that requires additional arguments.
    ///
    /// This type requires some external state in order to be
    /// parsed.
    pub fn read(data: FontData<'a>, feature_tag: Tag) -> Result<Self, ReadError> {
        let args = feature_tag;
        Self::read_with_args(data, &args)
    }
}

/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
pub type Feature<'a> = TableRef<'a, FeatureMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> Feature<'a> {
    /// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL
    pub fn feature_params_offset(&self) -> Nullable<Offset16> {
        let range = self.shape.feature_params_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`feature_params_offset`][Self::feature_params_offset].
    pub fn feature_params(&self) -> Option<Result<FeatureParams<'a>, ReadError>> {
        let data = self.data;
        let args = self.feature_tag();
        self.feature_params_offset().resolve_with_args(data, &args)
    }

    /// Number of LookupList indices for this feature
    pub fn lookup_index_count(&self) -> u16 {
        let range = self.shape.lookup_index_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of indices into the LookupList — zero-based (first
    /// lookup is LookupListIndex = 0)
    pub fn lookup_list_indices(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.lookup_list_indices_byte_range();
        self.data.read_array(range).unwrap()
    }

    pub(crate) fn feature_tag(&self) -> Tag {
        self.shape.feature_tag
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Feature<'a> {
    fn type_name(&self) -> &str {
        "Feature"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "feature_params_offset",
                FieldType::offset(self.feature_params_offset(), self.feature_params()),
            )),
            1usize => Some(Field::new("lookup_index_count", self.lookup_index_count())),
            2usize => Some(Field::new(
                "lookup_list_indices",
                self.lookup_list_indices(),
            )),
            _ => None,
        }
    }
}

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

/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
#[derive(Debug)]
#[doc(hidden)]
pub struct LookupListMarker<T = ()> {
    lookup_offsets_byte_len: usize,
    offset_type: std::marker::PhantomData<*const T>,
}

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

    pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
        let start = self.lookup_count_byte_range().end;
        start..start + self.lookup_offsets_byte_len
    }
}

impl MinByteRange for LookupListMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.lookup_offsets_byte_range().end
    }
}

impl<T> Clone for LookupListMarker<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Copy for LookupListMarker<T> {}

impl<'a, T> FontRead<'a> for LookupList<'a, T> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let lookup_count: u16 = cursor.read()?;
        let lookup_offsets_byte_len = (lookup_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(lookup_offsets_byte_len);
        cursor.finish(LookupListMarker {
            lookup_offsets_byte_len,
            offset_type: std::marker::PhantomData,
        })
    }
}

impl<'a> LookupList<'a, ()> {
    #[allow(dead_code)]
    pub(crate) fn into_concrete<T>(self) -> LookupList<'a, T> {
        let TableRef { data, shape } = self;
        TableRef {
            shape: LookupListMarker {
                lookup_offsets_byte_len: shape.lookup_offsets_byte_len,
                offset_type: std::marker::PhantomData,
            },
            data,
        }
    }
}

impl<'a, T> LookupList<'a, T> {
    #[allow(dead_code)]
    /// Replace the specific generic type on this implementation with `()`
    pub(crate) fn of_unit_type(&self) -> LookupList<'a, ()> {
        let TableRef { data, shape } = self;
        TableRef {
            shape: LookupListMarker {
                lookup_offsets_byte_len: shape.lookup_offsets_byte_len,
                offset_type: std::marker::PhantomData,
            },
            data: *data,
        }
    }
}

/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
pub type LookupList<'a, T> = TableRef<'a, LookupListMarker<T>>;

#[allow(clippy::needless_lifetimes)]
impl<'a, T> LookupList<'a, T> {
    /// Number of lookups in this table
    pub fn lookup_count(&self) -> u16 {
        let range = self.shape.lookup_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to Lookup tables, from beginning of LookupList
    /// — zero based (first lookup is Lookup index = 0)
    pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.lookup_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`lookup_offsets`][Self::lookup_offsets].
    pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset16>
    where
        T: FontRead<'a>,
    {
        let data = self.data;
        let offsets = self.lookup_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for LookupList<'a, T> {
    fn type_name(&self) -> &str {
        "LookupList"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("lookup_count", self.lookup_count())),
            1usize => Some({
                let data = self.data;
                Field::new(
                    "lookup_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<T>(),
                        self.lookup_offsets(),
                        move |off| {
                            let target = off.get().resolve::<T>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
#[derive(Debug)]
#[doc(hidden)]
pub struct LookupMarker<T = ()> {
    subtable_offsets_byte_len: usize,
    mark_filtering_set_byte_start: Option<usize>,
    offset_type: std::marker::PhantomData<*const T>,
}

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

    pub fn lookup_flag_byte_range(&self) -> Range<usize> {
        let start = self.lookup_type_byte_range().end;
        start..start + LookupFlag::RAW_BYTE_LEN
    }

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

    pub fn subtable_offsets_byte_range(&self) -> Range<usize> {
        let start = self.sub_table_count_byte_range().end;
        start..start + self.subtable_offsets_byte_len
    }

    pub fn mark_filtering_set_byte_range(&self) -> Option<Range<usize>> {
        let start = self.mark_filtering_set_byte_start?;
        Some(start..start + u16::RAW_BYTE_LEN)
    }
}

impl MinByteRange for LookupMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.subtable_offsets_byte_range().end
    }
}

impl<T> Clone for LookupMarker<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Copy for LookupMarker<T> {}

impl<'a, T> FontRead<'a> for Lookup<'a, T> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let lookup_flag: LookupFlag = cursor.read()?;
        let sub_table_count: u16 = cursor.read()?;
        let subtable_offsets_byte_len = (sub_table_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(subtable_offsets_byte_len);
        let mark_filtering_set_byte_start = lookup_flag
            .contains(LookupFlag::USE_MARK_FILTERING_SET)
            .then(|| cursor.position())
            .transpose()?;
        lookup_flag
            .contains(LookupFlag::USE_MARK_FILTERING_SET)
            .then(|| cursor.advance::<u16>());
        cursor.finish(LookupMarker {
            subtable_offsets_byte_len,
            mark_filtering_set_byte_start,
            offset_type: std::marker::PhantomData,
        })
    }
}

impl<'a> Lookup<'a, ()> {
    #[allow(dead_code)]
    pub(crate) fn into_concrete<T>(self) -> Lookup<'a, T> {
        let TableRef { data, shape } = self;
        TableRef {
            shape: LookupMarker {
                subtable_offsets_byte_len: shape.subtable_offsets_byte_len,
                mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start,
                offset_type: std::marker::PhantomData,
            },
            data,
        }
    }
}

impl<'a, T> Lookup<'a, T> {
    #[allow(dead_code)]
    /// Replace the specific generic type on this implementation with `()`
    pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
        let TableRef { data, shape } = self;
        TableRef {
            shape: LookupMarker {
                subtable_offsets_byte_len: shape.subtable_offsets_byte_len,
                mark_filtering_set_byte_start: shape.mark_filtering_set_byte_start,
                offset_type: std::marker::PhantomData,
            },
            data: *data,
        }
    }
}

/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
pub type Lookup<'a, T> = TableRef<'a, LookupMarker<T>>;

#[allow(clippy::needless_lifetimes)]
impl<'a, T> Lookup<'a, T> {
    /// Different enumerations for GSUB and GPOS
    pub fn lookup_type(&self) -> u16 {
        let range = self.shape.lookup_type_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Lookup qualifiers
    pub fn lookup_flag(&self) -> LookupFlag {
        let range = self.shape.lookup_flag_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of subtables for this lookup
    pub fn sub_table_count(&self) -> u16 {
        let range = self.shape.sub_table_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to lookup subtables, from beginning of Lookup
    /// table
    pub fn subtable_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.subtable_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`subtable_offsets`][Self::subtable_offsets].
    pub fn subtables(&self) -> ArrayOfOffsets<'a, T, Offset16>
    where
        T: FontRead<'a>,
    {
        let data = self.data;
        let offsets = self.subtable_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }

    /// Index (base 0) into GDEF mark glyph sets structure. This field
    /// is only present if the USE_MARK_FILTERING_SET lookup flag is
    /// set.
    pub fn mark_filtering_set(&self) -> Option<u16> {
        let range = self.shape.mark_filtering_set_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for Lookup<'a, T> {
    fn type_name(&self) -> &str {
        "Lookup"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        let lookup_flag = self.lookup_flag();
        match idx {
            0usize => Some(Field::new("lookup_type", self.lookup_type())),
            1usize => Some(Field::new("lookup_flag", self.traverse_lookup_flag())),
            2usize => Some(Field::new("sub_table_count", self.sub_table_count())),
            3usize => Some({
                let data = self.data;
                Field::new(
                    "subtable_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<T>(),
                        self.subtable_offsets(),
                        move |off| {
                            let target = off.get().resolve::<T>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            4usize if lookup_flag.contains(LookupFlag::USE_MARK_FILTERING_SET) => Some(Field::new(
                "mark_filtering_set",
                self.mark_filtering_set().unwrap(),
            )),
            _ => None,
        }
    }
}

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

impl Format<u16> for CoverageFormat1Marker {
    const FORMAT: u16 = 1;
}

/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CoverageFormat1Marker {
    glyph_array_byte_len: usize,
}

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

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

    pub fn glyph_array_byte_range(&self) -> Range<usize> {
        let start = self.glyph_count_byte_range().end;
        start..start + self.glyph_array_byte_len
    }
}

impl MinByteRange for CoverageFormat1Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.glyph_array_byte_range().end
    }
}

impl<'a> FontRead<'a> for CoverageFormat1<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let glyph_count: u16 = cursor.read()?;
        let glyph_array_byte_len = (glyph_count as usize)
            .checked_mul(GlyphId16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(glyph_array_byte_len);
        cursor.finish(CoverageFormat1Marker {
            glyph_array_byte_len,
        })
    }
}

/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
pub type CoverageFormat1<'a> = TableRef<'a, CoverageFormat1Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> CoverageFormat1<'a> {
    /// Format identifier — format = 1
    pub fn coverage_format(&self) -> u16 {
        let range = self.shape.coverage_format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of glyphs in the glyph array
    pub fn glyph_count(&self) -> u16 {
        let range = self.shape.glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of glyph IDs — in numerical order
    pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
        let range = self.shape.glyph_array_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

impl Format<u16> for CoverageFormat2Marker {
    const FORMAT: u16 = 2;
}

/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CoverageFormat2Marker {
    range_records_byte_len: usize,
}

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

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

    pub fn range_records_byte_range(&self) -> Range<usize> {
        let start = self.range_count_byte_range().end;
        start..start + self.range_records_byte_len
    }
}

impl MinByteRange for CoverageFormat2Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.range_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for CoverageFormat2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let range_count: u16 = cursor.read()?;
        let range_records_byte_len = (range_count as usize)
            .checked_mul(RangeRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(range_records_byte_len);
        cursor.finish(CoverageFormat2Marker {
            range_records_byte_len,
        })
    }
}

/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
pub type CoverageFormat2<'a> = TableRef<'a, CoverageFormat2Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> CoverageFormat2<'a> {
    /// Format identifier — format = 2
    pub fn coverage_format(&self) -> u16 {
        let range = self.shape.coverage_format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of RangeRecords
    pub fn range_count(&self) -> u16 {
        let range = self.shape.range_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of glyph ranges — ordered by startGlyphID.
    pub fn range_records(&self) -> &'a [RangeRecord] {
        let range = self.shape.range_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Used in [CoverageFormat2]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct RangeRecord {
    /// First glyph ID in the range
    pub start_glyph_id: BigEndian<GlyphId16>,
    /// Last glyph ID in the range
    pub end_glyph_id: BigEndian<GlyphId16>,
    /// Coverage Index of first glyph ID in range
    pub start_coverage_index: BigEndian<u16>,
}

impl RangeRecord {
    /// First glyph ID in the range
    pub fn start_glyph_id(&self) -> GlyphId16 {
        self.start_glyph_id.get()
    }

    /// Last glyph ID in the range
    pub fn end_glyph_id(&self) -> GlyphId16 {
        self.end_glyph_id.get()
    }

    /// Coverage Index of first glyph ID in range
    pub fn start_coverage_index(&self) -> u16 {
        self.start_coverage_index.get()
    }
}

impl FixedSize for RangeRecord {
    const RAW_BYTE_LEN: usize =
        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}

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

/// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table)
#[derive(Clone)]
pub enum CoverageTable<'a> {
    Format1(CoverageFormat1<'a>),
    Format2(CoverageFormat2<'a>),
}

impl<'a> CoverageTable<'a> {
    ///Return the `FontData` used to resolve offsets for this table.
    pub fn offset_data(&self) -> FontData<'a> {
        match self {
            Self::Format1(item) => item.offset_data(),
            Self::Format2(item) => item.offset_data(),
        }
    }

    /// Format identifier — format = 1
    pub fn coverage_format(&self) -> u16 {
        match self {
            Self::Format1(item) => item.coverage_format(),
            Self::Format2(item) => item.coverage_format(),
        }
    }
}

impl<'a> FontRead<'a> for CoverageTable<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u16 = data.read_at(0usize)?;
        match format {
            CoverageFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
            CoverageFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl MinByteRange for CoverageTable<'_> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Format1(item) => item.min_byte_range(),
            Self::Format2(item) => item.min_byte_range(),
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> CoverageTable<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Format1(table) => table,
            Self::Format2(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for CoverageTable<'_> {
    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 CoverageTable<'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 ClassDefFormat1Marker {
    const FORMAT: u16 = 1;
}

/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassDefFormat1Marker {
    class_value_array_byte_len: usize,
}

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

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

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

    pub fn class_value_array_byte_range(&self) -> Range<usize> {
        let start = self.glyph_count_byte_range().end;
        start..start + self.class_value_array_byte_len
    }
}

impl MinByteRange for ClassDefFormat1Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.class_value_array_byte_range().end
    }
}

impl<'a> FontRead<'a> for ClassDefFormat1<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<GlyphId16>();
        let glyph_count: u16 = cursor.read()?;
        let class_value_array_byte_len = (glyph_count as usize)
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(class_value_array_byte_len);
        cursor.finish(ClassDefFormat1Marker {
            class_value_array_byte_len,
        })
    }
}

/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
pub type ClassDefFormat1<'a> = TableRef<'a, ClassDefFormat1Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ClassDefFormat1<'a> {
    /// Format identifier — format = 1
    pub fn class_format(&self) -> u16 {
        let range = self.shape.class_format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// First glyph ID of the classValueArray
    pub fn start_glyph_id(&self) -> GlyphId16 {
        let range = self.shape.start_glyph_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Size of the classValueArray
    pub fn glyph_count(&self) -> u16 {
        let range = self.shape.glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of Class Values — one per glyph ID
    pub fn class_value_array(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.class_value_array_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

impl Format<u16> for ClassDefFormat2Marker {
    const FORMAT: u16 = 2;
}

/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassDefFormat2Marker {
    class_range_records_byte_len: usize,
}

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

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

    pub fn class_range_records_byte_range(&self) -> Range<usize> {
        let start = self.class_range_count_byte_range().end;
        start..start + self.class_range_records_byte_len
    }
}

impl MinByteRange for ClassDefFormat2Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.class_range_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for ClassDefFormat2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let class_range_count: u16 = cursor.read()?;
        let class_range_records_byte_len = (class_range_count as usize)
            .checked_mul(ClassRangeRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(class_range_records_byte_len);
        cursor.finish(ClassDefFormat2Marker {
            class_range_records_byte_len,
        })
    }
}

/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
pub type ClassDefFormat2<'a> = TableRef<'a, ClassDefFormat2Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ClassDefFormat2<'a> {
    /// Format identifier — format = 2
    pub fn class_format(&self) -> u16 {
        let range = self.shape.class_format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of ClassRangeRecords
    pub fn class_range_count(&self) -> u16 {
        let range = self.shape.class_range_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of ClassRangeRecords — ordered by startGlyphID
    pub fn class_range_records(&self) -> &'a [ClassRangeRecord] {
        let range = self.shape.class_range_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Used in [ClassDefFormat2]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct ClassRangeRecord {
    /// First glyph ID in the range
    pub start_glyph_id: BigEndian<GlyphId16>,
    /// Last glyph ID in the range
    pub end_glyph_id: BigEndian<GlyphId16>,
    /// Applied to all glyphs in the range
    pub class: BigEndian<u16>,
}

impl ClassRangeRecord {
    /// First glyph ID in the range
    pub fn start_glyph_id(&self) -> GlyphId16 {
        self.start_glyph_id.get()
    }

    /// Last glyph ID in the range
    pub fn end_glyph_id(&self) -> GlyphId16 {
        self.end_glyph_id.get()
    }

    /// Applied to all glyphs in the range
    pub fn class(&self) -> u16 {
        self.class.get()
    }
}

impl FixedSize for ClassRangeRecord {
    const RAW_BYTE_LEN: usize =
        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}

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

/// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)
#[derive(Clone)]
pub enum ClassDef<'a> {
    Format1(ClassDefFormat1<'a>),
    Format2(ClassDefFormat2<'a>),
}

impl<'a> ClassDef<'a> {
    ///Return the `FontData` used to resolve offsets for this table.
    pub fn offset_data(&self) -> FontData<'a> {
        match self {
            Self::Format1(item) => item.offset_data(),
            Self::Format2(item) => item.offset_data(),
        }
    }

    /// Format identifier — format = 1
    pub fn class_format(&self) -> u16 {
        match self {
            Self::Format1(item) => item.class_format(),
            Self::Format2(item) => item.class_format(),
        }
    }
}

impl<'a> FontRead<'a> for ClassDef<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u16 = data.read_at(0usize)?;
        match format {
            ClassDefFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
            ClassDefFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl MinByteRange for ClassDef<'_> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Format1(item) => item.min_byte_range(),
            Self::Format2(item) => item.min_byte_range(),
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> ClassDef<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Format1(table) => table,
            Self::Format2(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for ClassDef<'_> {
    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 ClassDef<'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)
    }
}

/// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct SequenceLookupRecord {
    /// Index (zero-based) into the input glyph sequence
    pub sequence_index: BigEndian<u16>,
    /// Index (zero-based) into the LookupList
    pub lookup_list_index: BigEndian<u16>,
}

impl SequenceLookupRecord {
    /// Index (zero-based) into the input glyph sequence
    pub fn sequence_index(&self) -> u16 {
        self.sequence_index.get()
    }

    /// Index (zero-based) into the LookupList
    pub fn lookup_list_index(&self) -> u16 {
        self.lookup_list_index.get()
    }
}

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

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

impl Format<u16> for SequenceContextFormat1Marker {
    const FORMAT: u16 = 1;
}

/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceContextFormat1Marker {
    seq_rule_set_offsets_byte_len: usize,
}

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

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

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

    pub fn seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
        let start = self.seq_rule_set_count_byte_range().end;
        start..start + self.seq_rule_set_offsets_byte_len
    }
}

impl MinByteRange for SequenceContextFormat1Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_rule_set_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for SequenceContextFormat1<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<Offset16>();
        let seq_rule_set_count: u16 = cursor.read()?;
        let seq_rule_set_offsets_byte_len = (seq_rule_set_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_rule_set_offsets_byte_len);
        cursor.finish(SequenceContextFormat1Marker {
            seq_rule_set_offsets_byte_len,
        })
    }
}

/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
pub type SequenceContextFormat1<'a> = TableRef<'a, SequenceContextFormat1Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceContextFormat1<'a> {
    /// Format identifier: format = 1
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Offset to Coverage table, from beginning of
    /// SequenceContextFormat1 table
    pub fn coverage_offset(&self) -> Offset16 {
        let range = self.shape.coverage_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
        let data = self.data;
        self.coverage_offset().resolve(data)
    }

    /// Number of SequenceRuleSet tables
    pub fn seq_rule_set_count(&self) -> u16 {
        let range = self.shape.seq_rule_set_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to SequenceRuleSet tables, from beginning of
    /// SequenceContextFormat1 table (offsets may be NULL)
    pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
        let range = self.shape.seq_rule_set_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`seq_rule_set_offsets`][Self::seq_rule_set_offsets].
    pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet<'a>, Offset16> {
        let data = self.data;
        let offsets = self.seq_rule_set_offsets();
        ArrayOfNullableOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceContextFormat1<'a> {
    fn type_name(&self) -> &str {
        "SequenceContextFormat1"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new(
                "coverage_offset",
                FieldType::offset(self.coverage_offset(), self.coverage()),
            )),
            2usize => Some(Field::new("seq_rule_set_count", self.seq_rule_set_count())),
            3usize => Some({
                let data = self.data;
                Field::new(
                    "seq_rule_set_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<SequenceRuleSet>(),
                        self.seq_rule_set_offsets(),
                        move |off| {
                            let target = off.get().resolve::<SequenceRuleSet>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [SequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceRuleSetMarker {
    seq_rule_offsets_byte_len: usize,
}

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

    pub fn seq_rule_offsets_byte_range(&self) -> Range<usize> {
        let start = self.seq_rule_count_byte_range().end;
        start..start + self.seq_rule_offsets_byte_len
    }
}

impl MinByteRange for SequenceRuleSetMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_rule_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for SequenceRuleSet<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let seq_rule_count: u16 = cursor.read()?;
        let seq_rule_offsets_byte_len = (seq_rule_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_rule_offsets_byte_len);
        cursor.finish(SequenceRuleSetMarker {
            seq_rule_offsets_byte_len,
        })
    }
}

/// Part of [SequenceContextFormat1]
pub type SequenceRuleSet<'a> = TableRef<'a, SequenceRuleSetMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceRuleSet<'a> {
    /// Number of SequenceRule tables
    pub fn seq_rule_count(&self) -> u16 {
        let range = self.shape.seq_rule_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to SequenceRule tables, from beginning of the
    /// SequenceRuleSet table
    pub fn seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.seq_rule_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`seq_rule_offsets`][Self::seq_rule_offsets].
    pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule<'a>, Offset16> {
        let data = self.data;
        let offsets = self.seq_rule_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceRuleSet<'a> {
    fn type_name(&self) -> &str {
        "SequenceRuleSet"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("seq_rule_count", self.seq_rule_count())),
            1usize => Some({
                let data = self.data;
                Field::new(
                    "seq_rule_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<SequenceRule>(),
                        self.seq_rule_offsets(),
                        move |off| {
                            let target = off.get().resolve::<SequenceRule>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [SequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceRuleMarker {
    input_sequence_byte_len: usize,
    seq_lookup_records_byte_len: usize,
}

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

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

    pub fn input_sequence_byte_range(&self) -> Range<usize> {
        let start = self.seq_lookup_count_byte_range().end;
        start..start + self.input_sequence_byte_len
    }

    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
        let start = self.input_sequence_byte_range().end;
        start..start + self.seq_lookup_records_byte_len
    }
}

impl MinByteRange for SequenceRuleMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_lookup_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for SequenceRule<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let glyph_count: u16 = cursor.read()?;
        let seq_lookup_count: u16 = cursor.read()?;
        let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize))
            .checked_mul(GlyphId16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(input_sequence_byte_len);
        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_lookup_records_byte_len);
        cursor.finish(SequenceRuleMarker {
            input_sequence_byte_len,
            seq_lookup_records_byte_len,
        })
    }
}

/// Part of [SequenceContextFormat1]
pub type SequenceRule<'a> = TableRef<'a, SequenceRuleMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceRule<'a> {
    /// Number of glyphs in the input glyph sequence
    pub fn glyph_count(&self) -> u16 {
        let range = self.shape.glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of SequenceLookupRecords
    pub fn seq_lookup_count(&self) -> u16 {
        let range = self.shape.seq_lookup_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of input glyph IDs—starting with the second glyph
    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
        let range = self.shape.input_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Array of Sequence lookup records
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
        let range = self.shape.seq_lookup_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

impl Format<u16> for SequenceContextFormat2Marker {
    const FORMAT: u16 = 2;
}

/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceContextFormat2Marker {
    class_seq_rule_set_offsets_byte_len: usize,
}

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

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

    pub fn class_def_offset_byte_range(&self) -> Range<usize> {
        let start = self.coverage_offset_byte_range().end;
        start..start + Offset16::RAW_BYTE_LEN
    }

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

    pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
        let start = self.class_seq_rule_set_count_byte_range().end;
        start..start + self.class_seq_rule_set_offsets_byte_len
    }
}

impl MinByteRange for SequenceContextFormat2Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.class_seq_rule_set_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for SequenceContextFormat2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<Offset16>();
        cursor.advance::<Offset16>();
        let class_seq_rule_set_count: u16 = cursor.read()?;
        let class_seq_rule_set_offsets_byte_len = (class_seq_rule_set_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(class_seq_rule_set_offsets_byte_len);
        cursor.finish(SequenceContextFormat2Marker {
            class_seq_rule_set_offsets_byte_len,
        })
    }
}

/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
pub type SequenceContextFormat2<'a> = TableRef<'a, SequenceContextFormat2Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceContextFormat2<'a> {
    /// Format identifier: format = 2
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Offset to Coverage table, from beginning of
    /// SequenceContextFormat2 table
    pub fn coverage_offset(&self) -> Offset16 {
        let range = self.shape.coverage_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
        let data = self.data;
        self.coverage_offset().resolve(data)
    }

    /// Offset to ClassDef table, from beginning of
    /// SequenceContextFormat2 table
    pub fn class_def_offset(&self) -> Offset16 {
        let range = self.shape.class_def_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`class_def_offset`][Self::class_def_offset].
    pub fn class_def(&self) -> Result<ClassDef<'a>, ReadError> {
        let data = self.data;
        self.class_def_offset().resolve(data)
    }

    /// Number of ClassSequenceRuleSet tables
    pub fn class_seq_rule_set_count(&self) -> u16 {
        let range = self.shape.class_seq_rule_set_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to ClassSequenceRuleSet tables, from beginning
    /// of SequenceContextFormat2 table (may be NULL)
    pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
        let range = self.shape.class_seq_rule_set_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`class_seq_rule_set_offsets`][Self::class_seq_rule_set_offsets].
    pub fn class_seq_rule_sets(
        &self,
    ) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet<'a>, Offset16> {
        let data = self.data;
        let offsets = self.class_seq_rule_set_offsets();
        ArrayOfNullableOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceContextFormat2<'a> {
    fn type_name(&self) -> &str {
        "SequenceContextFormat2"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new(
                "coverage_offset",
                FieldType::offset(self.coverage_offset(), self.coverage()),
            )),
            2usize => Some(Field::new(
                "class_def_offset",
                FieldType::offset(self.class_def_offset(), self.class_def()),
            )),
            3usize => Some(Field::new(
                "class_seq_rule_set_count",
                self.class_seq_rule_set_count(),
            )),
            4usize => Some({
                let data = self.data;
                Field::new(
                    "class_seq_rule_set_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<ClassSequenceRuleSet>(),
                        self.class_seq_rule_set_offsets(),
                        move |off| {
                            let target = off.get().resolve::<ClassSequenceRuleSet>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [SequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassSequenceRuleSetMarker {
    class_seq_rule_offsets_byte_len: usize,
}

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

    pub fn class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
        let start = self.class_seq_rule_count_byte_range().end;
        start..start + self.class_seq_rule_offsets_byte_len
    }
}

impl MinByteRange for ClassSequenceRuleSetMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.class_seq_rule_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let class_seq_rule_count: u16 = cursor.read()?;
        let class_seq_rule_offsets_byte_len = (class_seq_rule_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(class_seq_rule_offsets_byte_len);
        cursor.finish(ClassSequenceRuleSetMarker {
            class_seq_rule_offsets_byte_len,
        })
    }
}

/// Part of [SequenceContextFormat2]
pub type ClassSequenceRuleSet<'a> = TableRef<'a, ClassSequenceRuleSetMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ClassSequenceRuleSet<'a> {
    /// Number of ClassSequenceRule tables
    pub fn class_seq_rule_count(&self) -> u16 {
        let range = self.shape.class_seq_rule_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to ClassSequenceRule tables, from beginning of
    /// ClassSequenceRuleSet table
    pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.class_seq_rule_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`class_seq_rule_offsets`][Self::class_seq_rule_offsets].
    pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset16> {
        let data = self.data;
        let offsets = self.class_seq_rule_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ClassSequenceRuleSet<'a> {
    fn type_name(&self) -> &str {
        "ClassSequenceRuleSet"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "class_seq_rule_count",
                self.class_seq_rule_count(),
            )),
            1usize => Some({
                let data = self.data;
                Field::new(
                    "class_seq_rule_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<ClassSequenceRule>(),
                        self.class_seq_rule_offsets(),
                        move |off| {
                            let target = off.get().resolve::<ClassSequenceRule>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [SequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ClassSequenceRuleMarker {
    input_sequence_byte_len: usize,
    seq_lookup_records_byte_len: usize,
}

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

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

    pub fn input_sequence_byte_range(&self) -> Range<usize> {
        let start = self.seq_lookup_count_byte_range().end;
        start..start + self.input_sequence_byte_len
    }

    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
        let start = self.input_sequence_byte_range().end;
        start..start + self.seq_lookup_records_byte_len
    }
}

impl MinByteRange for ClassSequenceRuleMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_lookup_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for ClassSequenceRule<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let glyph_count: u16 = cursor.read()?;
        let seq_lookup_count: u16 = cursor.read()?;
        let input_sequence_byte_len = (transforms::subtract(glyph_count, 1_usize))
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(input_sequence_byte_len);
        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_lookup_records_byte_len);
        cursor.finish(ClassSequenceRuleMarker {
            input_sequence_byte_len,
            seq_lookup_records_byte_len,
        })
    }
}

/// Part of [SequenceContextFormat2]
pub type ClassSequenceRule<'a> = TableRef<'a, ClassSequenceRuleMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ClassSequenceRule<'a> {
    /// Number of glyphs to be matched
    pub fn glyph_count(&self) -> u16 {
        let range = self.shape.glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of SequenceLookupRecords
    pub fn seq_lookup_count(&self) -> u16 {
        let range = self.shape.seq_lookup_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Sequence of classes to be matched to the input glyph sequence,
    /// beginning with the second glyph position
    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.input_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Array of SequenceLookupRecords
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
        let range = self.shape.seq_lookup_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

impl Format<u16> for SequenceContextFormat3Marker {
    const FORMAT: u16 = 3;
}

/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SequenceContextFormat3Marker {
    coverage_offsets_byte_len: usize,
    seq_lookup_records_byte_len: usize,
}

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

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

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

    pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
        let start = self.seq_lookup_count_byte_range().end;
        start..start + self.coverage_offsets_byte_len
    }

    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
        let start = self.coverage_offsets_byte_range().end;
        start..start + self.seq_lookup_records_byte_len
    }
}

impl MinByteRange for SequenceContextFormat3Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_lookup_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for SequenceContextFormat3<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let glyph_count: u16 = cursor.read()?;
        let seq_lookup_count: u16 = cursor.read()?;
        let coverage_offsets_byte_len = (glyph_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(coverage_offsets_byte_len);
        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_lookup_records_byte_len);
        cursor.finish(SequenceContextFormat3Marker {
            coverage_offsets_byte_len,
            seq_lookup_records_byte_len,
        })
    }
}

/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
pub type SequenceContextFormat3<'a> = TableRef<'a, SequenceContextFormat3Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> SequenceContextFormat3<'a> {
    /// Format identifier: format = 3
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of glyphs in the input sequence
    pub fn glyph_count(&self) -> u16 {
        let range = self.shape.glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of SequenceLookupRecords
    pub fn seq_lookup_count(&self) -> u16 {
        let range = self.shape.seq_lookup_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to Coverage tables, from beginning of
    /// SequenceContextFormat3 subtable
    pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.coverage_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
    pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
        let data = self.data;
        let offsets = self.coverage_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }

    /// Array of SequenceLookupRecords
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
        let range = self.shape.seq_lookup_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SequenceContextFormat3<'a> {
    fn type_name(&self) -> &str {
        "SequenceContextFormat3"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("glyph_count", self.glyph_count())),
            2usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
            3usize => Some({
                let data = self.data;
                Field::new(
                    "coverage_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<CoverageTable>(),
                        self.coverage_offsets(),
                        move |off| {
                            let target = off.get().resolve::<CoverageTable>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            4usize => Some(Field::new(
                "seq_lookup_records",
                traversal::FieldType::array_of_records(
                    stringify!(SequenceLookupRecord),
                    self.seq_lookup_records(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

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

#[derive(Clone)]
pub enum SequenceContext<'a> {
    Format1(SequenceContextFormat1<'a>),
    Format2(SequenceContextFormat2<'a>),
    Format3(SequenceContextFormat3<'a>),
}

impl<'a> SequenceContext<'a> {
    ///Return the `FontData` used to resolve offsets for this table.
    pub fn offset_data(&self) -> FontData<'a> {
        match self {
            Self::Format1(item) => item.offset_data(),
            Self::Format2(item) => item.offset_data(),
            Self::Format3(item) => item.offset_data(),
        }
    }

    /// Format identifier: format = 1
    pub fn format(&self) -> u16 {
        match self {
            Self::Format1(item) => item.format(),
            Self::Format2(item) => item.format(),
            Self::Format3(item) => item.format(),
        }
    }
}

impl<'a> FontRead<'a> for SequenceContext<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u16 = data.read_at(0usize)?;
        match format {
            SequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
            SequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
            SequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl MinByteRange for SequenceContext<'_> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Format1(item) => item.min_byte_range(),
            Self::Format2(item) => item.min_byte_range(),
            Self::Format3(item) => item.min_byte_range(),
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SequenceContext<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Format1(table) => table,
            Self::Format2(table) => table,
            Self::Format3(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for SequenceContext<'_> {
    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 SequenceContext<'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 ChainedSequenceContextFormat1Marker {
    const FORMAT: u16 = 1;
}

/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceContextFormat1Marker {
    chained_seq_rule_set_offsets_byte_len: usize,
}

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

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

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

    pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
        let start = self.chained_seq_rule_set_count_byte_range().end;
        start..start + self.chained_seq_rule_set_offsets_byte_len
    }
}

impl MinByteRange for ChainedSequenceContextFormat1Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.chained_seq_rule_set_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<Offset16>();
        let chained_seq_rule_set_count: u16 = cursor.read()?;
        let chained_seq_rule_set_offsets_byte_len = (chained_seq_rule_set_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(chained_seq_rule_set_offsets_byte_len);
        cursor.finish(ChainedSequenceContextFormat1Marker {
            chained_seq_rule_set_offsets_byte_len,
        })
    }
}

/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
pub type ChainedSequenceContextFormat1<'a> = TableRef<'a, ChainedSequenceContextFormat1Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceContextFormat1<'a> {
    /// Format identifier: format = 1
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Offset to Coverage table, from beginning of
    /// ChainSequenceContextFormat1 table
    pub fn coverage_offset(&self) -> Offset16 {
        let range = self.shape.coverage_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
        let data = self.data;
        self.coverage_offset().resolve(data)
    }

    /// Number of ChainedSequenceRuleSet tables
    pub fn chained_seq_rule_set_count(&self) -> u16 {
        let range = self.shape.chained_seq_rule_set_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to ChainedSeqRuleSet tables, from beginning of
    /// ChainedSequenceContextFormat1 table (may be NULL)
    pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
        let range = self.shape.chained_seq_rule_set_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`chained_seq_rule_set_offsets`][Self::chained_seq_rule_set_offsets].
    pub fn chained_seq_rule_sets(
        &self,
    ) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet<'a>, Offset16> {
        let data = self.data;
        let offsets = self.chained_seq_rule_set_offsets();
        ArrayOfNullableOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceContextFormat1<'a> {
    fn type_name(&self) -> &str {
        "ChainedSequenceContextFormat1"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new(
                "coverage_offset",
                FieldType::offset(self.coverage_offset(), self.coverage()),
            )),
            2usize => Some(Field::new(
                "chained_seq_rule_set_count",
                self.chained_seq_rule_set_count(),
            )),
            3usize => Some({
                let data = self.data;
                Field::new(
                    "chained_seq_rule_set_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<ChainedSequenceRuleSet>(),
                        self.chained_seq_rule_set_offsets(),
                        move |off| {
                            let target = off.get().resolve::<ChainedSequenceRuleSet>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [ChainedSequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceRuleSetMarker {
    chained_seq_rule_offsets_byte_len: usize,
}

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

    pub fn chained_seq_rule_offsets_byte_range(&self) -> Range<usize> {
        let start = self.chained_seq_rule_count_byte_range().end;
        start..start + self.chained_seq_rule_offsets_byte_len
    }
}

impl MinByteRange for ChainedSequenceRuleSetMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.chained_seq_rule_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let chained_seq_rule_count: u16 = cursor.read()?;
        let chained_seq_rule_offsets_byte_len = (chained_seq_rule_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(chained_seq_rule_offsets_byte_len);
        cursor.finish(ChainedSequenceRuleSetMarker {
            chained_seq_rule_offsets_byte_len,
        })
    }
}

/// Part of [ChainedSequenceContextFormat1]
pub type ChainedSequenceRuleSet<'a> = TableRef<'a, ChainedSequenceRuleSetMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceRuleSet<'a> {
    /// Number of ChainedSequenceRule tables
    pub fn chained_seq_rule_count(&self) -> u16 {
        let range = self.shape.chained_seq_rule_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to ChainedSequenceRule tables, from beginning
    /// of ChainedSequenceRuleSet table
    pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.chained_seq_rule_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`chained_seq_rule_offsets`][Self::chained_seq_rule_offsets].
    pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule<'a>, Offset16> {
        let data = self.data;
        let offsets = self.chained_seq_rule_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceRuleSet<'a> {
    fn type_name(&self) -> &str {
        "ChainedSequenceRuleSet"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "chained_seq_rule_count",
                self.chained_seq_rule_count(),
            )),
            1usize => Some({
                let data = self.data;
                Field::new(
                    "chained_seq_rule_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<ChainedSequenceRule>(),
                        self.chained_seq_rule_offsets(),
                        move |off| {
                            let target = off.get().resolve::<ChainedSequenceRule>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [ChainedSequenceContextFormat1]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceRuleMarker {
    backtrack_sequence_byte_len: usize,
    input_sequence_byte_len: usize,
    lookahead_sequence_byte_len: usize,
    seq_lookup_records_byte_len: usize,
}

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

    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
        let start = self.backtrack_glyph_count_byte_range().end;
        start..start + self.backtrack_sequence_byte_len
    }

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

    pub fn input_sequence_byte_range(&self) -> Range<usize> {
        let start = self.input_glyph_count_byte_range().end;
        start..start + self.input_sequence_byte_len
    }

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

    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
        let start = self.lookahead_glyph_count_byte_range().end;
        start..start + self.lookahead_sequence_byte_len
    }

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

    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
        let start = self.seq_lookup_count_byte_range().end;
        start..start + self.seq_lookup_records_byte_len
    }
}

impl MinByteRange for ChainedSequenceRuleMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_lookup_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for ChainedSequenceRule<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let backtrack_glyph_count: u16 = cursor.read()?;
        let backtrack_sequence_byte_len = (backtrack_glyph_count as usize)
            .checked_mul(GlyphId16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(backtrack_sequence_byte_len);
        let input_glyph_count: u16 = cursor.read()?;
        let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize))
            .checked_mul(GlyphId16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(input_sequence_byte_len);
        let lookahead_glyph_count: u16 = cursor.read()?;
        let lookahead_sequence_byte_len = (lookahead_glyph_count as usize)
            .checked_mul(GlyphId16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(lookahead_sequence_byte_len);
        let seq_lookup_count: u16 = cursor.read()?;
        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_lookup_records_byte_len);
        cursor.finish(ChainedSequenceRuleMarker {
            backtrack_sequence_byte_len,
            input_sequence_byte_len,
            lookahead_sequence_byte_len,
            seq_lookup_records_byte_len,
        })
    }
}

/// Part of [ChainedSequenceContextFormat1]
pub type ChainedSequenceRule<'a> = TableRef<'a, ChainedSequenceRuleMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceRule<'a> {
    /// Number of glyphs in the backtrack sequence
    pub fn backtrack_glyph_count(&self) -> u16 {
        let range = self.shape.backtrack_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of backtrack glyph IDs
    pub fn backtrack_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
        let range = self.shape.backtrack_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Number of glyphs in the input sequence
    pub fn input_glyph_count(&self) -> u16 {
        let range = self.shape.input_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of input glyph IDs—start with second glyph
    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
        let range = self.shape.input_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Number of glyphs in the lookahead sequence
    pub fn lookahead_glyph_count(&self) -> u16 {
        let range = self.shape.lookahead_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of lookahead glyph IDs
    pub fn lookahead_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
        let range = self.shape.lookahead_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Number of SequenceLookupRecords
    pub fn seq_lookup_count(&self) -> u16 {
        let range = self.shape.seq_lookup_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of SequenceLookupRecords
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
        let range = self.shape.seq_lookup_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceRule<'a> {
    fn type_name(&self) -> &str {
        "ChainedSequenceRule"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "backtrack_glyph_count",
                self.backtrack_glyph_count(),
            )),
            1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
            2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
            3usize => Some(Field::new("input_sequence", self.input_sequence())),
            4usize => Some(Field::new(
                "lookahead_glyph_count",
                self.lookahead_glyph_count(),
            )),
            5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
            6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
            7usize => Some(Field::new(
                "seq_lookup_records",
                traversal::FieldType::array_of_records(
                    stringify!(SequenceLookupRecord),
                    self.seq_lookup_records(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

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

impl Format<u16> for ChainedSequenceContextFormat2Marker {
    const FORMAT: u16 = 2;
}

/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceContextFormat2Marker {
    chained_class_seq_rule_set_offsets_byte_len: usize,
}

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

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

    pub fn backtrack_class_def_offset_byte_range(&self) -> Range<usize> {
        let start = self.coverage_offset_byte_range().end;
        start..start + Offset16::RAW_BYTE_LEN
    }

    pub fn input_class_def_offset_byte_range(&self) -> Range<usize> {
        let start = self.backtrack_class_def_offset_byte_range().end;
        start..start + Offset16::RAW_BYTE_LEN
    }

    pub fn lookahead_class_def_offset_byte_range(&self) -> Range<usize> {
        let start = self.input_class_def_offset_byte_range().end;
        start..start + Offset16::RAW_BYTE_LEN
    }

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

    pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
        let start = self.chained_class_seq_rule_set_count_byte_range().end;
        start..start + self.chained_class_seq_rule_set_offsets_byte_len
    }
}

impl MinByteRange for ChainedSequenceContextFormat2Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.chained_class_seq_rule_set_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<Offset16>();
        cursor.advance::<Offset16>();
        cursor.advance::<Offset16>();
        cursor.advance::<Offset16>();
        let chained_class_seq_rule_set_count: u16 = cursor.read()?;
        let chained_class_seq_rule_set_offsets_byte_len = (chained_class_seq_rule_set_count
            as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(chained_class_seq_rule_set_offsets_byte_len);
        cursor.finish(ChainedSequenceContextFormat2Marker {
            chained_class_seq_rule_set_offsets_byte_len,
        })
    }
}

/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
pub type ChainedSequenceContextFormat2<'a> = TableRef<'a, ChainedSequenceContextFormat2Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceContextFormat2<'a> {
    /// Format identifier: format = 2
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Offset to Coverage table, from beginning of
    /// ChainedSequenceContextFormat2 table
    pub fn coverage_offset(&self) -> Offset16 {
        let range = self.shape.coverage_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
        let data = self.data;
        self.coverage_offset().resolve(data)
    }

    /// Offset to ClassDef table containing backtrack sequence context,
    /// from beginning of ChainedSequenceContextFormat2 table
    pub fn backtrack_class_def_offset(&self) -> Offset16 {
        let range = self.shape.backtrack_class_def_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`backtrack_class_def_offset`][Self::backtrack_class_def_offset].
    pub fn backtrack_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
        let data = self.data;
        self.backtrack_class_def_offset().resolve(data)
    }

    /// Offset to ClassDef table containing input sequence context,
    /// from beginning of ChainedSequenceContextFormat2 table
    pub fn input_class_def_offset(&self) -> Offset16 {
        let range = self.shape.input_class_def_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`input_class_def_offset`][Self::input_class_def_offset].
    pub fn input_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
        let data = self.data;
        self.input_class_def_offset().resolve(data)
    }

    /// Offset to ClassDef table containing lookahead sequence context,
    /// from beginning of ChainedSequenceContextFormat2 table
    pub fn lookahead_class_def_offset(&self) -> Offset16 {
        let range = self.shape.lookahead_class_def_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`lookahead_class_def_offset`][Self::lookahead_class_def_offset].
    pub fn lookahead_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
        let data = self.data;
        self.lookahead_class_def_offset().resolve(data)
    }

    /// Number of ChainedClassSequenceRuleSet tables
    pub fn chained_class_seq_rule_set_count(&self) -> u16 {
        let range = self.shape.chained_class_seq_rule_set_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to ChainedClassSequenceRuleSet tables, from
    /// beginning of ChainedSequenceContextFormat2 table (may be NULL)
    pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
        let range = self.shape.chained_class_seq_rule_set_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`chained_class_seq_rule_set_offsets`][Self::chained_class_seq_rule_set_offsets].
    pub fn chained_class_seq_rule_sets(
        &self,
    ) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet<'a>, Offset16> {
        let data = self.data;
        let offsets = self.chained_class_seq_rule_set_offsets();
        ArrayOfNullableOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceContextFormat2<'a> {
    fn type_name(&self) -> &str {
        "ChainedSequenceContextFormat2"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new(
                "coverage_offset",
                FieldType::offset(self.coverage_offset(), self.coverage()),
            )),
            2usize => Some(Field::new(
                "backtrack_class_def_offset",
                FieldType::offset(
                    self.backtrack_class_def_offset(),
                    self.backtrack_class_def(),
                ),
            )),
            3usize => Some(Field::new(
                "input_class_def_offset",
                FieldType::offset(self.input_class_def_offset(), self.input_class_def()),
            )),
            4usize => Some(Field::new(
                "lookahead_class_def_offset",
                FieldType::offset(
                    self.lookahead_class_def_offset(),
                    self.lookahead_class_def(),
                ),
            )),
            5usize => Some(Field::new(
                "chained_class_seq_rule_set_count",
                self.chained_class_seq_rule_set_count(),
            )),
            6usize => Some({
                let data = self.data;
                Field::new(
                    "chained_class_seq_rule_set_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<ChainedClassSequenceRuleSet>(),
                        self.chained_class_seq_rule_set_offsets(),
                        move |off| {
                            let target = off.get().resolve::<ChainedClassSequenceRuleSet>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [ChainedSequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedClassSequenceRuleSetMarker {
    chained_class_seq_rule_offsets_byte_len: usize,
}

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

    pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
        let start = self.chained_class_seq_rule_count_byte_range().end;
        start..start + self.chained_class_seq_rule_offsets_byte_len
    }
}

impl MinByteRange for ChainedClassSequenceRuleSetMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.chained_class_seq_rule_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let chained_class_seq_rule_count: u16 = cursor.read()?;
        let chained_class_seq_rule_offsets_byte_len = (chained_class_seq_rule_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(chained_class_seq_rule_offsets_byte_len);
        cursor.finish(ChainedClassSequenceRuleSetMarker {
            chained_class_seq_rule_offsets_byte_len,
        })
    }
}

/// Part of [ChainedSequenceContextFormat2]
pub type ChainedClassSequenceRuleSet<'a> = TableRef<'a, ChainedClassSequenceRuleSetMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedClassSequenceRuleSet<'a> {
    /// Number of ChainedClassSequenceRule tables
    pub fn chained_class_seq_rule_count(&self) -> u16 {
        let range = self.shape.chained_class_seq_rule_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to ChainedClassSequenceRule tables, from
    /// beginning of ChainedClassSequenceRuleSet
    pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.chained_class_seq_rule_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`chained_class_seq_rule_offsets`][Self::chained_class_seq_rule_offsets].
    pub fn chained_class_seq_rules(
        &self,
    ) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset16> {
        let data = self.data;
        let offsets = self.chained_class_seq_rule_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedClassSequenceRuleSet<'a> {
    fn type_name(&self) -> &str {
        "ChainedClassSequenceRuleSet"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "chained_class_seq_rule_count",
                self.chained_class_seq_rule_count(),
            )),
            1usize => Some({
                let data = self.data;
                Field::new(
                    "chained_class_seq_rule_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<ChainedClassSequenceRule>(),
                        self.chained_class_seq_rule_offsets(),
                        move |off| {
                            let target = off.get().resolve::<ChainedClassSequenceRule>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// Part of [ChainedSequenceContextFormat2]
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedClassSequenceRuleMarker {
    backtrack_sequence_byte_len: usize,
    input_sequence_byte_len: usize,
    lookahead_sequence_byte_len: usize,
    seq_lookup_records_byte_len: usize,
}

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

    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
        let start = self.backtrack_glyph_count_byte_range().end;
        start..start + self.backtrack_sequence_byte_len
    }

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

    pub fn input_sequence_byte_range(&self) -> Range<usize> {
        let start = self.input_glyph_count_byte_range().end;
        start..start + self.input_sequence_byte_len
    }

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

    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
        let start = self.lookahead_glyph_count_byte_range().end;
        start..start + self.lookahead_sequence_byte_len
    }

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

    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
        let start = self.seq_lookup_count_byte_range().end;
        start..start + self.seq_lookup_records_byte_len
    }
}

impl MinByteRange for ChainedClassSequenceRuleMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_lookup_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let backtrack_glyph_count: u16 = cursor.read()?;
        let backtrack_sequence_byte_len = (backtrack_glyph_count as usize)
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(backtrack_sequence_byte_len);
        let input_glyph_count: u16 = cursor.read()?;
        let input_sequence_byte_len = (transforms::subtract(input_glyph_count, 1_usize))
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(input_sequence_byte_len);
        let lookahead_glyph_count: u16 = cursor.read()?;
        let lookahead_sequence_byte_len = (lookahead_glyph_count as usize)
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(lookahead_sequence_byte_len);
        let seq_lookup_count: u16 = cursor.read()?;
        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_lookup_records_byte_len);
        cursor.finish(ChainedClassSequenceRuleMarker {
            backtrack_sequence_byte_len,
            input_sequence_byte_len,
            lookahead_sequence_byte_len,
            seq_lookup_records_byte_len,
        })
    }
}

/// Part of [ChainedSequenceContextFormat2]
pub type ChainedClassSequenceRule<'a> = TableRef<'a, ChainedClassSequenceRuleMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedClassSequenceRule<'a> {
    /// Number of glyphs in the backtrack sequence
    pub fn backtrack_glyph_count(&self) -> u16 {
        let range = self.shape.backtrack_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of backtrack-sequence classes
    pub fn backtrack_sequence(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.backtrack_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Total number of glyphs in the input sequence
    pub fn input_glyph_count(&self) -> u16 {
        let range = self.shape.input_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of input sequence classes, beginning with the second
    /// glyph position
    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.input_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Number of glyphs in the lookahead sequence
    pub fn lookahead_glyph_count(&self) -> u16 {
        let range = self.shape.lookahead_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of lookahead-sequence classes
    pub fn lookahead_sequence(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.lookahead_sequence_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Number of SequenceLookupRecords
    pub fn seq_lookup_count(&self) -> u16 {
        let range = self.shape.seq_lookup_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of SequenceLookupRecords
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
        let range = self.shape.seq_lookup_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedClassSequenceRule<'a> {
    fn type_name(&self) -> &str {
        "ChainedClassSequenceRule"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new(
                "backtrack_glyph_count",
                self.backtrack_glyph_count(),
            )),
            1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
            2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
            3usize => Some(Field::new("input_sequence", self.input_sequence())),
            4usize => Some(Field::new(
                "lookahead_glyph_count",
                self.lookahead_glyph_count(),
            )),
            5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
            6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
            7usize => Some(Field::new(
                "seq_lookup_records",
                traversal::FieldType::array_of_records(
                    stringify!(SequenceLookupRecord),
                    self.seq_lookup_records(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

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

impl Format<u16> for ChainedSequenceContextFormat3Marker {
    const FORMAT: u16 = 3;
}

/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ChainedSequenceContextFormat3Marker {
    backtrack_coverage_offsets_byte_len: usize,
    input_coverage_offsets_byte_len: usize,
    lookahead_coverage_offsets_byte_len: usize,
    seq_lookup_records_byte_len: usize,
}

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

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

    pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
        let start = self.backtrack_glyph_count_byte_range().end;
        start..start + self.backtrack_coverage_offsets_byte_len
    }

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

    pub fn input_coverage_offsets_byte_range(&self) -> Range<usize> {
        let start = self.input_glyph_count_byte_range().end;
        start..start + self.input_coverage_offsets_byte_len
    }

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

    pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
        let start = self.lookahead_glyph_count_byte_range().end;
        start..start + self.lookahead_coverage_offsets_byte_len
    }

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

    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
        let start = self.seq_lookup_count_byte_range().end;
        start..start + self.seq_lookup_records_byte_len
    }
}

impl MinByteRange for ChainedSequenceContextFormat3Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.seq_lookup_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let backtrack_glyph_count: u16 = cursor.read()?;
        let backtrack_coverage_offsets_byte_len = (backtrack_glyph_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(backtrack_coverage_offsets_byte_len);
        let input_glyph_count: u16 = cursor.read()?;
        let input_coverage_offsets_byte_len = (input_glyph_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(input_coverage_offsets_byte_len);
        let lookahead_glyph_count: u16 = cursor.read()?;
        let lookahead_coverage_offsets_byte_len = (lookahead_glyph_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(lookahead_coverage_offsets_byte_len);
        let seq_lookup_count: u16 = cursor.read()?;
        let seq_lookup_records_byte_len = (seq_lookup_count as usize)
            .checked_mul(SequenceLookupRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(seq_lookup_records_byte_len);
        cursor.finish(ChainedSequenceContextFormat3Marker {
            backtrack_coverage_offsets_byte_len,
            input_coverage_offsets_byte_len,
            lookahead_coverage_offsets_byte_len,
            seq_lookup_records_byte_len,
        })
    }
}

/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
pub type ChainedSequenceContextFormat3<'a> = TableRef<'a, ChainedSequenceContextFormat3Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ChainedSequenceContextFormat3<'a> {
    /// Format identifier: format = 3
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of glyphs in the backtrack sequence
    pub fn backtrack_glyph_count(&self) -> u16 {
        let range = self.shape.backtrack_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to coverage tables for the backtrack sequence
    pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.backtrack_coverage_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`backtrack_coverage_offsets`][Self::backtrack_coverage_offsets].
    pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
        let data = self.data;
        let offsets = self.backtrack_coverage_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }

    /// Number of glyphs in the input sequence
    pub fn input_glyph_count(&self) -> u16 {
        let range = self.shape.input_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to coverage tables for the input sequence
    pub fn input_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.input_coverage_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`input_coverage_offsets`][Self::input_coverage_offsets].
    pub fn input_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
        let data = self.data;
        let offsets = self.input_coverage_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }

    /// Number of glyphs in the lookahead sequence
    pub fn lookahead_glyph_count(&self) -> u16 {
        let range = self.shape.lookahead_glyph_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to coverage tables for the lookahead sequence
    pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.lookahead_coverage_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`lookahead_coverage_offsets`][Self::lookahead_coverage_offsets].
    pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
        let data = self.data;
        let offsets = self.lookahead_coverage_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }

    /// Number of SequenceLookupRecords
    pub fn seq_lookup_count(&self) -> u16 {
        let range = self.shape.seq_lookup_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of SequenceLookupRecords
    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
        let range = self.shape.seq_lookup_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ChainedSequenceContextFormat3<'a> {
    fn type_name(&self) -> &str {
        "ChainedSequenceContextFormat3"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new(
                "backtrack_glyph_count",
                self.backtrack_glyph_count(),
            )),
            2usize => Some({
                let data = self.data;
                Field::new(
                    "backtrack_coverage_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<CoverageTable>(),
                        self.backtrack_coverage_offsets(),
                        move |off| {
                            let target = off.get().resolve::<CoverageTable>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            3usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
            4usize => Some({
                let data = self.data;
                Field::new(
                    "input_coverage_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<CoverageTable>(),
                        self.input_coverage_offsets(),
                        move |off| {
                            let target = off.get().resolve::<CoverageTable>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            5usize => Some(Field::new(
                "lookahead_glyph_count",
                self.lookahead_glyph_count(),
            )),
            6usize => Some({
                let data = self.data;
                Field::new(
                    "lookahead_coverage_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<CoverageTable>(),
                        self.lookahead_coverage_offsets(),
                        move |off| {
                            let target = off.get().resolve::<CoverageTable>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            7usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
            8usize => Some(Field::new(
                "seq_lookup_records",
                traversal::FieldType::array_of_records(
                    stringify!(SequenceLookupRecord),
                    self.seq_lookup_records(),
                    self.offset_data(),
                ),
            )),
            _ => None,
        }
    }
}

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

#[derive(Clone)]
pub enum ChainedSequenceContext<'a> {
    Format1(ChainedSequenceContextFormat1<'a>),
    Format2(ChainedSequenceContextFormat2<'a>),
    Format3(ChainedSequenceContextFormat3<'a>),
}

impl<'a> ChainedSequenceContext<'a> {
    ///Return the `FontData` used to resolve offsets for this table.
    pub fn offset_data(&self) -> FontData<'a> {
        match self {
            Self::Format1(item) => item.offset_data(),
            Self::Format2(item) => item.offset_data(),
            Self::Format3(item) => item.offset_data(),
        }
    }

    /// Format identifier: format = 1
    pub fn format(&self) -> u16 {
        match self {
            Self::Format1(item) => item.format(),
            Self::Format2(item) => item.format(),
            Self::Format3(item) => item.format(),
        }
    }
}

impl<'a> FontRead<'a> for ChainedSequenceContext<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u16 = data.read_at(0usize)?;
        match format {
            ChainedSequenceContextFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
            ChainedSequenceContextFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
            ChainedSequenceContextFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl MinByteRange for ChainedSequenceContext<'_> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Format1(item) => item.min_byte_range(),
            Self::Format2(item) => item.min_byte_range(),
            Self::Format3(item) => item.min_byte_range(),
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> ChainedSequenceContext<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Format1(table) => table,
            Self::Format2(table) => table,
            Self::Format3(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for ChainedSequenceContext<'_> {
    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 ChainedSequenceContext<'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)
    }
}

/// [Device](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
/// delta formats
#[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 DeltaFormat {
    /// Signed 2-bit value, 8 values per uint16
    #[default]
    Local2BitDeltas = 0x0001,
    /// Signed 4-bit value, 4 values per uint16
    Local4BitDeltas = 0x0002,
    /// Signed 8-bit value, 2 values per uint16
    Local8BitDeltas = 0x0003,
    /// VariationIndex table, contains a delta-set index pair.
    VariationIndex = 0x8000,
    #[doc(hidden)]
    /// If font data is malformed we will map unknown values to this variant
    Unknown,
}

impl DeltaFormat {
    /// 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 {
            0x0001 => Self::Local2BitDeltas,
            0x0002 => Self::Local4BitDeltas,
            0x0003 => Self::Local8BitDeltas,
            0x8000 => Self::VariationIndex,
            _ => Self::Unknown,
        }
    }
}

impl font_types::Scalar for DeltaFormat {
    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<DeltaFormat> for FieldType<'a> {
    fn from(src: DeltaFormat) -> FieldType<'a> {
        (src as u16).into()
    }
}

/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct DeviceMarker {
    delta_value_byte_len: usize,
}

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

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

    pub fn delta_format_byte_range(&self) -> Range<usize> {
        let start = self.end_size_byte_range().end;
        start..start + DeltaFormat::RAW_BYTE_LEN
    }

    pub fn delta_value_byte_range(&self) -> Range<usize> {
        let start = self.delta_format_byte_range().end;
        start..start + self.delta_value_byte_len
    }
}

impl MinByteRange for DeviceMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.delta_value_byte_range().end
    }
}

impl<'a> FontRead<'a> for Device<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let start_size: u16 = cursor.read()?;
        let end_size: u16 = cursor.read()?;
        let delta_format: DeltaFormat = cursor.read()?;
        let delta_value_byte_len = (DeltaFormat::value_count(delta_format, start_size, end_size))
            .checked_mul(u16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(delta_value_byte_len);
        cursor.finish(DeviceMarker {
            delta_value_byte_len,
        })
    }
}

/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
pub type Device<'a> = TableRef<'a, DeviceMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> Device<'a> {
    /// Smallest size to correct, in ppem
    pub fn start_size(&self) -> u16 {
        let range = self.shape.start_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Largest size to correct, in ppem
    pub fn end_size(&self) -> u16 {
        let range = self.shape.end_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003
    pub fn delta_format(&self) -> DeltaFormat {
        let range = self.shape.delta_format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of compressed data
    pub fn delta_value(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.delta_value_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Variation index table
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct VariationIndexMarker {}

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

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

    pub fn delta_format_byte_range(&self) -> Range<usize> {
        let start = self.delta_set_inner_index_byte_range().end;
        start..start + DeltaFormat::RAW_BYTE_LEN
    }
}

impl MinByteRange for VariationIndexMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.delta_format_byte_range().end
    }
}

impl<'a> FontRead<'a> for VariationIndex<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<DeltaFormat>();
        cursor.finish(VariationIndexMarker {})
    }
}

/// Variation index table
pub type VariationIndex<'a> = TableRef<'a, VariationIndexMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> VariationIndex<'a> {
    /// A delta-set outer index — used to select an item variation
    /// data subtable within the item variation store.
    pub fn delta_set_outer_index(&self) -> u16 {
        let range = self.shape.delta_set_outer_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// A delta-set inner index — used to select a delta-set row
    /// within an item variation data subtable.
    pub fn delta_set_inner_index(&self) -> u16 {
        let range = self.shape.delta_set_inner_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Format, = 0x8000
    pub fn delta_format(&self) -> DeltaFormat {
        let range = self.shape.delta_format_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

/// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font)
#[derive(Clone)]
pub enum DeviceOrVariationIndex<'a> {
    Device(Device<'a>),
    VariationIndex(VariationIndex<'a>),
}

impl<'a> DeviceOrVariationIndex<'a> {
    ///Return the `FontData` used to resolve offsets for this table.
    pub fn offset_data(&self) -> FontData<'a> {
        match self {
            Self::Device(item) => item.offset_data(),
            Self::VariationIndex(item) => item.offset_data(),
        }
    }
}

impl<'a> FontRead<'a> for DeviceOrVariationIndex<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: DeltaFormat = data.read_at(4usize)?;

        #[allow(clippy::redundant_guards)]
        match format {
            format if format != DeltaFormat::VariationIndex => {
                Ok(Self::Device(FontRead::read(data)?))
            }
            format if format == DeltaFormat::VariationIndex => {
                Ok(Self::VariationIndex(FontRead::read(data)?))
            }
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl MinByteRange for DeviceOrVariationIndex<'_> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Device(item) => item.min_byte_range(),
            Self::VariationIndex(item) => item.min_byte_range(),
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> DeviceOrVariationIndex<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Device(table) => table,
            Self::VariationIndex(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for DeviceOrVariationIndex<'_> {
    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 DeviceOrVariationIndex<'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)
    }
}

/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureVariationsMarker {
    feature_variation_records_byte_len: usize,
}

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

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

    pub fn feature_variation_records_byte_range(&self) -> Range<usize> {
        let start = self.feature_variation_record_count_byte_range().end;
        start..start + self.feature_variation_records_byte_len
    }
}

impl MinByteRange for FeatureVariationsMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.feature_variation_records_byte_range().end
    }
}

impl<'a> FontRead<'a> for FeatureVariations<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<MajorMinor>();
        let feature_variation_record_count: u32 = cursor.read()?;
        let feature_variation_records_byte_len = (feature_variation_record_count as usize)
            .checked_mul(FeatureVariationRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(feature_variation_records_byte_len);
        cursor.finish(FeatureVariationsMarker {
            feature_variation_records_byte_len,
        })
    }
}

/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
pub type FeatureVariations<'a> = TableRef<'a, FeatureVariationsMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> FeatureVariations<'a> {
    pub fn version(&self) -> MajorMinor {
        let range = self.shape.version_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of feature variation records.
    pub fn feature_variation_record_count(&self) -> u32 {
        let range = self.shape.feature_variation_record_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of feature variation records.
    pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] {
        let range = self.shape.feature_variation_records_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Part of [FeatureVariations]
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FeatureVariationRecord {
    /// Offset to a condition set table, from beginning of
    /// FeatureVariations table.
    pub condition_set_offset: BigEndian<Nullable<Offset32>>,
    /// Offset to a feature table substitution table, from beginning of
    /// the FeatureVariations table.
    pub feature_table_substitution_offset: BigEndian<Nullable<Offset32>>,
}

impl FeatureVariationRecord {
    /// Offset to a condition set table, from beginning of
    /// FeatureVariations table.
    pub fn condition_set_offset(&self) -> Nullable<Offset32> {
        self.condition_set_offset.get()
    }

    /// Offset to a condition set table, from beginning of
    /// FeatureVariations table.
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn condition_set<'a>(
        &self,
        data: FontData<'a>,
    ) -> Option<Result<ConditionSet<'a>, ReadError>> {
        self.condition_set_offset().resolve(data)
    }

    /// Offset to a feature table substitution table, from beginning of
    /// the FeatureVariations table.
    pub fn feature_table_substitution_offset(&self) -> Nullable<Offset32> {
        self.feature_table_substitution_offset.get()
    }

    /// Offset to a feature table substitution table, from beginning of
    /// the FeatureVariations table.
    ///
    /// The `data` argument should be retrieved from the parent table
    /// By calling its `offset_data` method.
    pub fn feature_table_substitution<'a>(
        &self,
        data: FontData<'a>,
    ) -> Option<Result<FeatureTableSubstitution<'a>, ReadError>> {
        self.feature_table_substitution_offset().resolve(data)
    }
}

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

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

/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionSetMarker {
    condition_offsets_byte_len: usize,
}

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

    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
        let start = self.condition_count_byte_range().end;
        start..start + self.condition_offsets_byte_len
    }
}

impl MinByteRange for ConditionSetMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.condition_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ConditionSet<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let condition_count: u16 = cursor.read()?;
        let condition_offsets_byte_len = (condition_count as usize)
            .checked_mul(Offset32::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(condition_offsets_byte_len);
        cursor.finish(ConditionSetMarker {
            condition_offsets_byte_len,
        })
    }
}

/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
pub type ConditionSet<'a> = TableRef<'a, ConditionSetMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionSet<'a> {
    /// Number of conditions for this condition set.
    pub fn condition_count(&self) -> u16 {
        let range = self.shape.condition_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of offsets to condition tables, from beginning of the
    /// ConditionSet table.
    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset32>] {
        let range = self.shape.condition_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset32> {
        let data = self.data;
        let offsets = self.condition_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionSet<'a> {
    fn type_name(&self) -> &str {
        "ConditionSet"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("condition_count", self.condition_count())),
            1usize => Some({
                let data = self.data;
                Field::new(
                    "condition_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<Condition>(),
                        self.condition_offsets(),
                        move |off| {
                            let target = off.get().resolve::<Condition>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

/// [Condition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table)
///
/// Formats 2..5 are implementations of specification changes currently under debate at ISO for an OFF
/// update. For the time being the specification is <https://github.com/harfbuzz/boring-expansion-spec/blob/main/ConditionTree.md>.
#[derive(Clone)]
pub enum Condition<'a> {
    Format1AxisRange(ConditionFormat1<'a>),
    Format2VariableValue(ConditionFormat2<'a>),
    Format3And(ConditionFormat3<'a>),
    Format4Or(ConditionFormat4<'a>),
    Format5Negate(ConditionFormat5<'a>),
}

impl<'a> Condition<'a> {
    ///Return the `FontData` used to resolve offsets for this table.
    pub fn offset_data(&self) -> FontData<'a> {
        match self {
            Self::Format1AxisRange(item) => item.offset_data(),
            Self::Format2VariableValue(item) => item.offset_data(),
            Self::Format3And(item) => item.offset_data(),
            Self::Format4Or(item) => item.offset_data(),
            Self::Format5Negate(item) => item.offset_data(),
        }
    }

    /// Format, = 1
    pub fn format(&self) -> u16 {
        match self {
            Self::Format1AxisRange(item) => item.format(),
            Self::Format2VariableValue(item) => item.format(),
            Self::Format3And(item) => item.format(),
            Self::Format4Or(item) => item.format(),
            Self::Format5Negate(item) => item.format(),
        }
    }
}

impl<'a> FontRead<'a> for Condition<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u16 = data.read_at(0usize)?;
        match format {
            ConditionFormat1Marker::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)),
            ConditionFormat2Marker::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)),
            ConditionFormat3Marker::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)),
            ConditionFormat4Marker::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)),
            ConditionFormat5Marker::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl MinByteRange for Condition<'_> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Format1AxisRange(item) => item.min_byte_range(),
            Self::Format2VariableValue(item) => item.min_byte_range(),
            Self::Format3And(item) => item.min_byte_range(),
            Self::Format4Or(item) => item.min_byte_range(),
            Self::Format5Negate(item) => item.min_byte_range(),
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> Condition<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Format1AxisRange(table) => table,
            Self::Format2VariableValue(table) => table,
            Self::Format3And(table) => table,
            Self::Format4Or(table) => table,
            Self::Format5Negate(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for Condition<'_> {
    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 Condition<'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 ConditionFormat1Marker {
    const FORMAT: u16 = 1;
}

/// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat1Marker {}

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

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

    pub fn filter_range_min_value_byte_range(&self) -> Range<usize> {
        let start = self.axis_index_byte_range().end;
        start..start + F2Dot14::RAW_BYTE_LEN
    }

    pub fn filter_range_max_value_byte_range(&self) -> Range<usize> {
        let start = self.filter_range_min_value_byte_range().end;
        start..start + F2Dot14::RAW_BYTE_LEN
    }
}

impl MinByteRange for ConditionFormat1Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.filter_range_max_value_byte_range().end
    }
}

impl<'a> FontRead<'a> for ConditionFormat1<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<F2Dot14>();
        cursor.advance::<F2Dot14>();
        cursor.finish(ConditionFormat1Marker {})
    }
}

/// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range
pub type ConditionFormat1<'a> = TableRef<'a, ConditionFormat1Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat1<'a> {
    /// Format, = 1
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Index (zero-based) for the variation axis within the 'fvar'
    /// table.
    pub fn axis_index(&self) -> u16 {
        let range = self.shape.axis_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Minimum value of the font variation instances that satisfy this
    /// condition.
    pub fn filter_range_min_value(&self) -> F2Dot14 {
        let range = self.shape.filter_range_min_value_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Maximum value of the font variation instances that satisfy this
    /// condition.
    pub fn filter_range_max_value(&self) -> F2Dot14 {
        let range = self.shape.filter_range_max_value_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

impl Format<u16> for ConditionFormat2Marker {
    const FORMAT: u16 = 2;
}

/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat2Marker {}

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

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

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

impl MinByteRange for ConditionFormat2Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.var_index_byte_range().end
    }
}

impl<'a> FontRead<'a> for ConditionFormat2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<i16>();
        cursor.advance::<u32>();
        cursor.finish(ConditionFormat2Marker {})
    }
}

/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
pub type ConditionFormat2<'a> = TableRef<'a, ConditionFormat2Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat2<'a> {
    /// Format, = 2
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Value at default instance.
    pub fn default_value(&self) -> i16 {
        let range = self.shape.default_value_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Variation index to vary the value based on current designspace location.
    pub fn var_index(&self) -> u32 {
        let range = self.shape.var_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

impl Format<u16> for ConditionFormat3Marker {
    const FORMAT: u16 = 3;
}

/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat3Marker {
    condition_offsets_byte_len: usize,
}

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

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

    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
        let start = self.condition_count_byte_range().end;
        start..start + self.condition_offsets_byte_len
    }
}

impl MinByteRange for ConditionFormat3Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.condition_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ConditionFormat3<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let condition_count: u8 = cursor.read()?;
        let condition_offsets_byte_len = (condition_count as usize)
            .checked_mul(Offset24::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(condition_offsets_byte_len);
        cursor.finish(ConditionFormat3Marker {
            condition_offsets_byte_len,
        })
    }
}

/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
pub type ConditionFormat3<'a> = TableRef<'a, ConditionFormat3Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat3<'a> {
    /// Format, = 3
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of conditions.
    pub fn condition_count(&self) -> u8 {
        let range = self.shape.condition_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of condition tables for this conjunction (AND) expression.
    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
        let range = self.shape.condition_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
        let data = self.data;
        let offsets = self.condition_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat3<'a> {
    fn type_name(&self) -> &str {
        "ConditionFormat3"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("condition_count", self.condition_count())),
            2usize => Some({
                let data = self.data;
                Field::new(
                    "condition_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<Condition>(),
                        self.condition_offsets(),
                        move |off| {
                            let target = off.get().resolve::<Condition>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

impl Format<u16> for ConditionFormat4Marker {
    const FORMAT: u16 = 4;
}

/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat4Marker {
    condition_offsets_byte_len: usize,
}

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

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

    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
        let start = self.condition_count_byte_range().end;
        start..start + self.condition_offsets_byte_len
    }
}

impl MinByteRange for ConditionFormat4Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.condition_offsets_byte_range().end
    }
}

impl<'a> FontRead<'a> for ConditionFormat4<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let condition_count: u8 = cursor.read()?;
        let condition_offsets_byte_len = (condition_count as usize)
            .checked_mul(Offset24::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(condition_offsets_byte_len);
        cursor.finish(ConditionFormat4Marker {
            condition_offsets_byte_len,
        })
    }
}

/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
pub type ConditionFormat4<'a> = TableRef<'a, ConditionFormat4Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat4<'a> {
    /// Format, = 4
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of conditions.
    pub fn condition_count(&self) -> u8 {
        let range = self.shape.condition_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of condition tables for this disjunction (OR) expression.
    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
        let range = self.shape.condition_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
        let data = self.data;
        let offsets = self.condition_offsets();
        ArrayOfOffsets::new(offsets, data, ())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat4<'a> {
    fn type_name(&self) -> &str {
        "ConditionFormat4"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("condition_count", self.condition_count())),
            2usize => Some({
                let data = self.data;
                Field::new(
                    "condition_offsets",
                    FieldType::array_of_offsets(
                        better_type_name::<Condition>(),
                        self.condition_offsets(),
                        move |off| {
                            let target = off.get().resolve::<Condition>(data);
                            FieldType::offset(off.get(), target)
                        },
                    ),
                )
            }),
            _ => None,
        }
    }
}

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

impl Format<u16> for ConditionFormat5Marker {
    const FORMAT: u16 = 5;
}

/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct ConditionFormat5Marker {}

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

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

impl MinByteRange for ConditionFormat5Marker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.condition_offset_byte_range().end
    }
}

impl<'a> FontRead<'a> for ConditionFormat5<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<Offset24>();
        cursor.finish(ConditionFormat5Marker {})
    }
}

/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
pub type ConditionFormat5<'a> = TableRef<'a, ConditionFormat5Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> ConditionFormat5<'a> {
    /// Format, = 5
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Condition to negate.
    pub fn condition_offset(&self) -> Offset24 {
        let range = self.shape.condition_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`condition_offset`][Self::condition_offset].
    pub fn condition(&self) -> Result<Condition<'a>, ReadError> {
        let data = self.data;
        self.condition_offset().resolve(data)
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for ConditionFormat5<'a> {
    fn type_name(&self) -> &str {
        "ConditionFormat5"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new(
                "condition_offset",
                FieldType::offset(self.condition_offset(), self.condition()),
            )),
            _ => None,
        }
    }
}

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

/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FeatureTableSubstitutionMarker {
    substitutions_byte_len: usize,
}

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

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

    pub fn substitutions_byte_range(&self) -> Range<usize> {
        let start = self.substitution_count_byte_range().end;
        start..start + self.substitutions_byte_len
    }
}

impl MinByteRange for FeatureTableSubstitutionMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.substitutions_byte_range().end
    }
}

impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<MajorMinor>();
        let substitution_count: u16 = cursor.read()?;
        let substitutions_byte_len = (substitution_count as usize)
            .checked_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(substitutions_byte_len);
        cursor.finish(FeatureTableSubstitutionMarker {
            substitutions_byte_len,
        })
    }
}

/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
pub type FeatureTableSubstitution<'a> = TableRef<'a, FeatureTableSubstitutionMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> FeatureTableSubstitution<'a> {
    /// Major & minor version of the table: (1, 0)
    pub fn version(&self) -> MajorMinor {
        let range = self.shape.version_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of feature table substitution records.
    pub fn substitution_count(&self) -> u16 {
        let range = self.shape.substitution_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of feature table substitution records.
    pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] {
        let range = self.shape.substitutions_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Used in [FeatureTableSubstitution]
#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FeatureTableSubstitutionRecord {
    /// The feature table index to match.
    pub feature_index: BigEndian<u16>,
    /// Offset to an alternate feature table, from start of the
    /// FeatureTableSubstitution table.
    pub alternate_feature_offset: BigEndian<Offset32>,
}

impl FeatureTableSubstitutionRecord {
    /// The feature table index to match.
    pub fn feature_index(&self) -> u16 {
        self.feature_index.get()
    }

    /// Offset to an alternate feature table, from start of the
    /// FeatureTableSubstitution table.
    pub fn alternate_feature_offset(&self) -> Offset32 {
        self.alternate_feature_offset.get()
    }
}

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

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

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct SizeParamsMarker {}

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

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

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

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

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

impl MinByteRange for SizeParamsMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.range_end_byte_range().end
    }
}

impl<'a> FontRead<'a> for SizeParams<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.finish(SizeParamsMarker {})
    }
}

pub type SizeParams<'a> = TableRef<'a, SizeParamsMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> SizeParams<'a> {
    /// The first value represents the design size in 720/inch units (decipoints).
    ///
    /// The design size entry must be non-zero. When there is a design size but
    /// no recommended size range, the rest of the array will consist of zeros.
    pub fn design_size(&self) -> u16 {
        let range = self.shape.design_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The second value has no independent meaning, but serves as an identifier that associates fonts in a subfamily.
    ///
    /// All fonts which share a Typographic or Font Family name and which differ
    /// only by size range shall have the same subfamily value, and no fonts
    /// which differ in weight or style shall have the same subfamily value.
    /// If this value is zero, the remaining fields in the array will be ignored.
    pub fn identifier(&self) -> u16 {
        let range = self.shape.identifier_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The third value enables applications to use a single name for the subfamily identified by the second value.
    ///
    /// If the preceding value is non-zero, this value must be set in the range
    /// 256 – 32767 (inclusive). It records the value of a field in the 'name'
    /// table, which must contain English-language strings encoded in Windows
    /// Unicode and Macintosh Roman, and may contain additional strings localized
    /// to other scripts and languages. Each of these strings is the name
    /// an application should use, in combination with the family name, to
    /// represent the subfamily in a menu. Applications will choose the
    /// appropriate version based on their selection criteria.
    pub fn name_entry(&self) -> u16 {
        let range = self.shape.name_entry_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The fourth and fifth values represent the small end of the recommended
    /// usage range (exclusive) and the large end of the recommended usage range
    /// (inclusive), stored in 720/inch units (decipoints).
    ///
    /// Ranges must not overlap, and should generally be contiguous.
    pub fn range_start(&self) -> u16 {
        let range = self.shape.range_start_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    pub fn range_end(&self) -> u16 {
        let range = self.shape.range_end_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for SizeParams<'a> {
    fn type_name(&self) -> &str {
        "SizeParams"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("design_size", self.design_size())),
            1usize => Some(Field::new("identifier", self.identifier())),
            2usize => Some(Field::new("name_entry", self.name_entry())),
            3usize => Some(Field::new("range_start", self.range_start())),
            4usize => Some(Field::new("range_end", self.range_end())),
            _ => None,
        }
    }
}

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

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct StylisticSetParamsMarker {}

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

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

impl MinByteRange for StylisticSetParamsMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.ui_name_id_byte_range().end
    }
}

impl<'a> FontRead<'a> for StylisticSetParams<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<NameId>();
        cursor.finish(StylisticSetParamsMarker {})
    }
}

pub type StylisticSetParams<'a> = TableRef<'a, StylisticSetParamsMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> StylisticSetParams<'a> {
    pub fn version(&self) -> u16 {
        let range = self.shape.version_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The 'name' table name ID that specifies a string (or strings, for
    /// multiple languages) for a user-interface label for this feature.
    ///
    /// The value of uiLabelNameId is expected to be in the font-specific name
    /// ID range (256-32767), though that is not a requirement in this Feature
    /// Parameters specification. The user-interface label for the feature can
    /// be provided in multiple languages. An English string should be included
    /// as a fallback. The string should be kept to a minimal length to fit
    /// comfortably with different application interfaces.
    pub fn ui_name_id(&self) -> NameId {
        let range = self.shape.ui_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

impl Format<u16> for CharacterVariantParamsMarker {
    const FORMAT: u16 = 0;
}

/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CharacterVariantParamsMarker {
    character_byte_len: usize,
}

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

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

    pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range<usize> {
        let start = self.feat_ui_label_name_id_byte_range().end;
        start..start + NameId::RAW_BYTE_LEN
    }

    pub fn sample_text_name_id_byte_range(&self) -> Range<usize> {
        let start = self.feat_ui_tooltip_text_name_id_byte_range().end;
        start..start + NameId::RAW_BYTE_LEN
    }

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

    pub fn first_param_ui_label_name_id_byte_range(&self) -> Range<usize> {
        let start = self.num_named_parameters_byte_range().end;
        start..start + NameId::RAW_BYTE_LEN
    }

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

    pub fn character_byte_range(&self) -> Range<usize> {
        let start = self.char_count_byte_range().end;
        start..start + self.character_byte_len
    }
}

impl MinByteRange for CharacterVariantParamsMarker {
    fn min_byte_range(&self) -> Range<usize> {
        0..self.character_byte_range().end
    }
}

impl<'a> FontRead<'a> for CharacterVariantParams<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        cursor.advance::<NameId>();
        cursor.advance::<NameId>();
        cursor.advance::<NameId>();
        cursor.advance::<u16>();
        cursor.advance::<NameId>();
        let char_count: u16 = cursor.read()?;
        let character_byte_len = (char_count as usize)
            .checked_mul(Uint24::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(character_byte_len);
        cursor.finish(CharacterVariantParamsMarker { character_byte_len })
    }
}

/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
pub type CharacterVariantParams<'a> = TableRef<'a, CharacterVariantParamsMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> CharacterVariantParams<'a> {
    /// Format number is set to 0.
    pub fn format(&self) -> u16 {
        let range = self.shape.format_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The 'name' table name ID that specifies a string (or strings,
    /// for multiple languages) for a user-interface label for this
    /// feature. (May be NULL.)
    pub fn feat_ui_label_name_id(&self) -> NameId {
        let range = self.shape.feat_ui_label_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The 'name' table name ID that specifies a string (or strings,
    /// for multiple languages) that an application can use for tooltip
    /// text for this feature. (May be NULL.)
    pub fn feat_ui_tooltip_text_name_id(&self) -> NameId {
        let range = self.shape.feat_ui_tooltip_text_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The 'name' table name ID that specifies sample text that
    /// illustrates the effect of this feature. (May be NULL.)
    pub fn sample_text_name_id(&self) -> NameId {
        let range = self.shape.sample_text_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Number of named parameters. (May be zero.)
    pub fn num_named_parameters(&self) -> u16 {
        let range = self.shape.num_named_parameters_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The first 'name' table name ID used to specify strings for
    /// user-interface labels for the feature parameters. (Must be zero
    /// if numParameters is zero.)
    pub fn first_param_ui_label_name_id(&self) -> NameId {
        let range = self.shape.first_param_ui_label_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The count of characters for which this feature provides glyph
    /// variants. (May be zero.)
    pub fn char_count(&self) -> u16 {
        let range = self.shape.char_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The Unicode Scalar Value of the characters for which this
    /// feature provides glyph variants.
    pub fn character(&self) -> &'a [BigEndian<Uint24>] {
        let range = self.shape.character_byte_range();
        self.data.read_array(range).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for CharacterVariantParams<'a> {
    fn type_name(&self) -> &str {
        "CharacterVariantParams"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new(
                "feat_ui_label_name_id",
                self.feat_ui_label_name_id(),
            )),
            2usize => Some(Field::new(
                "feat_ui_tooltip_text_name_id",
                self.feat_ui_tooltip_text_name_id(),
            )),
            3usize => Some(Field::new(
                "sample_text_name_id",
                self.sample_text_name_id(),
            )),
            4usize => Some(Field::new(
                "num_named_parameters",
                self.num_named_parameters(),
            )),
            5usize => Some(Field::new(
                "first_param_ui_label_name_id",
                self.first_param_ui_label_name_id(),
            )),
            6usize => Some(Field::new("char_count", self.char_count())),
            7usize => Some(Field::new("character", self.character())),
            _ => None,
        }
    }
}

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