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

pub use read_fonts::tables::layout::DeltaFormat;

/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ScriptList {
    /// Array of ScriptRecords, listed alphabetically by script tag
    pub script_records: Vec<ScriptRecord>,
}

impl ScriptList {
    /// Construct a new `ScriptList`
    pub fn new(script_records: Vec<ScriptRecord>) -> Self {
        Self { script_records }
    }
}

impl FontWrite for ScriptList {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.script_records)).unwrap()).write_into(writer);
        self.script_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ScriptList")
    }
}

impl Validate for ScriptList {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ScriptList", |ctx| {
            ctx.in_field("script_records", |ctx| {
                if self.script_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.script_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ScriptList<'a>> for ScriptList {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ScriptList<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        ScriptList {
            script_records: obj.script_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ScriptList<'a>> for ScriptList {}

impl<'a> FontRead<'a> for ScriptList {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ScriptList as FontRead>::read(data).map(|x| x.to_owned_table())
    }
}

/// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ScriptRecord {
    /// 4-byte script tag identifier
    pub script_tag: Tag,
    /// Offset to Script table, from beginning of ScriptList
    pub script: OffsetMarker<Script>,
}

impl ScriptRecord {
    /// Construct a new `ScriptRecord`
    pub fn new(script_tag: Tag, script: Script) -> Self {
        Self {
            script_tag,
            script: script.into(),
        }
    }
}

impl FontWrite for ScriptRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.script_tag.write_into(writer);
        self.script.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ScriptRecord")
    }
}

impl Validate for ScriptRecord {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ScriptRecord", |ctx| {
            ctx.in_field("script", |ctx| {
                self.script.validate_impl(ctx);
            });
        })
    }
}

impl FromObjRef<read_fonts::tables::layout::ScriptRecord> for ScriptRecord {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ScriptRecord, offset_data: FontData) -> Self {
        ScriptRecord {
            script_tag: obj.script_tag(),
            script: obj.script(offset_data).to_owned_table(),
        }
    }
}

/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Script {
    /// Offset to default LangSys table, from beginning of Script table
    /// — may be NULL
    pub default_lang_sys: NullableOffsetMarker<LangSys>,
    /// Array of LangSysRecords, listed alphabetically by LangSys tag
    pub lang_sys_records: Vec<LangSysRecord>,
}

impl Script {
    /// Construct a new `Script`
    pub fn new(default_lang_sys: Option<LangSys>, lang_sys_records: Vec<LangSysRecord>) -> Self {
        Self {
            default_lang_sys: default_lang_sys.into(),
            lang_sys_records,
        }
    }
}

impl FontWrite for Script {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        self.default_lang_sys.write_into(writer);
        (u16::try_from(array_len(&self.lang_sys_records)).unwrap()).write_into(writer);
        self.lang_sys_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("Script")
    }
}

impl Validate for Script {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("Script", |ctx| {
            ctx.in_field("default_lang_sys", |ctx| {
                self.default_lang_sys.validate_impl(ctx);
            });
            ctx.in_field("lang_sys_records", |ctx| {
                if self.lang_sys_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.lang_sys_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::Script<'a>> for Script {
    fn from_obj_ref(obj: &read_fonts::tables::layout::Script<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        Script {
            default_lang_sys: obj.default_lang_sys().to_owned_table(),
            lang_sys_records: obj.lang_sys_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::Script<'a>> for Script {}

impl<'a> FontRead<'a> for Script {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::Script as FontRead>::read(data).map(|x| x.to_owned_table())
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LangSysRecord {
    /// 4-byte LangSysTag identifier
    pub lang_sys_tag: Tag,
    /// Offset to LangSys table, from beginning of Script table
    pub lang_sys: OffsetMarker<LangSys>,
}

impl LangSysRecord {
    /// Construct a new `LangSysRecord`
    pub fn new(lang_sys_tag: Tag, lang_sys: LangSys) -> Self {
        Self {
            lang_sys_tag,
            lang_sys: lang_sys.into(),
        }
    }
}

impl FontWrite for LangSysRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.lang_sys_tag.write_into(writer);
        self.lang_sys.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("LangSysRecord")
    }
}

impl Validate for LangSysRecord {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("LangSysRecord", |ctx| {
            ctx.in_field("lang_sys", |ctx| {
                self.lang_sys.validate_impl(ctx);
            });
        })
    }
}

impl FromObjRef<read_fonts::tables::layout::LangSysRecord> for LangSysRecord {
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::LangSysRecord,
        offset_data: FontData,
    ) -> Self {
        LangSysRecord {
            lang_sys_tag: obj.lang_sys_tag(),
            lang_sys: obj.lang_sys(offset_data).to_owned_table(),
        }
    }
}

/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LangSys {
    /// Index of a feature required for this language system; if no
    /// required features = 0xFFFF
    pub required_feature_index: u16,
    /// Array of indices into the FeatureList, in arbitrary order
    pub feature_indices: Vec<u16>,
}

impl Default for LangSys {
    fn default() -> Self {
        Self {
            required_feature_index: 0xFFFF,
            feature_indices: Default::default(),
        }
    }
}

impl LangSys {
    /// Construct a new `LangSys`
    pub fn new(feature_indices: Vec<u16>) -> Self {
        Self {
            feature_indices,
            ..Default::default()
        }
    }
}

impl FontWrite for LangSys {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (0 as u16).write_into(writer);
        self.required_feature_index.write_into(writer);
        (u16::try_from(array_len(&self.feature_indices)).unwrap()).write_into(writer);
        self.feature_indices.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("LangSys")
    }
}

impl Validate for LangSys {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("LangSys", |ctx| {
            ctx.in_field("feature_indices", |ctx| {
                if self.feature_indices.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::LangSys<'a>> for LangSys {
    fn from_obj_ref(obj: &read_fonts::tables::layout::LangSys<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        LangSys {
            required_feature_index: obj.required_feature_index(),
            feature_indices: obj.feature_indices().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::LangSys<'a>> for LangSys {}

impl<'a> FontRead<'a> for LangSys {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::LangSys as FontRead>::read(data).map(|x| x.to_owned_table())
    }
}

/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FeatureList {
    /// Array of FeatureRecords — zero-based (first feature has
    /// FeatureIndex = 0), listed alphabetically by feature tag
    pub feature_records: Vec<FeatureRecord>,
}

impl FeatureList {
    /// Construct a new `FeatureList`
    pub fn new(feature_records: Vec<FeatureRecord>) -> Self {
        Self { feature_records }
    }
}

impl FontWrite for FeatureList {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.feature_records)).unwrap()).write_into(writer);
        self.feature_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("FeatureList")
    }
}

impl Validate for FeatureList {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("FeatureList", |ctx| {
            ctx.in_field("feature_records", |ctx| {
                if self.feature_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.feature_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::FeatureList<'a>> for FeatureList {
    fn from_obj_ref(obj: &read_fonts::tables::layout::FeatureList<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        FeatureList {
            feature_records: obj.feature_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::FeatureList<'a>> for FeatureList {}

impl<'a> FontRead<'a> for FeatureList {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::FeatureList as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [FeatureList]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FeatureRecord {
    /// 4-byte feature identification tag
    pub feature_tag: Tag,
    /// Offset to Feature table, from beginning of FeatureList
    pub feature: OffsetMarker<Feature>,
}

impl FeatureRecord {
    /// Construct a new `FeatureRecord`
    pub fn new(feature_tag: Tag, feature: Feature) -> Self {
        Self {
            feature_tag,
            feature: feature.into(),
        }
    }
}

impl FontWrite for FeatureRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.feature_tag.write_into(writer);
        self.feature.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("FeatureRecord")
    }
}

impl Validate for FeatureRecord {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("FeatureRecord", |ctx| {
            ctx.in_field("feature", |ctx| {
                self.feature.validate_impl(ctx);
            });
        })
    }
}

impl FromObjRef<read_fonts::tables::layout::FeatureRecord> for FeatureRecord {
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::FeatureRecord,
        offset_data: FontData,
    ) -> Self {
        FeatureRecord {
            feature_tag: obj.feature_tag(),
            feature: obj.feature(offset_data).to_owned_table(),
        }
    }
}

/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Feature {
    /// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL
    pub feature_params: NullableOffsetMarker<FeatureParams>,
    /// Array of indices into the LookupList — zero-based (first
    /// lookup is LookupListIndex = 0)
    pub lookup_list_indices: Vec<u16>,
}

impl Feature {
    /// Construct a new `Feature`
    pub fn new(feature_params: Option<FeatureParams>, lookup_list_indices: Vec<u16>) -> Self {
        Self {
            feature_params: feature_params.into(),
            lookup_list_indices,
        }
    }
}

impl FontWrite for Feature {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        self.feature_params.write_into(writer);
        (u16::try_from(array_len(&self.lookup_list_indices)).unwrap()).write_into(writer);
        self.lookup_list_indices.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("Feature")
    }
}

impl Validate for Feature {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("Feature", |ctx| {
            ctx.in_field("feature_params", |ctx| {
                self.feature_params.validate_impl(ctx);
            });
            ctx.in_field("lookup_list_indices", |ctx| {
                if self.lookup_list_indices.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::Feature<'a>> for Feature {
    fn from_obj_ref(obj: &read_fonts::tables::layout::Feature<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        Feature {
            feature_params: obj.feature_params().to_owned_table(),
            lookup_list_indices: obj.lookup_list_indices().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::Feature<'a>> for Feature {}

/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct LookupList<T> {
    /// Array of offsets to Lookup tables, from beginning of LookupList
    /// — zero based (first lookup is Lookup index = 0)
    pub lookups: Vec<OffsetMarker<T>>,
}

impl<T: Default> LookupList<T> {
    /// Construct a new `LookupList`
    pub fn new(lookups: Vec<T>) -> Self {
        Self {
            lookups: lookups.into_iter().map(Into::into).collect(),
        }
    }
}

impl<T: FontWrite> FontWrite for LookupList<T> {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.lookups)).unwrap()).write_into(writer);
        self.lookups.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("LookupList")
    }
}

impl<T: Validate> Validate for LookupList<T> {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("LookupList", |ctx| {
            ctx.in_field("lookups", |ctx| {
                if self.lookups.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.lookups.validate_impl(ctx);
            });
        })
    }
}

impl<'a, T, U> FromObjRef<read_fonts::tables::layout::LookupList<'a, U>> for LookupList<T>
where
    U: FontRead<'a>,
    T: FromTableRef<U> + Default + 'static,
{
    fn from_obj_ref(obj: &read_fonts::tables::layout::LookupList<'a, U>, _: FontData) -> Self {
        LookupList {
            lookups: obj.lookups().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a, T, U> FromTableRef<read_fonts::tables::layout::LookupList<'a, U>> for LookupList<T>
where
    U: FontRead<'a>,
    T: FromTableRef<U> + Default + 'static,
{
}

/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Lookup<T> {
    /// Lookup qualifiers
    pub lookup_flag: LookupFlag,
    /// Array of offsets to lookup subtables, from beginning of Lookup
    /// table
    pub subtables: Vec<OffsetMarker<T>>,
    /// 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 mark_filtering_set: Option<u16>,
}

impl<T: Default> Lookup<T> {
    /// Construct a new `Lookup`
    pub fn new(lookup_flag: LookupFlag, subtables: Vec<T>) -> Self {
        Self {
            lookup_flag,
            subtables: subtables.into_iter().map(Into::into).collect(),
            ..Default::default()
        }
    }
}

impl<T: Validate> Validate for Lookup<T> {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("Lookup", |ctx| {
            ctx.in_field("subtables", |ctx| {
                if self.subtables.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.subtables.validate_impl(ctx);
            });
            ctx.in_field("mark_filtering_set", |ctx| {
                if !(self
                    .lookup_flag
                    .contains(LookupFlag::USE_MARK_FILTERING_SET))
                    && self.mark_filtering_set.is_some()
                {
                    ctx.report("'mark_filtering_set' is present but USE_MARK_FILTERING_SET not set")
                }
                if (self
                    .lookup_flag
                    .contains(LookupFlag::USE_MARK_FILTERING_SET))
                    && self.mark_filtering_set.is_none()
                {
                    ctx.report("USE_MARK_FILTERING_SET is set but 'mark_filtering_set' is None")
                }
            });
        })
    }
}

impl<'a, T, U> FromObjRef<read_fonts::tables::layout::Lookup<'a, U>> for Lookup<T>
where
    U: FontRead<'a>,
    T: FromTableRef<U> + Default + 'static,
{
    fn from_obj_ref(obj: &read_fonts::tables::layout::Lookup<'a, U>, _: FontData) -> Self {
        Lookup {
            lookup_flag: obj.lookup_flag(),
            subtables: obj.subtables().to_owned_table(),
            mark_filtering_set: obj.mark_filtering_set(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a, T, U> FromTableRef<read_fonts::tables::layout::Lookup<'a, U>> for Lookup<T>
where
    U: FontRead<'a>,
    T: FromTableRef<U> + Default + 'static,
{
}

/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CoverageFormat1 {
    /// Array of glyph IDs — in numerical order
    pub glyph_array: Vec<GlyphId16>,
}

impl CoverageFormat1 {
    /// Construct a new `CoverageFormat1`
    pub fn new(glyph_array: Vec<GlyphId16>) -> Self {
        Self { glyph_array }
    }
}

impl FontWrite for CoverageFormat1 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (1 as u16).write_into(writer);
        (u16::try_from(array_len(&self.glyph_array)).unwrap()).write_into(writer);
        self.glyph_array.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("CoverageFormat1")
    }
}

impl Validate for CoverageFormat1 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("CoverageFormat1", |ctx| {
            ctx.in_field("glyph_array", |ctx| {
                if self.glyph_array.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::CoverageFormat1<'a>> for CoverageFormat1 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::CoverageFormat1<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        CoverageFormat1 {
            glyph_array: obj.glyph_array().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::CoverageFormat1<'a>> for CoverageFormat1 {}

impl<'a> FontRead<'a> for CoverageFormat1 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::CoverageFormat1 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CoverageFormat2 {
    /// Array of glyph ranges — ordered by startGlyphID.
    pub range_records: Vec<RangeRecord>,
}

impl CoverageFormat2 {
    /// Construct a new `CoverageFormat2`
    pub fn new(range_records: Vec<RangeRecord>) -> Self {
        Self { range_records }
    }
}

impl FontWrite for CoverageFormat2 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (2 as u16).write_into(writer);
        (u16::try_from(array_len(&self.range_records)).unwrap()).write_into(writer);
        self.range_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("CoverageFormat2")
    }
}

impl Validate for CoverageFormat2 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("CoverageFormat2", |ctx| {
            ctx.in_field("range_records", |ctx| {
                if self.range_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.range_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::CoverageFormat2<'a>> for CoverageFormat2 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::CoverageFormat2<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        CoverageFormat2 {
            range_records: obj.range_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::CoverageFormat2<'a>> for CoverageFormat2 {}

impl<'a> FontRead<'a> for CoverageFormat2 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::CoverageFormat2 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Used in [CoverageFormat2]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RangeRecord {
    /// First glyph ID in the range
    pub start_glyph_id: GlyphId16,
    /// Last glyph ID in the range
    pub end_glyph_id: GlyphId16,
    /// Coverage Index of first glyph ID in range
    pub start_coverage_index: u16,
}

impl RangeRecord {
    /// Construct a new `RangeRecord`
    pub fn new(
        start_glyph_id: GlyphId16,
        end_glyph_id: GlyphId16,
        start_coverage_index: u16,
    ) -> Self {
        Self {
            start_glyph_id,
            end_glyph_id,
            start_coverage_index,
        }
    }
}

impl FontWrite for RangeRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.start_glyph_id.write_into(writer);
        self.end_glyph_id.write_into(writer);
        self.start_coverage_index.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("RangeRecord")
    }
}

impl Validate for RangeRecord {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl FromObjRef<read_fonts::tables::layout::RangeRecord> for RangeRecord {
    fn from_obj_ref(obj: &read_fonts::tables::layout::RangeRecord, _: FontData) -> Self {
        RangeRecord {
            start_glyph_id: obj.start_glyph_id(),
            end_glyph_id: obj.end_glyph_id(),
            start_coverage_index: obj.start_coverage_index(),
        }
    }
}

/// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CoverageTable {
    Format1(CoverageFormat1),
    Format2(CoverageFormat2),
}

impl CoverageTable {
    /// Construct a new `CoverageFormat1` subtable
    pub fn format_1(glyph_array: Vec<GlyphId16>) -> Self {
        Self::Format1(CoverageFormat1::new(glyph_array))
    }

    /// Construct a new `CoverageFormat2` subtable
    pub fn format_2(range_records: Vec<RangeRecord>) -> Self {
        Self::Format2(CoverageFormat2::new(range_records))
    }
}

impl Default for CoverageTable {
    fn default() -> Self {
        Self::Format1(Default::default())
    }
}

impl FontWrite for CoverageTable {
    fn write_into(&self, writer: &mut TableWriter) {
        match self {
            Self::Format1(item) => item.write_into(writer),
            Self::Format2(item) => item.write_into(writer),
        }
    }
    fn table_type(&self) -> TableType {
        match self {
            Self::Format1(item) => item.table_type(),
            Self::Format2(item) => item.table_type(),
        }
    }
}

impl Validate for CoverageTable {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        match self {
            Self::Format1(item) => item.validate_impl(ctx),
            Self::Format2(item) => item.validate_impl(ctx),
        }
    }
}

impl FromObjRef<read_fonts::tables::layout::CoverageTable<'_>> for CoverageTable {
    fn from_obj_ref(obj: &read_fonts::tables::layout::CoverageTable, _: FontData) -> Self {
        use read_fonts::tables::layout::CoverageTable as ObjRefType;
        match obj {
            ObjRefType::Format1(item) => CoverageTable::Format1(item.to_owned_table()),
            ObjRefType::Format2(item) => CoverageTable::Format2(item.to_owned_table()),
        }
    }
}

impl FromTableRef<read_fonts::tables::layout::CoverageTable<'_>> for CoverageTable {}

impl<'a> FontRead<'a> for CoverageTable {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::CoverageTable as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

impl From<CoverageFormat1> for CoverageTable {
    fn from(src: CoverageFormat1) -> CoverageTable {
        CoverageTable::Format1(src)
    }
}

impl From<CoverageFormat2> for CoverageTable {
    fn from(src: CoverageFormat2) -> CoverageTable {
        CoverageTable::Format2(src)
    }
}

/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClassDefFormat1 {
    /// First glyph ID of the classValueArray
    pub start_glyph_id: GlyphId16,
    /// Array of Class Values — one per glyph ID
    pub class_value_array: Vec<u16>,
}

impl ClassDefFormat1 {
    /// Construct a new `ClassDefFormat1`
    pub fn new(start_glyph_id: GlyphId16, class_value_array: Vec<u16>) -> Self {
        Self {
            start_glyph_id,
            class_value_array,
        }
    }
}

impl FontWrite for ClassDefFormat1 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (1 as u16).write_into(writer);
        self.start_glyph_id.write_into(writer);
        (u16::try_from(array_len(&self.class_value_array)).unwrap()).write_into(writer);
        self.class_value_array.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ClassDefFormat1")
    }
}

impl Validate for ClassDefFormat1 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ClassDefFormat1", |ctx| {
            ctx.in_field("class_value_array", |ctx| {
                if self.class_value_array.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ClassDefFormat1<'a>> for ClassDefFormat1 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassDefFormat1<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        ClassDefFormat1 {
            start_glyph_id: obj.start_glyph_id(),
            class_value_array: obj.class_value_array().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ClassDefFormat1<'a>> for ClassDefFormat1 {}

impl<'a> FontRead<'a> for ClassDefFormat1 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ClassDefFormat1 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClassDefFormat2 {
    /// Array of ClassRangeRecords — ordered by startGlyphID
    pub class_range_records: Vec<ClassRangeRecord>,
}

impl ClassDefFormat2 {
    /// Construct a new `ClassDefFormat2`
    pub fn new(class_range_records: Vec<ClassRangeRecord>) -> Self {
        Self {
            class_range_records,
        }
    }
}

impl FontWrite for ClassDefFormat2 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (2 as u16).write_into(writer);
        (u16::try_from(array_len(&self.class_range_records)).unwrap()).write_into(writer);
        self.class_range_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ClassDefFormat2")
    }
}

impl Validate for ClassDefFormat2 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ClassDefFormat2", |ctx| {
            ctx.in_field("class_range_records", |ctx| {
                if self.class_range_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.class_range_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ClassDefFormat2<'a>> for ClassDefFormat2 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassDefFormat2<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        ClassDefFormat2 {
            class_range_records: obj.class_range_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ClassDefFormat2<'a>> for ClassDefFormat2 {}

impl<'a> FontRead<'a> for ClassDefFormat2 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ClassDefFormat2 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Used in [ClassDefFormat2]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClassRangeRecord {
    /// First glyph ID in the range
    pub start_glyph_id: GlyphId16,
    /// Last glyph ID in the range
    pub end_glyph_id: GlyphId16,
    /// Applied to all glyphs in the range
    pub class: u16,
}

impl ClassRangeRecord {
    /// Construct a new `ClassRangeRecord`
    pub fn new(start_glyph_id: GlyphId16, end_glyph_id: GlyphId16, class: u16) -> Self {
        Self {
            start_glyph_id,
            end_glyph_id,
            class,
        }
    }
}

impl FontWrite for ClassRangeRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.start_glyph_id.write_into(writer);
        self.end_glyph_id.write_into(writer);
        self.class.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ClassRangeRecord")
    }
}

impl Validate for ClassRangeRecord {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ClassRangeRecord", |ctx| {
            ctx.in_field("start_glyph_id", |ctx| {
                self.validate_glyph_range(ctx);
            });
        })
    }
}

impl FromObjRef<read_fonts::tables::layout::ClassRangeRecord> for ClassRangeRecord {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassRangeRecord, _: FontData) -> Self {
        ClassRangeRecord {
            start_glyph_id: obj.start_glyph_id(),
            end_glyph_id: obj.end_glyph_id(),
            class: obj.class(),
        }
    }
}

/// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ClassDef {
    Format1(ClassDefFormat1),
    Format2(ClassDefFormat2),
}

impl ClassDef {
    /// Construct a new `ClassDefFormat1` subtable
    pub fn format_1(start_glyph_id: GlyphId16, class_value_array: Vec<u16>) -> Self {
        Self::Format1(ClassDefFormat1::new(start_glyph_id, class_value_array))
    }

    /// Construct a new `ClassDefFormat2` subtable
    pub fn format_2(class_range_records: Vec<ClassRangeRecord>) -> Self {
        Self::Format2(ClassDefFormat2::new(class_range_records))
    }
}

impl Default for ClassDef {
    fn default() -> Self {
        Self::Format1(Default::default())
    }
}

impl FontWrite for ClassDef {
    fn write_into(&self, writer: &mut TableWriter) {
        match self {
            Self::Format1(item) => item.write_into(writer),
            Self::Format2(item) => item.write_into(writer),
        }
    }
    fn table_type(&self) -> TableType {
        match self {
            Self::Format1(item) => item.table_type(),
            Self::Format2(item) => item.table_type(),
        }
    }
}

impl Validate for ClassDef {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        match self {
            Self::Format1(item) => item.validate_impl(ctx),
            Self::Format2(item) => item.validate_impl(ctx),
        }
    }
}

impl FromObjRef<read_fonts::tables::layout::ClassDef<'_>> for ClassDef {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassDef, _: FontData) -> Self {
        use read_fonts::tables::layout::ClassDef as ObjRefType;
        match obj {
            ObjRefType::Format1(item) => ClassDef::Format1(item.to_owned_table()),
            ObjRefType::Format2(item) => ClassDef::Format2(item.to_owned_table()),
        }
    }
}

impl FromTableRef<read_fonts::tables::layout::ClassDef<'_>> for ClassDef {}

impl<'a> FontRead<'a> for ClassDef {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ClassDef as FontRead>::read(data).map(|x| x.to_owned_table())
    }
}

impl From<ClassDefFormat1> for ClassDef {
    fn from(src: ClassDefFormat1) -> ClassDef {
        ClassDef::Format1(src)
    }
}

impl From<ClassDefFormat2> for ClassDef {
    fn from(src: ClassDefFormat2) -> ClassDef {
        ClassDef::Format2(src)
    }
}

/// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SequenceLookupRecord {
    /// Index (zero-based) into the input glyph sequence
    pub sequence_index: u16,
    /// Index (zero-based) into the LookupList
    pub lookup_list_index: u16,
}

impl SequenceLookupRecord {
    /// Construct a new `SequenceLookupRecord`
    pub fn new(sequence_index: u16, lookup_list_index: u16) -> Self {
        Self {
            sequence_index,
            lookup_list_index,
        }
    }
}

impl FontWrite for SequenceLookupRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.sequence_index.write_into(writer);
        self.lookup_list_index.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("SequenceLookupRecord")
    }
}

impl Validate for SequenceLookupRecord {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl FromObjRef<read_fonts::tables::layout::SequenceLookupRecord> for SequenceLookupRecord {
    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceLookupRecord, _: FontData) -> Self {
        SequenceLookupRecord {
            sequence_index: obj.sequence_index(),
            lookup_list_index: obj.lookup_list_index(),
        }
    }
}

/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SequenceContextFormat1 {
    /// Offset to Coverage table, from beginning of
    /// SequenceContextFormat1 table
    pub coverage: OffsetMarker<CoverageTable>,
    /// Array of offsets to SequenceRuleSet tables, from beginning of
    /// SequenceContextFormat1 table (offsets may be NULL)
    pub seq_rule_sets: Vec<NullableOffsetMarker<SequenceRuleSet>>,
}

impl SequenceContextFormat1 {
    /// Construct a new `SequenceContextFormat1`
    pub fn new(coverage: CoverageTable, seq_rule_sets: Vec<Option<SequenceRuleSet>>) -> Self {
        Self {
            coverage: coverage.into(),
            seq_rule_sets: seq_rule_sets.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for SequenceContextFormat1 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (1 as u16).write_into(writer);
        self.coverage.write_into(writer);
        (u16::try_from(array_len(&self.seq_rule_sets)).unwrap()).write_into(writer);
        self.seq_rule_sets.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("SequenceContextFormat1")
    }
}

impl Validate for SequenceContextFormat1 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("SequenceContextFormat1", |ctx| {
            ctx.in_field("coverage", |ctx| {
                self.coverage.validate_impl(ctx);
            });
            ctx.in_field("seq_rule_sets", |ctx| {
                if self.seq_rule_sets.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_rule_sets.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::SequenceContextFormat1<'a>>
    for SequenceContextFormat1
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::SequenceContextFormat1<'a>,
        _: FontData,
    ) -> Self {
        SequenceContextFormat1 {
            coverage: obj.coverage().to_owned_table(),
            seq_rule_sets: obj.seq_rule_sets().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::SequenceContextFormat1<'a>>
    for SequenceContextFormat1
{
}

impl<'a> FontRead<'a> for SequenceContextFormat1 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::SequenceContextFormat1 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [SequenceContextFormat1]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SequenceRuleSet {
    /// Array of offsets to SequenceRule tables, from beginning of the
    /// SequenceRuleSet table
    pub seq_rules: Vec<OffsetMarker<SequenceRule>>,
}

impl SequenceRuleSet {
    /// Construct a new `SequenceRuleSet`
    pub fn new(seq_rules: Vec<SequenceRule>) -> Self {
        Self {
            seq_rules: seq_rules.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for SequenceRuleSet {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.seq_rules)).unwrap()).write_into(writer);
        self.seq_rules.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("SequenceRuleSet")
    }
}

impl Validate for SequenceRuleSet {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("SequenceRuleSet", |ctx| {
            ctx.in_field("seq_rules", |ctx| {
                if self.seq_rules.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_rules.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::SequenceRuleSet<'a>> for SequenceRuleSet {
    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceRuleSet<'a>, _: FontData) -> Self {
        SequenceRuleSet {
            seq_rules: obj.seq_rules().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::SequenceRuleSet<'a>> for SequenceRuleSet {}

impl<'a> FontRead<'a> for SequenceRuleSet {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::SequenceRuleSet as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [SequenceContextFormat1]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SequenceRule {
    /// Array of input glyph IDs—starting with the second glyph
    pub input_sequence: Vec<GlyphId16>,
    /// Array of Sequence lookup records
    pub seq_lookup_records: Vec<SequenceLookupRecord>,
}

impl SequenceRule {
    /// Construct a new `SequenceRule`
    pub fn new(
        input_sequence: Vec<GlyphId16>,
        seq_lookup_records: Vec<SequenceLookupRecord>,
    ) -> Self {
        Self {
            input_sequence,
            seq_lookup_records,
        }
    }
}

impl FontWrite for SequenceRule {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
        self.input_sequence.write_into(writer);
        self.seq_lookup_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("SequenceRule")
    }
}

impl Validate for SequenceRule {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("SequenceRule", |ctx| {
            ctx.in_field("seq_lookup_records", |ctx| {
                if self.seq_lookup_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_lookup_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::SequenceRule<'a>> for SequenceRule {
    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceRule<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        SequenceRule {
            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::SequenceRule<'a>> for SequenceRule {}

impl<'a> FontRead<'a> for SequenceRule {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::SequenceRule as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SequenceContextFormat2 {
    /// Offset to Coverage table, from beginning of
    /// SequenceContextFormat2 table
    pub coverage: OffsetMarker<CoverageTable>,
    /// Offset to ClassDef table, from beginning of
    /// SequenceContextFormat2 table
    pub class_def: OffsetMarker<ClassDef>,
    /// Array of offsets to ClassSequenceRuleSet tables, from beginning
    /// of SequenceContextFormat2 table (may be NULL)
    pub class_seq_rule_sets: Vec<NullableOffsetMarker<ClassSequenceRuleSet>>,
}

impl SequenceContextFormat2 {
    /// Construct a new `SequenceContextFormat2`
    pub fn new(
        coverage: CoverageTable,
        class_def: ClassDef,
        class_seq_rule_sets: Vec<Option<ClassSequenceRuleSet>>,
    ) -> Self {
        Self {
            coverage: coverage.into(),
            class_def: class_def.into(),
            class_seq_rule_sets: class_seq_rule_sets.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for SequenceContextFormat2 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (2 as u16).write_into(writer);
        self.coverage.write_into(writer);
        self.class_def.write_into(writer);
        (u16::try_from(array_len(&self.class_seq_rule_sets)).unwrap()).write_into(writer);
        self.class_seq_rule_sets.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("SequenceContextFormat2")
    }
}

impl Validate for SequenceContextFormat2 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("SequenceContextFormat2", |ctx| {
            ctx.in_field("coverage", |ctx| {
                self.coverage.validate_impl(ctx);
            });
            ctx.in_field("class_def", |ctx| {
                self.class_def.validate_impl(ctx);
            });
            ctx.in_field("class_seq_rule_sets", |ctx| {
                if self.class_seq_rule_sets.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.class_seq_rule_sets.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::SequenceContextFormat2<'a>>
    for SequenceContextFormat2
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::SequenceContextFormat2<'a>,
        _: FontData,
    ) -> Self {
        SequenceContextFormat2 {
            coverage: obj.coverage().to_owned_table(),
            class_def: obj.class_def().to_owned_table(),
            class_seq_rule_sets: obj.class_seq_rule_sets().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::SequenceContextFormat2<'a>>
    for SequenceContextFormat2
{
}

impl<'a> FontRead<'a> for SequenceContextFormat2 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::SequenceContextFormat2 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [SequenceContextFormat2]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClassSequenceRuleSet {
    /// Array of offsets to ClassSequenceRule tables, from beginning of
    /// ClassSequenceRuleSet table
    pub class_seq_rules: Vec<OffsetMarker<ClassSequenceRule>>,
}

impl ClassSequenceRuleSet {
    /// Construct a new `ClassSequenceRuleSet`
    pub fn new(class_seq_rules: Vec<ClassSequenceRule>) -> Self {
        Self {
            class_seq_rules: class_seq_rules.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for ClassSequenceRuleSet {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.class_seq_rules)).unwrap()).write_into(writer);
        self.class_seq_rules.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ClassSequenceRuleSet")
    }
}

impl Validate for ClassSequenceRuleSet {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ClassSequenceRuleSet", |ctx| {
            ctx.in_field("class_seq_rules", |ctx| {
                if self.class_seq_rules.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.class_seq_rules.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ClassSequenceRuleSet<'a>> for ClassSequenceRuleSet {
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ClassSequenceRuleSet<'a>,
        _: FontData,
    ) -> Self {
        ClassSequenceRuleSet {
            class_seq_rules: obj.class_seq_rules().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ClassSequenceRuleSet<'a>>
    for ClassSequenceRuleSet
{
}

impl<'a> FontRead<'a> for ClassSequenceRuleSet {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ClassSequenceRuleSet as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [SequenceContextFormat2]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ClassSequenceRule {
    /// Sequence of classes to be matched to the input glyph sequence,
    /// beginning with the second glyph position
    pub input_sequence: Vec<u16>,
    /// Array of SequenceLookupRecords
    pub seq_lookup_records: Vec<SequenceLookupRecord>,
}

impl ClassSequenceRule {
    /// Construct a new `ClassSequenceRule`
    pub fn new(input_sequence: Vec<u16>, seq_lookup_records: Vec<SequenceLookupRecord>) -> Self {
        Self {
            input_sequence,
            seq_lookup_records,
        }
    }
}

impl FontWrite for ClassSequenceRule {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
        self.input_sequence.write_into(writer);
        self.seq_lookup_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ClassSequenceRule")
    }
}

impl Validate for ClassSequenceRule {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ClassSequenceRule", |ctx| {
            ctx.in_field("seq_lookup_records", |ctx| {
                if self.seq_lookup_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_lookup_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ClassSequenceRule<'a>> for ClassSequenceRule {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ClassSequenceRule<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        ClassSequenceRule {
            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ClassSequenceRule<'a>> for ClassSequenceRule {}

impl<'a> FontRead<'a> for ClassSequenceRule {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ClassSequenceRule as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SequenceContextFormat3 {
    /// Array of offsets to Coverage tables, from beginning of
    /// SequenceContextFormat3 subtable
    pub coverages: Vec<OffsetMarker<CoverageTable>>,
    /// Array of SequenceLookupRecords
    pub seq_lookup_records: Vec<SequenceLookupRecord>,
}

impl SequenceContextFormat3 {
    /// Construct a new `SequenceContextFormat3`
    pub fn new(
        coverages: Vec<CoverageTable>,
        seq_lookup_records: Vec<SequenceLookupRecord>,
    ) -> Self {
        Self {
            coverages: coverages.into_iter().map(Into::into).collect(),
            seq_lookup_records,
        }
    }
}

impl FontWrite for SequenceContextFormat3 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (3 as u16).write_into(writer);
        (u16::try_from(array_len(&self.coverages)).unwrap()).write_into(writer);
        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
        self.coverages.write_into(writer);
        self.seq_lookup_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("SequenceContextFormat3")
    }
}

impl Validate for SequenceContextFormat3 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("SequenceContextFormat3", |ctx| {
            ctx.in_field("coverages", |ctx| {
                if self.coverages.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.coverages.validate_impl(ctx);
            });
            ctx.in_field("seq_lookup_records", |ctx| {
                if self.seq_lookup_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_lookup_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::SequenceContextFormat3<'a>>
    for SequenceContextFormat3
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::SequenceContextFormat3<'a>,
        _: FontData,
    ) -> Self {
        let offset_data = obj.offset_data();
        SequenceContextFormat3 {
            coverages: obj.coverages().to_owned_table(),
            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::SequenceContextFormat3<'a>>
    for SequenceContextFormat3
{
}

impl<'a> FontRead<'a> for SequenceContextFormat3 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::SequenceContextFormat3 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SequenceContext {
    Format1(SequenceContextFormat1),
    Format2(SequenceContextFormat2),
    Format3(SequenceContextFormat3),
}

impl SequenceContext {
    /// Construct a new `SequenceContextFormat1` subtable
    pub fn format_1(coverage: CoverageTable, seq_rule_sets: Vec<Option<SequenceRuleSet>>) -> Self {
        Self::Format1(SequenceContextFormat1::new(coverage, seq_rule_sets))
    }

    /// Construct a new `SequenceContextFormat2` subtable
    pub fn format_2(
        coverage: CoverageTable,
        class_def: ClassDef,
        class_seq_rule_sets: Vec<Option<ClassSequenceRuleSet>>,
    ) -> Self {
        Self::Format2(SequenceContextFormat2::new(
            coverage,
            class_def,
            class_seq_rule_sets,
        ))
    }

    /// Construct a new `SequenceContextFormat3` subtable
    pub fn format_3(
        coverages: Vec<CoverageTable>,
        seq_lookup_records: Vec<SequenceLookupRecord>,
    ) -> Self {
        Self::Format3(SequenceContextFormat3::new(coverages, seq_lookup_records))
    }
}

impl Default for SequenceContext {
    fn default() -> Self {
        Self::Format1(Default::default())
    }
}

impl FontWrite for SequenceContext {
    fn write_into(&self, writer: &mut TableWriter) {
        match self {
            Self::Format1(item) => item.write_into(writer),
            Self::Format2(item) => item.write_into(writer),
            Self::Format3(item) => item.write_into(writer),
        }
    }
    fn table_type(&self) -> TableType {
        match self {
            Self::Format1(item) => item.table_type(),
            Self::Format2(item) => item.table_type(),
            Self::Format3(item) => item.table_type(),
        }
    }
}

impl Validate for SequenceContext {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        match self {
            Self::Format1(item) => item.validate_impl(ctx),
            Self::Format2(item) => item.validate_impl(ctx),
            Self::Format3(item) => item.validate_impl(ctx),
        }
    }
}

impl FromObjRef<read_fonts::tables::layout::SequenceContext<'_>> for SequenceContext {
    fn from_obj_ref(obj: &read_fonts::tables::layout::SequenceContext, _: FontData) -> Self {
        use read_fonts::tables::layout::SequenceContext as ObjRefType;
        match obj {
            ObjRefType::Format1(item) => SequenceContext::Format1(item.to_owned_table()),
            ObjRefType::Format2(item) => SequenceContext::Format2(item.to_owned_table()),
            ObjRefType::Format3(item) => SequenceContext::Format3(item.to_owned_table()),
        }
    }
}

impl FromTableRef<read_fonts::tables::layout::SequenceContext<'_>> for SequenceContext {}

impl<'a> FontRead<'a> for SequenceContext {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::SequenceContext as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

impl From<SequenceContextFormat1> for SequenceContext {
    fn from(src: SequenceContextFormat1) -> SequenceContext {
        SequenceContext::Format1(src)
    }
}

impl From<SequenceContextFormat2> for SequenceContext {
    fn from(src: SequenceContextFormat2) -> SequenceContext {
        SequenceContext::Format2(src)
    }
}

impl From<SequenceContextFormat3> for SequenceContext {
    fn from(src: SequenceContextFormat3) -> SequenceContext {
        SequenceContext::Format3(src)
    }
}

/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChainedSequenceContextFormat1 {
    /// Offset to Coverage table, from beginning of
    /// ChainSequenceContextFormat1 table
    pub coverage: OffsetMarker<CoverageTable>,
    /// Array of offsets to ChainedSeqRuleSet tables, from beginning of
    /// ChainedSequenceContextFormat1 table (may be NULL)
    pub chained_seq_rule_sets: Vec<NullableOffsetMarker<ChainedSequenceRuleSet>>,
}

impl ChainedSequenceContextFormat1 {
    /// Construct a new `ChainedSequenceContextFormat1`
    pub fn new(
        coverage: CoverageTable,
        chained_seq_rule_sets: Vec<Option<ChainedSequenceRuleSet>>,
    ) -> Self {
        Self {
            coverage: coverage.into(),
            chained_seq_rule_sets: chained_seq_rule_sets.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for ChainedSequenceContextFormat1 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (1 as u16).write_into(writer);
        self.coverage.write_into(writer);
        (u16::try_from(array_len(&self.chained_seq_rule_sets)).unwrap()).write_into(writer);
        self.chained_seq_rule_sets.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ChainedSequenceContextFormat1")
    }
}

impl Validate for ChainedSequenceContextFormat1 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ChainedSequenceContextFormat1", |ctx| {
            ctx.in_field("coverage", |ctx| {
                self.coverage.validate_impl(ctx);
            });
            ctx.in_field("chained_seq_rule_sets", |ctx| {
                if self.chained_seq_rule_sets.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.chained_seq_rule_sets.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceContextFormat1<'a>>
    for ChainedSequenceContextFormat1
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ChainedSequenceContextFormat1<'a>,
        _: FontData,
    ) -> Self {
        ChainedSequenceContextFormat1 {
            coverage: obj.coverage().to_owned_table(),
            chained_seq_rule_sets: obj.chained_seq_rule_sets().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceContextFormat1<'a>>
    for ChainedSequenceContextFormat1
{
}

impl<'a> FontRead<'a> for ChainedSequenceContextFormat1 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedSequenceContextFormat1 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [ChainedSequenceContextFormat1]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChainedSequenceRuleSet {
    /// Array of offsets to ChainedSequenceRule tables, from beginning
    /// of ChainedSequenceRuleSet table
    pub chained_seq_rules: Vec<OffsetMarker<ChainedSequenceRule>>,
}

impl ChainedSequenceRuleSet {
    /// Construct a new `ChainedSequenceRuleSet`
    pub fn new(chained_seq_rules: Vec<ChainedSequenceRule>) -> Self {
        Self {
            chained_seq_rules: chained_seq_rules.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for ChainedSequenceRuleSet {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.chained_seq_rules)).unwrap()).write_into(writer);
        self.chained_seq_rules.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ChainedSequenceRuleSet")
    }
}

impl Validate for ChainedSequenceRuleSet {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ChainedSequenceRuleSet", |ctx| {
            ctx.in_field("chained_seq_rules", |ctx| {
                if self.chained_seq_rules.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.chained_seq_rules.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceRuleSet<'a>>
    for ChainedSequenceRuleSet
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ChainedSequenceRuleSet<'a>,
        _: FontData,
    ) -> Self {
        ChainedSequenceRuleSet {
            chained_seq_rules: obj.chained_seq_rules().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceRuleSet<'a>>
    for ChainedSequenceRuleSet
{
}

impl<'a> FontRead<'a> for ChainedSequenceRuleSet {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedSequenceRuleSet as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [ChainedSequenceContextFormat1]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChainedSequenceRule {
    /// Array of backtrack glyph IDs
    pub backtrack_sequence: Vec<GlyphId16>,
    /// Array of input glyph IDs—start with second glyph
    pub input_sequence: Vec<GlyphId16>,
    /// Array of lookahead glyph IDs
    pub lookahead_sequence: Vec<GlyphId16>,
    /// Array of SequenceLookupRecords
    pub seq_lookup_records: Vec<SequenceLookupRecord>,
}

impl ChainedSequenceRule {
    /// Construct a new `ChainedSequenceRule`
    pub fn new(
        backtrack_sequence: Vec<GlyphId16>,
        input_sequence: Vec<GlyphId16>,
        lookahead_sequence: Vec<GlyphId16>,
        seq_lookup_records: Vec<SequenceLookupRecord>,
    ) -> Self {
        Self {
            backtrack_sequence,
            input_sequence,
            lookahead_sequence,
            seq_lookup_records,
        }
    }
}

impl FontWrite for ChainedSequenceRule {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.backtrack_sequence)).unwrap()).write_into(writer);
        self.backtrack_sequence.write_into(writer);
        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
        self.input_sequence.write_into(writer);
        (u16::try_from(array_len(&self.lookahead_sequence)).unwrap()).write_into(writer);
        self.lookahead_sequence.write_into(writer);
        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
        self.seq_lookup_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ChainedSequenceRule")
    }
}

impl Validate for ChainedSequenceRule {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ChainedSequenceRule", |ctx| {
            ctx.in_field("backtrack_sequence", |ctx| {
                if self.backtrack_sequence.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
            ctx.in_field("lookahead_sequence", |ctx| {
                if self.lookahead_sequence.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
            ctx.in_field("seq_lookup_records", |ctx| {
                if self.seq_lookup_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_lookup_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceRule<'a>> for ChainedSequenceRule {
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ChainedSequenceRule<'a>,
        _: FontData,
    ) -> Self {
        let offset_data = obj.offset_data();
        ChainedSequenceRule {
            backtrack_sequence: obj.backtrack_sequence().to_owned_obj(offset_data),
            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
            lookahead_sequence: obj.lookahead_sequence().to_owned_obj(offset_data),
            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceRule<'a>> for ChainedSequenceRule {}

impl<'a> FontRead<'a> for ChainedSequenceRule {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedSequenceRule as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [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(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChainedSequenceContextFormat2 {
    /// Offset to Coverage table, from beginning of
    /// ChainedSequenceContextFormat2 table
    pub coverage: OffsetMarker<CoverageTable>,
    /// Offset to ClassDef table containing backtrack sequence context,
    /// from beginning of ChainedSequenceContextFormat2 table
    pub backtrack_class_def: OffsetMarker<ClassDef>,
    /// Offset to ClassDef table containing input sequence context,
    /// from beginning of ChainedSequenceContextFormat2 table
    pub input_class_def: OffsetMarker<ClassDef>,
    /// Offset to ClassDef table containing lookahead sequence context,
    /// from beginning of ChainedSequenceContextFormat2 table
    pub lookahead_class_def: OffsetMarker<ClassDef>,
    /// Array of offsets to ChainedClassSequenceRuleSet tables, from
    /// beginning of ChainedSequenceContextFormat2 table (may be NULL)
    pub chained_class_seq_rule_sets: Vec<NullableOffsetMarker<ChainedClassSequenceRuleSet>>,
}

impl ChainedSequenceContextFormat2 {
    /// Construct a new `ChainedSequenceContextFormat2`
    pub fn new(
        coverage: CoverageTable,
        backtrack_class_def: ClassDef,
        input_class_def: ClassDef,
        lookahead_class_def: ClassDef,
        chained_class_seq_rule_sets: Vec<Option<ChainedClassSequenceRuleSet>>,
    ) -> Self {
        Self {
            coverage: coverage.into(),
            backtrack_class_def: backtrack_class_def.into(),
            input_class_def: input_class_def.into(),
            lookahead_class_def: lookahead_class_def.into(),
            chained_class_seq_rule_sets: chained_class_seq_rule_sets
                .into_iter()
                .map(Into::into)
                .collect(),
        }
    }
}

impl FontWrite for ChainedSequenceContextFormat2 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (2 as u16).write_into(writer);
        self.coverage.write_into(writer);
        self.backtrack_class_def.write_into(writer);
        self.input_class_def.write_into(writer);
        self.lookahead_class_def.write_into(writer);
        (u16::try_from(array_len(&self.chained_class_seq_rule_sets)).unwrap()).write_into(writer);
        self.chained_class_seq_rule_sets.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ChainedSequenceContextFormat2")
    }
}

impl Validate for ChainedSequenceContextFormat2 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ChainedSequenceContextFormat2", |ctx| {
            ctx.in_field("coverage", |ctx| {
                self.coverage.validate_impl(ctx);
            });
            ctx.in_field("backtrack_class_def", |ctx| {
                self.backtrack_class_def.validate_impl(ctx);
            });
            ctx.in_field("input_class_def", |ctx| {
                self.input_class_def.validate_impl(ctx);
            });
            ctx.in_field("lookahead_class_def", |ctx| {
                self.lookahead_class_def.validate_impl(ctx);
            });
            ctx.in_field("chained_class_seq_rule_sets", |ctx| {
                if self.chained_class_seq_rule_sets.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.chained_class_seq_rule_sets.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceContextFormat2<'a>>
    for ChainedSequenceContextFormat2
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ChainedSequenceContextFormat2<'a>,
        _: FontData,
    ) -> Self {
        ChainedSequenceContextFormat2 {
            coverage: obj.coverage().to_owned_table(),
            backtrack_class_def: obj.backtrack_class_def().to_owned_table(),
            input_class_def: obj.input_class_def().to_owned_table(),
            lookahead_class_def: obj.lookahead_class_def().to_owned_table(),
            chained_class_seq_rule_sets: obj.chained_class_seq_rule_sets().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceContextFormat2<'a>>
    for ChainedSequenceContextFormat2
{
}

impl<'a> FontRead<'a> for ChainedSequenceContextFormat2 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedSequenceContextFormat2 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [ChainedSequenceContextFormat2]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChainedClassSequenceRuleSet {
    /// Array of offsets to ChainedClassSequenceRule tables, from
    /// beginning of ChainedClassSequenceRuleSet
    pub chained_class_seq_rules: Vec<OffsetMarker<ChainedClassSequenceRule>>,
}

impl ChainedClassSequenceRuleSet {
    /// Construct a new `ChainedClassSequenceRuleSet`
    pub fn new(chained_class_seq_rules: Vec<ChainedClassSequenceRule>) -> Self {
        Self {
            chained_class_seq_rules: chained_class_seq_rules
                .into_iter()
                .map(Into::into)
                .collect(),
        }
    }
}

impl FontWrite for ChainedClassSequenceRuleSet {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.chained_class_seq_rules)).unwrap()).write_into(writer);
        self.chained_class_seq_rules.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ChainedClassSequenceRuleSet")
    }
}

impl Validate for ChainedClassSequenceRuleSet {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ChainedClassSequenceRuleSet", |ctx| {
            ctx.in_field("chained_class_seq_rules", |ctx| {
                if self.chained_class_seq_rules.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.chained_class_seq_rules.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ChainedClassSequenceRuleSet<'a>>
    for ChainedClassSequenceRuleSet
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ChainedClassSequenceRuleSet<'a>,
        _: FontData,
    ) -> Self {
        ChainedClassSequenceRuleSet {
            chained_class_seq_rules: obj.chained_class_seq_rules().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ChainedClassSequenceRuleSet<'a>>
    for ChainedClassSequenceRuleSet
{
}

impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedClassSequenceRuleSet as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [ChainedSequenceContextFormat2]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChainedClassSequenceRule {
    /// Array of backtrack-sequence classes
    pub backtrack_sequence: Vec<u16>,
    /// Array of input sequence classes, beginning with the second
    /// glyph position
    pub input_sequence: Vec<u16>,
    /// Array of lookahead-sequence classes
    pub lookahead_sequence: Vec<u16>,
    /// Array of SequenceLookupRecords
    pub seq_lookup_records: Vec<SequenceLookupRecord>,
}

impl ChainedClassSequenceRule {
    /// Construct a new `ChainedClassSequenceRule`
    pub fn new(
        backtrack_sequence: Vec<u16>,
        input_sequence: Vec<u16>,
        lookahead_sequence: Vec<u16>,
        seq_lookup_records: Vec<SequenceLookupRecord>,
    ) -> Self {
        Self {
            backtrack_sequence,
            input_sequence,
            lookahead_sequence,
            seq_lookup_records,
        }
    }
}

impl FontWrite for ChainedClassSequenceRule {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.backtrack_sequence)).unwrap()).write_into(writer);
        self.backtrack_sequence.write_into(writer);
        (u16::try_from(plus_one(&self.input_sequence.len())).unwrap()).write_into(writer);
        self.input_sequence.write_into(writer);
        (u16::try_from(array_len(&self.lookahead_sequence)).unwrap()).write_into(writer);
        self.lookahead_sequence.write_into(writer);
        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
        self.seq_lookup_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ChainedClassSequenceRule")
    }
}

impl Validate for ChainedClassSequenceRule {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ChainedClassSequenceRule", |ctx| {
            ctx.in_field("backtrack_sequence", |ctx| {
                if self.backtrack_sequence.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
            ctx.in_field("lookahead_sequence", |ctx| {
                if self.lookahead_sequence.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
            ctx.in_field("seq_lookup_records", |ctx| {
                if self.seq_lookup_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_lookup_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ChainedClassSequenceRule<'a>>
    for ChainedClassSequenceRule
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ChainedClassSequenceRule<'a>,
        _: FontData,
    ) -> Self {
        let offset_data = obj.offset_data();
        ChainedClassSequenceRule {
            backtrack_sequence: obj.backtrack_sequence().to_owned_obj(offset_data),
            input_sequence: obj.input_sequence().to_owned_obj(offset_data),
            lookahead_sequence: obj.lookahead_sequence().to_owned_obj(offset_data),
            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ChainedClassSequenceRule<'a>>
    for ChainedClassSequenceRule
{
}

impl<'a> FontRead<'a> for ChainedClassSequenceRule {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedClassSequenceRule as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [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(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ChainedSequenceContextFormat3 {
    /// Array of offsets to coverage tables for the backtrack sequence
    pub backtrack_coverages: Vec<OffsetMarker<CoverageTable>>,
    /// Array of offsets to coverage tables for the input sequence
    pub input_coverages: Vec<OffsetMarker<CoverageTable>>,
    /// Array of offsets to coverage tables for the lookahead sequence
    pub lookahead_coverages: Vec<OffsetMarker<CoverageTable>>,
    /// Array of SequenceLookupRecords
    pub seq_lookup_records: Vec<SequenceLookupRecord>,
}

impl ChainedSequenceContextFormat3 {
    /// Construct a new `ChainedSequenceContextFormat3`
    pub fn new(
        backtrack_coverages: Vec<CoverageTable>,
        input_coverages: Vec<CoverageTable>,
        lookahead_coverages: Vec<CoverageTable>,
        seq_lookup_records: Vec<SequenceLookupRecord>,
    ) -> Self {
        Self {
            backtrack_coverages: backtrack_coverages.into_iter().map(Into::into).collect(),
            input_coverages: input_coverages.into_iter().map(Into::into).collect(),
            lookahead_coverages: lookahead_coverages.into_iter().map(Into::into).collect(),
            seq_lookup_records,
        }
    }
}

impl FontWrite for ChainedSequenceContextFormat3 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (3 as u16).write_into(writer);
        (u16::try_from(array_len(&self.backtrack_coverages)).unwrap()).write_into(writer);
        self.backtrack_coverages.write_into(writer);
        (u16::try_from(array_len(&self.input_coverages)).unwrap()).write_into(writer);
        self.input_coverages.write_into(writer);
        (u16::try_from(array_len(&self.lookahead_coverages)).unwrap()).write_into(writer);
        self.lookahead_coverages.write_into(writer);
        (u16::try_from(array_len(&self.seq_lookup_records)).unwrap()).write_into(writer);
        self.seq_lookup_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ChainedSequenceContextFormat3")
    }
}

impl Validate for ChainedSequenceContextFormat3 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ChainedSequenceContextFormat3", |ctx| {
            ctx.in_field("backtrack_coverages", |ctx| {
                if self.backtrack_coverages.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.backtrack_coverages.validate_impl(ctx);
            });
            ctx.in_field("input_coverages", |ctx| {
                if self.input_coverages.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.input_coverages.validate_impl(ctx);
            });
            ctx.in_field("lookahead_coverages", |ctx| {
                if self.lookahead_coverages.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.lookahead_coverages.validate_impl(ctx);
            });
            ctx.in_field("seq_lookup_records", |ctx| {
                if self.seq_lookup_records.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.seq_lookup_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ChainedSequenceContextFormat3<'a>>
    for ChainedSequenceContextFormat3
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::ChainedSequenceContextFormat3<'a>,
        _: FontData,
    ) -> Self {
        let offset_data = obj.offset_data();
        ChainedSequenceContextFormat3 {
            backtrack_coverages: obj.backtrack_coverages().to_owned_table(),
            input_coverages: obj.input_coverages().to_owned_table(),
            lookahead_coverages: obj.lookahead_coverages().to_owned_table(),
            seq_lookup_records: obj.seq_lookup_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ChainedSequenceContextFormat3<'a>>
    for ChainedSequenceContextFormat3
{
}

impl<'a> FontRead<'a> for ChainedSequenceContextFormat3 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedSequenceContextFormat3 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ChainedSequenceContext {
    Format1(ChainedSequenceContextFormat1),
    Format2(ChainedSequenceContextFormat2),
    Format3(ChainedSequenceContextFormat3),
}

impl ChainedSequenceContext {
    /// Construct a new `ChainedSequenceContextFormat1` subtable
    pub fn format_1(
        coverage: CoverageTable,
        chained_seq_rule_sets: Vec<Option<ChainedSequenceRuleSet>>,
    ) -> Self {
        Self::Format1(ChainedSequenceContextFormat1::new(
            coverage,
            chained_seq_rule_sets,
        ))
    }

    /// Construct a new `ChainedSequenceContextFormat2` subtable
    pub fn format_2(
        coverage: CoverageTable,
        backtrack_class_def: ClassDef,
        input_class_def: ClassDef,
        lookahead_class_def: ClassDef,
        chained_class_seq_rule_sets: Vec<Option<ChainedClassSequenceRuleSet>>,
    ) -> Self {
        Self::Format2(ChainedSequenceContextFormat2::new(
            coverage,
            backtrack_class_def,
            input_class_def,
            lookahead_class_def,
            chained_class_seq_rule_sets,
        ))
    }

    /// Construct a new `ChainedSequenceContextFormat3` subtable
    pub fn format_3(
        backtrack_coverages: Vec<CoverageTable>,
        input_coverages: Vec<CoverageTable>,
        lookahead_coverages: Vec<CoverageTable>,
        seq_lookup_records: Vec<SequenceLookupRecord>,
    ) -> Self {
        Self::Format3(ChainedSequenceContextFormat3::new(
            backtrack_coverages,
            input_coverages,
            lookahead_coverages,
            seq_lookup_records,
        ))
    }
}

impl Default for ChainedSequenceContext {
    fn default() -> Self {
        Self::Format1(Default::default())
    }
}

impl FontWrite for ChainedSequenceContext {
    fn write_into(&self, writer: &mut TableWriter) {
        match self {
            Self::Format1(item) => item.write_into(writer),
            Self::Format2(item) => item.write_into(writer),
            Self::Format3(item) => item.write_into(writer),
        }
    }
    fn table_type(&self) -> TableType {
        match self {
            Self::Format1(item) => item.table_type(),
            Self::Format2(item) => item.table_type(),
            Self::Format3(item) => item.table_type(),
        }
    }
}

impl Validate for ChainedSequenceContext {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        match self {
            Self::Format1(item) => item.validate_impl(ctx),
            Self::Format2(item) => item.validate_impl(ctx),
            Self::Format3(item) => item.validate_impl(ctx),
        }
    }
}

impl FromObjRef<read_fonts::tables::layout::ChainedSequenceContext<'_>> for ChainedSequenceContext {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ChainedSequenceContext, _: FontData) -> Self {
        use read_fonts::tables::layout::ChainedSequenceContext as ObjRefType;
        match obj {
            ObjRefType::Format1(item) => ChainedSequenceContext::Format1(item.to_owned_table()),
            ObjRefType::Format2(item) => ChainedSequenceContext::Format2(item.to_owned_table()),
            ObjRefType::Format3(item) => ChainedSequenceContext::Format3(item.to_owned_table()),
        }
    }
}

impl FromTableRef<read_fonts::tables::layout::ChainedSequenceContext<'_>>
    for ChainedSequenceContext
{
}

impl<'a> FontRead<'a> for ChainedSequenceContext {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ChainedSequenceContext as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

impl From<ChainedSequenceContextFormat1> for ChainedSequenceContext {
    fn from(src: ChainedSequenceContextFormat1) -> ChainedSequenceContext {
        ChainedSequenceContext::Format1(src)
    }
}

impl From<ChainedSequenceContextFormat2> for ChainedSequenceContext {
    fn from(src: ChainedSequenceContextFormat2) -> ChainedSequenceContext {
        ChainedSequenceContext::Format2(src)
    }
}

impl From<ChainedSequenceContextFormat3> for ChainedSequenceContext {
    fn from(src: ChainedSequenceContextFormat3) -> ChainedSequenceContext {
        ChainedSequenceContext::Format3(src)
    }
}

impl FontWrite for DeltaFormat {
    fn write_into(&self, writer: &mut TableWriter) {
        let val = *self as u16;
        writer.write_slice(&val.to_be_bytes())
    }
}

/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Device {
    /// Smallest size to correct, in ppem
    pub start_size: u16,
    /// Largest size to correct, in ppem
    pub end_size: u16,
    /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003
    pub delta_format: DeltaFormat,
    /// Array of compressed data
    pub delta_value: Vec<u16>,
}

impl FontWrite for Device {
    fn write_into(&self, writer: &mut TableWriter) {
        self.start_size.write_into(writer);
        self.end_size.write_into(writer);
        self.delta_format.write_into(writer);
        self.delta_value.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("Device")
    }
}

impl Validate for Device {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl<'a> FromObjRef<read_fonts::tables::layout::Device<'a>> for Device {
    fn from_obj_ref(obj: &read_fonts::tables::layout::Device<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        Device {
            start_size: obj.start_size(),
            end_size: obj.end_size(),
            delta_format: obj.delta_format(),
            delta_value: obj.delta_value().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::Device<'a>> for Device {}

impl<'a> FontRead<'a> for Device {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::Device as FontRead>::read(data).map(|x| x.to_owned_table())
    }
}

/// Variation index table
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct VariationIndex {
    /// A delta-set outer index — used to select an item variation
    /// data subtable within the item variation store.
    pub delta_set_outer_index: u16,
    /// A delta-set inner index — used to select a delta-set row
    /// within an item variation data subtable.
    pub delta_set_inner_index: u16,
}

impl VariationIndex {
    /// Construct a new `VariationIndex`
    pub fn new(delta_set_outer_index: u16, delta_set_inner_index: u16) -> Self {
        Self {
            delta_set_outer_index,
            delta_set_inner_index,
        }
    }
}

impl FontWrite for VariationIndex {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        self.delta_set_outer_index.write_into(writer);
        self.delta_set_inner_index.write_into(writer);
        (DeltaFormat::VariationIndex as DeltaFormat).write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("VariationIndex")
    }
}

impl Validate for VariationIndex {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl<'a> FromObjRef<read_fonts::tables::layout::VariationIndex<'a>> for VariationIndex {
    fn from_obj_ref(obj: &read_fonts::tables::layout::VariationIndex<'a>, _: FontData) -> Self {
        VariationIndex {
            delta_set_outer_index: obj.delta_set_outer_index(),
            delta_set_inner_index: obj.delta_set_inner_index(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::VariationIndex<'a>> for VariationIndex {}

impl<'a> FontRead<'a> for VariationIndex {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::VariationIndex as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// A type representing a temporary identifier for a set of variation deltas.
///
/// The final indices used in the VariationIndex table are not known until
/// all deltas have been collected. This variant is used to assign a
/// temporary identifier during compilation.
///
/// This type is not part of the spec and will never appear in an actual font file.
/// It is intended to serve as a sentinel value, and will panic when written,
/// ensuring that all VariationIndex tables have been correctly mapped before
/// the font is compiled.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PendingVariationIndex {
    /// A unique identifier for a given set of deltas.
    pub delta_set_id: u32,
}

impl PendingVariationIndex {
    /// Construct a new `PendingVariationIndex`
    pub fn new(delta_set_id: u32) -> Self {
        Self { delta_set_id }
    }
}

impl Validate for PendingVariationIndex {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

/// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum DeviceOrVariationIndex {
    Device(Device),
    VariationIndex(VariationIndex),
    PendingVariationIndex(PendingVariationIndex),
}

impl DeviceOrVariationIndex {
    /// Construct a new `VariationIndex` subtable
    pub fn variation_index(delta_set_outer_index: u16, delta_set_inner_index: u16) -> Self {
        Self::VariationIndex(VariationIndex::new(
            delta_set_outer_index,
            delta_set_inner_index,
        ))
    }

    /// Construct a new `PendingVariationIndex` subtable
    pub fn pending_variation_index(delta_set_id: u32) -> Self {
        Self::PendingVariationIndex(PendingVariationIndex::new(delta_set_id))
    }
}

impl Default for DeviceOrVariationIndex {
    fn default() -> Self {
        Self::Device(Default::default())
    }
}

impl FontWrite for DeviceOrVariationIndex {
    fn write_into(&self, writer: &mut TableWriter) {
        match self {
            Self::Device(item) => item.write_into(writer),
            Self::VariationIndex(item) => item.write_into(writer),
            Self::PendingVariationIndex(item) => item.write_into(writer),
        }
    }
    fn table_type(&self) -> TableType {
        match self {
            Self::Device(item) => item.table_type(),
            Self::VariationIndex(item) => item.table_type(),
            Self::PendingVariationIndex(item) => item.table_type(),
        }
    }
}

impl Validate for DeviceOrVariationIndex {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        match self {
            Self::Device(item) => item.validate_impl(ctx),
            Self::VariationIndex(item) => item.validate_impl(ctx),
            Self::PendingVariationIndex(item) => item.validate_impl(ctx),
        }
    }
}

impl FromObjRef<read_fonts::tables::layout::DeviceOrVariationIndex<'_>> for DeviceOrVariationIndex {
    fn from_obj_ref(obj: &read_fonts::tables::layout::DeviceOrVariationIndex, _: FontData) -> Self {
        use read_fonts::tables::layout::DeviceOrVariationIndex as ObjRefType;
        match obj {
            ObjRefType::Device(item) => DeviceOrVariationIndex::Device(item.to_owned_table()),
            ObjRefType::VariationIndex(item) => {
                DeviceOrVariationIndex::VariationIndex(item.to_owned_table())
            }
        }
    }
}

impl FromTableRef<read_fonts::tables::layout::DeviceOrVariationIndex<'_>>
    for DeviceOrVariationIndex
{
}

impl<'a> FontRead<'a> for DeviceOrVariationIndex {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::DeviceOrVariationIndex as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

impl From<Device> for DeviceOrVariationIndex {
    fn from(src: Device) -> DeviceOrVariationIndex {
        DeviceOrVariationIndex::Device(src)
    }
}

impl From<VariationIndex> for DeviceOrVariationIndex {
    fn from(src: VariationIndex) -> DeviceOrVariationIndex {
        DeviceOrVariationIndex::VariationIndex(src)
    }
}

impl From<PendingVariationIndex> for DeviceOrVariationIndex {
    fn from(src: PendingVariationIndex) -> DeviceOrVariationIndex {
        DeviceOrVariationIndex::PendingVariationIndex(src)
    }
}

/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FeatureVariations {
    /// Array of feature variation records.
    pub feature_variation_records: Vec<FeatureVariationRecord>,
}

impl FeatureVariations {
    /// Construct a new `FeatureVariations`
    pub fn new(feature_variation_records: Vec<FeatureVariationRecord>) -> Self {
        Self {
            feature_variation_records,
        }
    }
}

impl FontWrite for FeatureVariations {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (MajorMinor::VERSION_1_0 as MajorMinor).write_into(writer);
        (u32::try_from(array_len(&self.feature_variation_records)).unwrap()).write_into(writer);
        self.feature_variation_records.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("FeatureVariations")
    }
}

impl Validate for FeatureVariations {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("FeatureVariations", |ctx| {
            ctx.in_field("feature_variation_records", |ctx| {
                if self.feature_variation_records.len() > (u32::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.feature_variation_records.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::FeatureVariations<'a>> for FeatureVariations {
    fn from_obj_ref(obj: &read_fonts::tables::layout::FeatureVariations<'a>, _: FontData) -> Self {
        let offset_data = obj.offset_data();
        FeatureVariations {
            feature_variation_records: obj.feature_variation_records().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::FeatureVariations<'a>> for FeatureVariations {}

impl<'a> FontRead<'a> for FeatureVariations {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::FeatureVariations as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Part of [FeatureVariations]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FeatureVariationRecord {
    /// Offset to a condition set table, from beginning of
    /// FeatureVariations table.
    pub condition_set: NullableOffsetMarker<ConditionSet, WIDTH_32>,
    /// Offset to a feature table substitution table, from beginning of
    /// the FeatureVariations table.
    pub feature_table_substitution: NullableOffsetMarker<FeatureTableSubstitution, WIDTH_32>,
}

impl FeatureVariationRecord {
    /// Construct a new `FeatureVariationRecord`
    pub fn new(
        condition_set: Option<ConditionSet>,
        feature_table_substitution: Option<FeatureTableSubstitution>,
    ) -> Self {
        Self {
            condition_set: condition_set.into(),
            feature_table_substitution: feature_table_substitution.into(),
        }
    }
}

impl FontWrite for FeatureVariationRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.condition_set.write_into(writer);
        self.feature_table_substitution.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("FeatureVariationRecord")
    }
}

impl Validate for FeatureVariationRecord {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("FeatureVariationRecord", |ctx| {
            ctx.in_field("condition_set", |ctx| {
                self.condition_set.validate_impl(ctx);
            });
            ctx.in_field("feature_table_substitution", |ctx| {
                self.feature_table_substitution.validate_impl(ctx);
            });
        })
    }
}

impl FromObjRef<read_fonts::tables::layout::FeatureVariationRecord> for FeatureVariationRecord {
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::FeatureVariationRecord,
        offset_data: FontData,
    ) -> Self {
        FeatureVariationRecord {
            condition_set: obj.condition_set(offset_data).to_owned_table(),
            feature_table_substitution: obj
                .feature_table_substitution(offset_data)
                .to_owned_table(),
        }
    }
}

/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConditionSet {
    /// Array of offsets to condition tables, from beginning of the
    /// ConditionSet table.
    pub conditions: Vec<OffsetMarker<Condition, WIDTH_32>>,
}

impl ConditionSet {
    /// Construct a new `ConditionSet`
    pub fn new(conditions: Vec<Condition>) -> Self {
        Self {
            conditions: conditions.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for ConditionSet {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (u16::try_from(array_len(&self.conditions)).unwrap()).write_into(writer);
        self.conditions.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ConditionSet")
    }
}

impl Validate for ConditionSet {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ConditionSet", |ctx| {
            ctx.in_field("conditions", |ctx| {
                if self.conditions.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.conditions.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ConditionSet<'a>> for ConditionSet {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionSet<'a>, _: FontData) -> Self {
        ConditionSet {
            conditions: obj.conditions().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ConditionSet<'a>> for ConditionSet {}

impl<'a> FontRead<'a> for ConditionSet {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ConditionSet as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [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, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Condition {
    Format1AxisRange(ConditionFormat1),
    Format2VariableValue(ConditionFormat2),
    Format3And(ConditionFormat3),
    Format4Or(ConditionFormat4),
    Format5Negate(ConditionFormat5),
}

impl Condition {
    /// Construct a new `ConditionFormat1` subtable
    pub fn format_1_axis_range(
        axis_index: u16,
        filter_range_min_value: F2Dot14,
        filter_range_max_value: F2Dot14,
    ) -> Self {
        Self::Format1AxisRange(ConditionFormat1::new(
            axis_index,
            filter_range_min_value,
            filter_range_max_value,
        ))
    }

    /// Construct a new `ConditionFormat2` subtable
    pub fn format_2_variable_value(default_value: i16, var_index: u32) -> Self {
        Self::Format2VariableValue(ConditionFormat2::new(default_value, var_index))
    }

    /// Construct a new `ConditionFormat3` subtable
    pub fn format_3_and(condition_count: u8, conditions: Vec<Condition>) -> Self {
        Self::Format3And(ConditionFormat3::new(condition_count, conditions))
    }

    /// Construct a new `ConditionFormat4` subtable
    pub fn format_4_or(condition_count: u8, conditions: Vec<Condition>) -> Self {
        Self::Format4Or(ConditionFormat4::new(condition_count, conditions))
    }

    /// Construct a new `ConditionFormat5` subtable
    pub fn format_5_negate(condition: Condition) -> Self {
        Self::Format5Negate(ConditionFormat5::new(condition))
    }
}

impl Default for Condition {
    fn default() -> Self {
        Self::Format1AxisRange(Default::default())
    }
}

impl FontWrite for Condition {
    fn write_into(&self, writer: &mut TableWriter) {
        match self {
            Self::Format1AxisRange(item) => item.write_into(writer),
            Self::Format2VariableValue(item) => item.write_into(writer),
            Self::Format3And(item) => item.write_into(writer),
            Self::Format4Or(item) => item.write_into(writer),
            Self::Format5Negate(item) => item.write_into(writer),
        }
    }
    fn table_type(&self) -> TableType {
        match self {
            Self::Format1AxisRange(item) => item.table_type(),
            Self::Format2VariableValue(item) => item.table_type(),
            Self::Format3And(item) => item.table_type(),
            Self::Format4Or(item) => item.table_type(),
            Self::Format5Negate(item) => item.table_type(),
        }
    }
}

impl Validate for Condition {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        match self {
            Self::Format1AxisRange(item) => item.validate_impl(ctx),
            Self::Format2VariableValue(item) => item.validate_impl(ctx),
            Self::Format3And(item) => item.validate_impl(ctx),
            Self::Format4Or(item) => item.validate_impl(ctx),
            Self::Format5Negate(item) => item.validate_impl(ctx),
        }
    }
}

impl FromObjRef<read_fonts::tables::layout::Condition<'_>> for Condition {
    fn from_obj_ref(obj: &read_fonts::tables::layout::Condition, _: FontData) -> Self {
        use read_fonts::tables::layout::Condition as ObjRefType;
        match obj {
            ObjRefType::Format1AxisRange(item) => {
                Condition::Format1AxisRange(item.to_owned_table())
            }
            ObjRefType::Format2VariableValue(item) => {
                Condition::Format2VariableValue(item.to_owned_table())
            }
            ObjRefType::Format3And(item) => Condition::Format3And(item.to_owned_table()),
            ObjRefType::Format4Or(item) => Condition::Format4Or(item.to_owned_table()),
            ObjRefType::Format5Negate(item) => Condition::Format5Negate(item.to_owned_table()),
        }
    }
}

impl FromTableRef<read_fonts::tables::layout::Condition<'_>> for Condition {}

impl<'a> FontRead<'a> for Condition {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::Condition as FontRead>::read(data).map(|x| x.to_owned_table())
    }
}

impl From<ConditionFormat1> for Condition {
    fn from(src: ConditionFormat1) -> Condition {
        Condition::Format1AxisRange(src)
    }
}

impl From<ConditionFormat2> for Condition {
    fn from(src: ConditionFormat2) -> Condition {
        Condition::Format2VariableValue(src)
    }
}

impl From<ConditionFormat3> for Condition {
    fn from(src: ConditionFormat3) -> Condition {
        Condition::Format3And(src)
    }
}

impl From<ConditionFormat4> for Condition {
    fn from(src: ConditionFormat4) -> Condition {
        Condition::Format4Or(src)
    }
}

impl From<ConditionFormat5> for Condition {
    fn from(src: ConditionFormat5) -> Condition {
        Condition::Format5Negate(src)
    }
}

/// [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(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConditionFormat1 {
    /// Index (zero-based) for the variation axis within the 'fvar'
    /// table.
    pub axis_index: u16,
    /// Minimum value of the font variation instances that satisfy this
    /// condition.
    pub filter_range_min_value: F2Dot14,
    /// Maximum value of the font variation instances that satisfy this
    /// condition.
    pub filter_range_max_value: F2Dot14,
}

impl ConditionFormat1 {
    /// Construct a new `ConditionFormat1`
    pub fn new(
        axis_index: u16,
        filter_range_min_value: F2Dot14,
        filter_range_max_value: F2Dot14,
    ) -> Self {
        Self {
            axis_index,
            filter_range_min_value,
            filter_range_max_value,
        }
    }
}

impl FontWrite for ConditionFormat1 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (1 as u16).write_into(writer);
        self.axis_index.write_into(writer);
        self.filter_range_min_value.write_into(writer);
        self.filter_range_max_value.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ConditionFormat1")
    }
}

impl Validate for ConditionFormat1 {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat1<'a>> for ConditionFormat1 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat1<'a>, _: FontData) -> Self {
        ConditionFormat1 {
            axis_index: obj.axis_index(),
            filter_range_min_value: obj.filter_range_min_value(),
            filter_range_max_value: obj.filter_range_max_value(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat1<'a>> for ConditionFormat1 {}

impl<'a> FontRead<'a> for ConditionFormat1 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ConditionFormat1 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConditionFormat2 {
    /// Value at default instance.
    pub default_value: i16,
    /// Variation index to vary the value based on current designspace location.
    pub var_index: u32,
}

impl ConditionFormat2 {
    /// Construct a new `ConditionFormat2`
    pub fn new(default_value: i16, var_index: u32) -> Self {
        Self {
            default_value,
            var_index,
        }
    }
}

impl FontWrite for ConditionFormat2 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (2 as u16).write_into(writer);
        self.default_value.write_into(writer);
        self.var_index.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ConditionFormat2")
    }
}

impl Validate for ConditionFormat2 {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat2<'a>> for ConditionFormat2 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat2<'a>, _: FontData) -> Self {
        ConditionFormat2 {
            default_value: obj.default_value(),
            var_index: obj.var_index(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat2<'a>> for ConditionFormat2 {}

impl<'a> FontRead<'a> for ConditionFormat2 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ConditionFormat2 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConditionFormat3 {
    /// Number of conditions.
    pub condition_count: u8,
    /// Array of condition tables for this conjunction (AND) expression.
    pub conditions: Vec<OffsetMarker<Condition, WIDTH_24>>,
}

impl ConditionFormat3 {
    /// Construct a new `ConditionFormat3`
    pub fn new(condition_count: u8, conditions: Vec<Condition>) -> Self {
        Self {
            condition_count,
            conditions: conditions.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for ConditionFormat3 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (3 as u16).write_into(writer);
        self.condition_count.write_into(writer);
        self.conditions.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ConditionFormat3")
    }
}

impl Validate for ConditionFormat3 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ConditionFormat3", |ctx| {
            ctx.in_field("conditions", |ctx| {
                if self.conditions.len() > (u8::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.conditions.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat3<'a>> for ConditionFormat3 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat3<'a>, _: FontData) -> Self {
        ConditionFormat3 {
            condition_count: obj.condition_count(),
            conditions: obj.conditions().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat3<'a>> for ConditionFormat3 {}

impl<'a> FontRead<'a> for ConditionFormat3 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ConditionFormat3 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConditionFormat4 {
    /// Number of conditions.
    pub condition_count: u8,
    /// Array of condition tables for this disjunction (OR) expression.
    pub conditions: Vec<OffsetMarker<Condition, WIDTH_24>>,
}

impl ConditionFormat4 {
    /// Construct a new `ConditionFormat4`
    pub fn new(condition_count: u8, conditions: Vec<Condition>) -> Self {
        Self {
            condition_count,
            conditions: conditions.into_iter().map(Into::into).collect(),
        }
    }
}

impl FontWrite for ConditionFormat4 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (4 as u16).write_into(writer);
        self.condition_count.write_into(writer);
        self.conditions.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ConditionFormat4")
    }
}

impl Validate for ConditionFormat4 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ConditionFormat4", |ctx| {
            ctx.in_field("conditions", |ctx| {
                if self.conditions.len() > (u8::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.conditions.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat4<'a>> for ConditionFormat4 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat4<'a>, _: FontData) -> Self {
        ConditionFormat4 {
            condition_count: obj.condition_count(),
            conditions: obj.conditions().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat4<'a>> for ConditionFormat4 {}

impl<'a> FontRead<'a> for ConditionFormat4 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ConditionFormat4 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ConditionFormat5 {
    /// Condition to negate.
    pub condition: OffsetMarker<Condition, WIDTH_24>,
}

impl ConditionFormat5 {
    /// Construct a new `ConditionFormat5`
    pub fn new(condition: Condition) -> Self {
        Self {
            condition: condition.into(),
        }
    }
}

impl FontWrite for ConditionFormat5 {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (5 as u16).write_into(writer);
        self.condition.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("ConditionFormat5")
    }
}

impl Validate for ConditionFormat5 {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("ConditionFormat5", |ctx| {
            ctx.in_field("condition", |ctx| {
                self.condition.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::ConditionFormat5<'a>> for ConditionFormat5 {
    fn from_obj_ref(obj: &read_fonts::tables::layout::ConditionFormat5<'a>, _: FontData) -> Self {
        ConditionFormat5 {
            condition: obj.condition().to_owned_table(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::ConditionFormat5<'a>> for ConditionFormat5 {}

impl<'a> FontRead<'a> for ConditionFormat5 {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::ConditionFormat5 as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FeatureTableSubstitution {
    /// Array of feature table substitution records.
    pub substitutions: Vec<FeatureTableSubstitutionRecord>,
}

impl FeatureTableSubstitution {
    /// Construct a new `FeatureTableSubstitution`
    pub fn new(substitutions: Vec<FeatureTableSubstitutionRecord>) -> Self {
        Self { substitutions }
    }
}

impl FontWrite for FeatureTableSubstitution {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (MajorMinor::VERSION_1_0 as MajorMinor).write_into(writer);
        (u16::try_from(array_len(&self.substitutions)).unwrap()).write_into(writer);
        self.substitutions.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("FeatureTableSubstitution")
    }
}

impl Validate for FeatureTableSubstitution {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("FeatureTableSubstitution", |ctx| {
            ctx.in_field("substitutions", |ctx| {
                if self.substitutions.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
                self.substitutions.validate_impl(ctx);
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::FeatureTableSubstitution<'a>>
    for FeatureTableSubstitution
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::FeatureTableSubstitution<'a>,
        _: FontData,
    ) -> Self {
        let offset_data = obj.offset_data();
        FeatureTableSubstitution {
            substitutions: obj.substitutions().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::FeatureTableSubstitution<'a>>
    for FeatureTableSubstitution
{
}

impl<'a> FontRead<'a> for FeatureTableSubstitution {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::FeatureTableSubstitution as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// Used in [FeatureTableSubstitution]
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct FeatureTableSubstitutionRecord {
    /// The feature table index to match.
    pub feature_index: u16,
    /// Offset to an alternate feature table, from start of the
    /// FeatureTableSubstitution table.
    pub alternate_feature: OffsetMarker<Feature, WIDTH_32>,
}

impl FeatureTableSubstitutionRecord {
    /// Construct a new `FeatureTableSubstitutionRecord`
    pub fn new(feature_index: u16, alternate_feature: Feature) -> Self {
        Self {
            feature_index,
            alternate_feature: alternate_feature.into(),
        }
    }
}

impl FontWrite for FeatureTableSubstitutionRecord {
    fn write_into(&self, writer: &mut TableWriter) {
        self.feature_index.write_into(writer);
        self.alternate_feature.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("FeatureTableSubstitutionRecord")
    }
}

impl Validate for FeatureTableSubstitutionRecord {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("FeatureTableSubstitutionRecord", |ctx| {
            ctx.in_field("alternate_feature", |ctx| {
                self.alternate_feature.validate_impl(ctx);
            });
        })
    }
}

impl FromObjRef<read_fonts::tables::layout::FeatureTableSubstitutionRecord>
    for FeatureTableSubstitutionRecord
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::FeatureTableSubstitutionRecord,
        offset_data: FontData,
    ) -> Self {
        FeatureTableSubstitutionRecord {
            feature_index: obj.feature_index(),
            alternate_feature: obj.alternate_feature(offset_data).to_owned_table(),
        }
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SizeParams {
    /// 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 design_size: u16,
    /// 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 identifier: u16,
    /// 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 name_entry: u16,
    /// 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 range_start: u16,
    pub range_end: u16,
}

impl SizeParams {
    /// Construct a new `SizeParams`
    pub fn new(
        design_size: u16,
        identifier: u16,
        name_entry: u16,
        range_start: u16,
        range_end: u16,
    ) -> Self {
        Self {
            design_size,
            identifier,
            name_entry,
            range_start,
            range_end,
        }
    }
}

impl FontWrite for SizeParams {
    fn write_into(&self, writer: &mut TableWriter) {
        self.design_size.write_into(writer);
        self.identifier.write_into(writer);
        self.name_entry.write_into(writer);
        self.range_start.write_into(writer);
        self.range_end.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("SizeParams")
    }
}

impl Validate for SizeParams {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl<'a> FromObjRef<read_fonts::tables::layout::SizeParams<'a>> for SizeParams {
    fn from_obj_ref(obj: &read_fonts::tables::layout::SizeParams<'a>, _: FontData) -> Self {
        SizeParams {
            design_size: obj.design_size(),
            identifier: obj.identifier(),
            name_entry: obj.name_entry(),
            range_start: obj.range_start(),
            range_end: obj.range_end(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::SizeParams<'a>> for SizeParams {}

impl<'a> FontRead<'a> for SizeParams {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::SizeParams as FontRead>::read(data).map(|x| x.to_owned_table())
    }
}

#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StylisticSetParams {
    /// 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 ui_name_id: NameId,
}

impl StylisticSetParams {
    /// Construct a new `StylisticSetParams`
    pub fn new(ui_name_id: NameId) -> Self {
        Self { ui_name_id }
    }
}

impl FontWrite for StylisticSetParams {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (0 as u16).write_into(writer);
        self.ui_name_id.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("StylisticSetParams")
    }
}

impl Validate for StylisticSetParams {
    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
}

impl<'a> FromObjRef<read_fonts::tables::layout::StylisticSetParams<'a>> for StylisticSetParams {
    fn from_obj_ref(obj: &read_fonts::tables::layout::StylisticSetParams<'a>, _: FontData) -> Self {
        StylisticSetParams {
            ui_name_id: obj.ui_name_id(),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::StylisticSetParams<'a>> for StylisticSetParams {}

impl<'a> FontRead<'a> for StylisticSetParams {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::StylisticSetParams as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}

/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CharacterVariantParams {
    /// 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 feat_ui_label_name_id: NameId,
    /// 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 feat_ui_tooltip_text_name_id: NameId,
    /// The 'name' table name ID that specifies sample text that
    /// illustrates the effect of this feature. (May be NULL.)
    pub sample_text_name_id: NameId,
    /// Number of named parameters. (May be zero.)
    pub num_named_parameters: u16,
    /// 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 first_param_ui_label_name_id: NameId,
    /// The Unicode Scalar Value of the characters for which this
    /// feature provides glyph variants.
    pub character: Vec<Uint24>,
}

impl CharacterVariantParams {
    /// Construct a new `CharacterVariantParams`
    pub fn new(
        feat_ui_label_name_id: NameId,
        feat_ui_tooltip_text_name_id: NameId,
        sample_text_name_id: NameId,
        num_named_parameters: u16,
        first_param_ui_label_name_id: NameId,
        character: Vec<Uint24>,
    ) -> Self {
        Self {
            feat_ui_label_name_id,
            feat_ui_tooltip_text_name_id,
            sample_text_name_id,
            num_named_parameters,
            first_param_ui_label_name_id,
            character,
        }
    }
}

impl FontWrite for CharacterVariantParams {
    #[allow(clippy::unnecessary_cast)]
    fn write_into(&self, writer: &mut TableWriter) {
        (0 as u16).write_into(writer);
        self.feat_ui_label_name_id.write_into(writer);
        self.feat_ui_tooltip_text_name_id.write_into(writer);
        self.sample_text_name_id.write_into(writer);
        self.num_named_parameters.write_into(writer);
        self.first_param_ui_label_name_id.write_into(writer);
        (u16::try_from(array_len(&self.character)).unwrap()).write_into(writer);
        self.character.write_into(writer);
    }
    fn table_type(&self) -> TableType {
        TableType::Named("CharacterVariantParams")
    }
}

impl Validate for CharacterVariantParams {
    fn validate_impl(&self, ctx: &mut ValidationCtx) {
        ctx.in_table("CharacterVariantParams", |ctx| {
            ctx.in_field("character", |ctx| {
                if self.character.len() > (u16::MAX as usize) {
                    ctx.report("array exceeds max length");
                }
            });
        })
    }
}

impl<'a> FromObjRef<read_fonts::tables::layout::CharacterVariantParams<'a>>
    for CharacterVariantParams
{
    fn from_obj_ref(
        obj: &read_fonts::tables::layout::CharacterVariantParams<'a>,
        _: FontData,
    ) -> Self {
        let offset_data = obj.offset_data();
        CharacterVariantParams {
            feat_ui_label_name_id: obj.feat_ui_label_name_id(),
            feat_ui_tooltip_text_name_id: obj.feat_ui_tooltip_text_name_id(),
            sample_text_name_id: obj.sample_text_name_id(),
            num_named_parameters: obj.num_named_parameters(),
            first_param_ui_label_name_id: obj.first_param_ui_label_name_id(),
            character: obj.character().to_owned_obj(offset_data),
        }
    }
}

#[allow(clippy::needless_lifetimes)]
impl<'a> FromTableRef<read_fonts::tables::layout::CharacterVariantParams<'a>>
    for CharacterVariantParams
{
}

impl<'a> FontRead<'a> for CharacterVariantParams {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        <read_fonts::tables::layout::CharacterVariantParams as FontRead>::read(data)
            .map(|x| x.to_owned_table())
    }
}
