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

/// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct StatMarker {
    elided_fallback_name_id_byte_start: Option<usize>,
}

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

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

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

    pub fn design_axes_offset_byte_range(&self) -> Range<usize> {
        let start = self.design_axis_count_byte_range().end;
        start..start + Offset32::RAW_BYTE_LEN
    }

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

    pub fn offset_to_axis_value_offsets_byte_range(&self) -> Range<usize> {
        let start = self.axis_value_count_byte_range().end;
        start..start + Offset32::RAW_BYTE_LEN
    }

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

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

impl TopLevelTable for Stat<'_> {
    /// `STAT`
    const TAG: Tag = Tag::new(b"STAT");
}

impl<'a> FontRead<'a> for Stat<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let version: MajorMinor = cursor.read()?;
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<Offset32>();
        cursor.advance::<u16>();
        cursor.advance::<Offset32>();
        let elided_fallback_name_id_byte_start = version
            .compatible((1u16, 1u16))
            .then(|| cursor.position())
            .transpose()?;
        version
            .compatible((1u16, 1u16))
            .then(|| cursor.advance::<NameId>());
        cursor.finish(StatMarker {
            elided_fallback_name_id_byte_start,
        })
    }
}

/// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
pub type Stat<'a> = TableRef<'a, StatMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> Stat<'a> {
    /// Major/minor version number. Set to 1.2 for new fonts.
    pub fn version(&self) -> MajorMinor {
        let range = self.shape.version_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The size in bytes of each axis record.
    pub fn design_axis_size(&self) -> u16 {
        let range = self.shape.design_axis_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The number of axis records. In a font with an 'fvar' table,
    /// this value must be greater than or equal to the axisCount value
    /// in the 'fvar' table. In all fonts, must be greater than zero if
    /// axisValueCount is greater than zero.
    pub fn design_axis_count(&self) -> u16 {
        let range = self.shape.design_axis_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Offset in bytes from the beginning of the STAT table to the
    /// start of the design axes array. If designAxisCount is zero, set
    /// to zero; if designAxisCount is greater than zero, must be
    /// greater than zero.
    pub fn design_axes_offset(&self) -> Offset32 {
        let range = self.shape.design_axes_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Attempt to resolve [`design_axes_offset`][Self::design_axes_offset].
    pub fn design_axes(&self) -> Result<&'a [AxisRecord], ReadError> {
        let data = self.data;
        let args = self.design_axis_count();
        self.design_axes_offset().resolve_with_args(data, &args)
    }

    /// The number of axis value tables.
    pub fn axis_value_count(&self) -> u16 {
        let range = self.shape.axis_value_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Offset in bytes from the beginning of the STAT table to the
    /// start of the design axes value offsets array. If axisValueCount
    /// is zero, set to zero; if axisValueCount is greater than zero,
    /// must be greater than zero.
    pub fn offset_to_axis_value_offsets(&self) -> Nullable<Offset32> {
        let range = self.shape.offset_to_axis_value_offsets_byte_range();
        self.data.read_at(range.start).unwrap()
    }

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

    /// Name ID used as fallback when projection of names into a
    /// particular font model produces a subfamily name containing only
    /// elidable elements.
    pub fn elided_fallback_name_id(&self) -> Option<NameId> {
        let range = self.shape.elided_fallback_name_id_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Stat<'a> {
    fn type_name(&self) -> &str {
        "Stat"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        let version = self.version();
        match idx {
            0usize => Some(Field::new("version", self.version())),
            1usize => Some(Field::new("design_axis_size", self.design_axis_size())),
            2usize => Some(Field::new("design_axis_count", self.design_axis_count())),
            3usize => Some(Field::new(
                "design_axes_offset",
                traversal::FieldType::offset_to_array_of_records(
                    self.design_axes_offset(),
                    self.design_axes(),
                    stringify!(AxisRecord),
                    self.offset_data(),
                ),
            )),
            4usize => Some(Field::new("axis_value_count", self.axis_value_count())),
            5usize => Some(Field::new(
                "offset_to_axis_value_offsets",
                FieldType::offset(
                    self.offset_to_axis_value_offsets(),
                    self.offset_to_axis_values(),
                ),
            )),
            6usize if version.compatible((1u16, 1u16)) => Some(Field::new(
                "elided_fallback_name_id",
                self.elided_fallback_name_id().unwrap(),
            )),
            _ => None,
        }
    }
}

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

/// [Axis Records](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-records)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct AxisRecord {
    /// A tag identifying the axis of design variation.
    pub axis_tag: BigEndian<Tag>,
    /// The name ID for entries in the 'name' table that provide a
    /// display string for this axis.
    pub axis_name_id: BigEndian<NameId>,
    /// A value that applications can use to determine primary sorting
    /// of face names, or for ordering of labels when composing family
    /// or face names.
    pub axis_ordering: BigEndian<u16>,
}

impl AxisRecord {
    /// A tag identifying the axis of design variation.
    pub fn axis_tag(&self) -> Tag {
        self.axis_tag.get()
    }

    /// The name ID for entries in the 'name' table that provide a
    /// display string for this axis.
    pub fn axis_name_id(&self) -> NameId {
        self.axis_name_id.get()
    }

    /// A value that applications can use to determine primary sorting
    /// of face names, or for ordering of labels when composing family
    /// or face names.
    pub fn axis_ordering(&self) -> u16 {
        self.axis_ordering.get()
    }
}

impl FixedSize for AxisRecord {
    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
}

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

/// An array of [AxisValue] tables.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct AxisValueArrayMarker {
    axis_value_offsets_byte_len: usize,
}

impl AxisValueArrayMarker {
    pub fn axis_value_offsets_byte_range(&self) -> Range<usize> {
        let start = 0;
        start..start + self.axis_value_offsets_byte_len
    }
}

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

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

impl<'a> FontReadWithArgs<'a> for AxisValueArray<'a> {
    fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
        let axis_value_count = *args;
        let mut cursor = data.cursor();
        let axis_value_offsets_byte_len = (axis_value_count as usize)
            .checked_mul(Offset16::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(axis_value_offsets_byte_len);
        cursor.finish(AxisValueArrayMarker {
            axis_value_offsets_byte_len,
        })
    }
}

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

/// An array of [AxisValue] tables.
pub type AxisValueArray<'a> = TableRef<'a, AxisValueArrayMarker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> AxisValueArray<'a> {
    /// Array of offsets to axis value tables, in bytes from the start
    /// of the axis value offsets array.
    pub fn axis_value_offsets(&self) -> &'a [BigEndian<Offset16>] {
        let range = self.shape.axis_value_offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

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

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

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

/// [Axis Value Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-tables)
#[derive(Clone)]
pub enum AxisValue<'a> {
    Format1(AxisValueFormat1<'a>),
    Format2(AxisValueFormat2<'a>),
    Format3(AxisValueFormat3<'a>),
    Format4(AxisValueFormat4<'a>),
}

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

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

    /// Flags — see below for details.
    pub fn flags(&self) -> AxisValueTableFlags {
        match self {
            Self::Format1(item) => item.flags(),
            Self::Format2(item) => item.flags(),
            Self::Format3(item) => item.flags(),
            Self::Format4(item) => item.flags(),
        }
    }

    /// The name ID for entries in the 'name' table that provide a
    /// display string for this attribute value.
    pub fn value_name_id(&self) -> NameId {
        match self {
            Self::Format1(item) => item.value_name_id(),
            Self::Format2(item) => item.value_name_id(),
            Self::Format3(item) => item.value_name_id(),
            Self::Format4(item) => item.value_name_id(),
        }
    }
}

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

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

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

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

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

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

/// [Axis value table format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-1)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct AxisValueFormat1Marker {}

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

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

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

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

    pub fn value_byte_range(&self) -> Range<usize> {
        let start = self.value_name_id_byte_range().end;
        start..start + Fixed::RAW_BYTE_LEN
    }
}

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

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

/// [Axis value table format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-1)
pub type AxisValueFormat1<'a> = TableRef<'a, AxisValueFormat1Marker>;

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

    /// Zero-base index into the axis record array identifying the axis
    /// of design variation to which the axis value table applies. Must
    /// be less than designAxisCount.
    pub fn axis_index(&self) -> u16 {
        let range = self.shape.axis_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Flags — see below for details.
    pub fn flags(&self) -> AxisValueTableFlags {
        let range = self.shape.flags_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The name ID for entries in the 'name' table that provide a
    /// display string for this attribute value.
    pub fn value_name_id(&self) -> NameId {
        let range = self.shape.value_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// A numeric value for this attribute value.
    pub fn value(&self) -> Fixed {
        let range = self.shape.value_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

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

/// [Axis value table format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-2)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct AxisValueFormat2Marker {}

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

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

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

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

    pub fn nominal_value_byte_range(&self) -> Range<usize> {
        let start = self.value_name_id_byte_range().end;
        start..start + Fixed::RAW_BYTE_LEN
    }

    pub fn range_min_value_byte_range(&self) -> Range<usize> {
        let start = self.nominal_value_byte_range().end;
        start..start + Fixed::RAW_BYTE_LEN
    }

    pub fn range_max_value_byte_range(&self) -> Range<usize> {
        let start = self.range_min_value_byte_range().end;
        start..start + Fixed::RAW_BYTE_LEN
    }
}

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

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

/// [Axis value table format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-2)
pub type AxisValueFormat2<'a> = TableRef<'a, AxisValueFormat2Marker>;

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

    /// Zero-base index into the axis record array identifying the axis
    /// of design variation to which the axis value table applies. Must
    /// be less than designAxisCount.
    pub fn axis_index(&self) -> u16 {
        let range = self.shape.axis_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Flags — see below for details.
    pub fn flags(&self) -> AxisValueTableFlags {
        let range = self.shape.flags_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The name ID for entries in the 'name' table that provide a
    /// display string for this attribute value.
    pub fn value_name_id(&self) -> NameId {
        let range = self.shape.value_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// A nominal numeric value for this attribute value.
    pub fn nominal_value(&self) -> Fixed {
        let range = self.shape.nominal_value_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The minimum value for a range associated with the specified
    /// name ID.
    pub fn range_min_value(&self) -> Fixed {
        let range = self.shape.range_min_value_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The maximum value for a range associated with the specified
    /// name ID.
    pub fn range_max_value(&self) -> Fixed {
        let range = self.shape.range_max_value_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for AxisValueFormat2<'a> {
    fn type_name(&self) -> &str {
        "AxisValueFormat2"
    }
    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
        match idx {
            0usize => Some(Field::new("format", self.format())),
            1usize => Some(Field::new("axis_index", self.axis_index())),
            2usize => Some(Field::new("flags", self.flags())),
            3usize => Some(Field::new("value_name_id", self.value_name_id())),
            4usize => Some(Field::new("nominal_value", self.nominal_value())),
            5usize => Some(Field::new("range_min_value", self.range_min_value())),
            6usize => Some(Field::new("range_max_value", self.range_max_value())),
            _ => None,
        }
    }
}

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

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

/// [Axis value table format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-3)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct AxisValueFormat3Marker {}

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

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

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

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

    pub fn value_byte_range(&self) -> Range<usize> {
        let start = self.value_name_id_byte_range().end;
        start..start + Fixed::RAW_BYTE_LEN
    }

    pub fn linked_value_byte_range(&self) -> Range<usize> {
        let start = self.value_byte_range().end;
        start..start + Fixed::RAW_BYTE_LEN
    }
}

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

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

/// [Axis value table format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-3)
pub type AxisValueFormat3<'a> = TableRef<'a, AxisValueFormat3Marker>;

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

    /// Zero-base index into the axis record array identifying the axis
    /// of design variation to which the axis value table applies. Must
    /// be less than designAxisCount.
    pub fn axis_index(&self) -> u16 {
        let range = self.shape.axis_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Flags — see below for details.
    pub fn flags(&self) -> AxisValueTableFlags {
        let range = self.shape.flags_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The name ID for entries in the 'name' table that provide a
    /// display string for this attribute value.
    pub fn value_name_id(&self) -> NameId {
        let range = self.shape.value_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// A numeric value for this attribute value.
    pub fn value(&self) -> Fixed {
        let range = self.shape.value_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The numeric value for a style-linked mapping from this value.
    pub fn linked_value(&self) -> Fixed {
        let range = self.shape.linked_value_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

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

/// [Axis value table format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct AxisValueFormat4Marker {
    axis_values_byte_len: usize,
}

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

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

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

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

    pub fn axis_values_byte_range(&self) -> Range<usize> {
        let start = self.value_name_id_byte_range().end;
        start..start + self.axis_values_byte_len
    }
}

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

impl<'a> FontRead<'a> for AxisValueFormat4<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u16>();
        let axis_count: u16 = cursor.read()?;
        cursor.advance::<AxisValueTableFlags>();
        cursor.advance::<NameId>();
        let axis_values_byte_len = (axis_count as usize)
            .checked_mul(AxisValueRecord::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(axis_values_byte_len);
        cursor.finish(AxisValueFormat4Marker {
            axis_values_byte_len,
        })
    }
}

/// [Axis value table format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4)
pub type AxisValueFormat4<'a> = TableRef<'a, AxisValueFormat4Marker>;

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

    /// The total number of axes contributing to this axis-values
    /// combination.
    pub fn axis_count(&self) -> u16 {
        let range = self.shape.axis_count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Flags — see below for details.
    pub fn flags(&self) -> AxisValueTableFlags {
        let range = self.shape.flags_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The name ID for entries in the 'name' table that provide a
    /// display string for this combination of axis values.
    pub fn value_name_id(&self) -> NameId {
        let range = self.shape.value_name_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Array of AxisValue records that provide the combination of axis
    /// values, one for each contributing axis.
    pub fn axis_values(&self) -> &'a [AxisValueRecord] {
        let range = self.shape.axis_values_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Part of [AxisValueFormat4]
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct AxisValueRecord {
    /// Zero-base index into the axis record array identifying the axis
    /// to which this value applies. Must be less than designAxisCount.
    pub axis_index: BigEndian<u16>,
    /// A numeric value for this attribute value.
    pub value: BigEndian<Fixed>,
}

impl AxisValueRecord {
    /// Zero-base index into the axis record array identifying the axis
    /// to which this value applies. Must be less than designAxisCount.
    pub fn axis_index(&self) -> u16 {
        self.axis_index.get()
    }

    /// A numeric value for this attribute value.
    pub fn value(&self) -> Fixed {
        self.value.get()
    }
}

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

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

/// [Axis value table flags](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#flags).
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct AxisValueTableFlags {
    bits: u16,
}

impl AxisValueTableFlags {
    /// If set, this axis value table provides axis value information
    /// that is applicable to other fonts within the same font family.
    /// This is used if the other fonts were released earlier and did
    /// not include information about values for some axis. If newer
    /// versions of the other fonts include the information themselves
    /// and are present, then this table is ignored.
    pub const OLDER_SIBLING_FONT_ATTRIBUTE: Self = Self { bits: 0x0001 };

    /// If set, it indicates that the axis value represents the
    /// “normal” value for the axis and may be omitted when
    /// composing name strings.
    pub const ELIDABLE_AXIS_VALUE_NAME: Self = Self { bits: 0x0002 };
}

impl AxisValueTableFlags {
    ///  Returns an empty set of flags.
    #[inline]
    pub const fn empty() -> Self {
        Self { bits: 0 }
    }

    /// Returns the set containing all flags.
    #[inline]
    pub const fn all() -> Self {
        Self {
            bits: Self::OLDER_SIBLING_FONT_ATTRIBUTE.bits | Self::ELIDABLE_AXIS_VALUE_NAME.bits,
        }
    }

    /// Returns the raw value of the flags currently stored.
    #[inline]
    pub const fn bits(&self) -> u16 {
        self.bits
    }

    /// Convert from underlying bit representation, unless that
    /// representation contains bits that do not correspond to a flag.
    #[inline]
    pub const fn from_bits(bits: u16) -> Option<Self> {
        if (bits & !Self::all().bits()) == 0 {
            Some(Self { bits })
        } else {
            None
        }
    }

    /// Convert from underlying bit representation, dropping any bits
    /// that do not correspond to flags.
    #[inline]
    pub const fn from_bits_truncate(bits: u16) -> Self {
        Self {
            bits: bits & Self::all().bits,
        }
    }

    /// Returns `true` if no flags are currently stored.
    #[inline]
    pub const fn is_empty(&self) -> bool {
        self.bits() == Self::empty().bits()
    }

    /// Returns `true` if there are flags common to both `self` and `other`.
    #[inline]
    pub const fn intersects(&self, other: Self) -> bool {
        !(Self {
            bits: self.bits & other.bits,
        })
        .is_empty()
    }

    /// Returns `true` if all of the flags in `other` are contained within `self`.
    #[inline]
    pub const fn contains(&self, other: Self) -> bool {
        (self.bits & other.bits) == other.bits
    }

    /// Inserts the specified flags in-place.
    #[inline]
    pub fn insert(&mut self, other: Self) {
        self.bits |= other.bits;
    }

    /// Removes the specified flags in-place.
    #[inline]
    pub fn remove(&mut self, other: Self) {
        self.bits &= !other.bits;
    }

    /// Toggles the specified flags in-place.
    #[inline]
    pub fn toggle(&mut self, other: Self) {
        self.bits ^= other.bits;
    }

    /// Returns the intersection between the flags in `self` and
    /// `other`.
    ///
    /// Specifically, the returned set contains only the flags which are
    /// present in *both* `self` *and* `other`.
    ///
    /// This is equivalent to using the `&` operator (e.g.
    /// [`ops::BitAnd`]), as in `flags & other`.
    ///
    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
    #[inline]
    #[must_use]
    pub const fn intersection(self, other: Self) -> Self {
        Self {
            bits: self.bits & other.bits,
        }
    }

    /// Returns the union of between the flags in `self` and `other`.
    ///
    /// Specifically, the returned set contains all flags which are
    /// present in *either* `self` *or* `other`, including any which are
    /// present in both.
    ///
    /// This is equivalent to using the `|` operator (e.g.
    /// [`ops::BitOr`]), as in `flags | other`.
    ///
    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
    #[inline]
    #[must_use]
    pub const fn union(self, other: Self) -> Self {
        Self {
            bits: self.bits | other.bits,
        }
    }

    /// Returns the difference between the flags in `self` and `other`.
    ///
    /// Specifically, the returned set contains all flags present in
    /// `self`, except for the ones present in `other`.
    ///
    /// It is also conceptually equivalent to the "bit-clear" operation:
    /// `flags & !other` (and this syntax is also supported).
    ///
    /// This is equivalent to using the `-` operator (e.g.
    /// [`ops::Sub`]), as in `flags - other`.
    ///
    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
    #[inline]
    #[must_use]
    pub const fn difference(self, other: Self) -> Self {
        Self {
            bits: self.bits & !other.bits,
        }
    }
}

impl std::ops::BitOr for AxisValueTableFlags {
    type Output = Self;

    /// Returns the union of the two sets of flags.
    #[inline]
    fn bitor(self, other: AxisValueTableFlags) -> Self {
        Self {
            bits: self.bits | other.bits,
        }
    }
}

impl std::ops::BitOrAssign for AxisValueTableFlags {
    /// Adds the set of flags.
    #[inline]
    fn bitor_assign(&mut self, other: Self) {
        self.bits |= other.bits;
    }
}

impl std::ops::BitXor for AxisValueTableFlags {
    type Output = Self;

    /// Returns the left flags, but with all the right flags toggled.
    #[inline]
    fn bitxor(self, other: Self) -> Self {
        Self {
            bits: self.bits ^ other.bits,
        }
    }
}

impl std::ops::BitXorAssign for AxisValueTableFlags {
    /// Toggles the set of flags.
    #[inline]
    fn bitxor_assign(&mut self, other: Self) {
        self.bits ^= other.bits;
    }
}

impl std::ops::BitAnd for AxisValueTableFlags {
    type Output = Self;

    /// Returns the intersection between the two sets of flags.
    #[inline]
    fn bitand(self, other: Self) -> Self {
        Self {
            bits: self.bits & other.bits,
        }
    }
}

impl std::ops::BitAndAssign for AxisValueTableFlags {
    /// Disables all flags disabled in the set.
    #[inline]
    fn bitand_assign(&mut self, other: Self) {
        self.bits &= other.bits;
    }
}

impl std::ops::Sub for AxisValueTableFlags {
    type Output = Self;

    /// Returns the set difference of the two sets of flags.
    #[inline]
    fn sub(self, other: Self) -> Self {
        Self {
            bits: self.bits & !other.bits,
        }
    }
}

impl std::ops::SubAssign for AxisValueTableFlags {
    /// Disables all flags enabled in the set.
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        self.bits &= !other.bits;
    }
}

impl std::ops::Not for AxisValueTableFlags {
    type Output = Self;

    /// Returns the complement of this set of flags.
    #[inline]
    fn not(self) -> Self {
        Self { bits: !self.bits } & Self::all()
    }
}

impl std::fmt::Debug for AxisValueTableFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let members: &[(&str, Self)] = &[
            (
                "OLDER_SIBLING_FONT_ATTRIBUTE",
                Self::OLDER_SIBLING_FONT_ATTRIBUTE,
            ),
            ("ELIDABLE_AXIS_VALUE_NAME", Self::ELIDABLE_AXIS_VALUE_NAME),
        ];
        let mut first = true;
        for (name, value) in members {
            if self.contains(*value) {
                if !first {
                    f.write_str(" | ")?;
                }
                first = false;
                f.write_str(name)?;
            }
        }
        if first {
            f.write_str("(empty)")?;
        }
        Ok(())
    }
}

impl std::fmt::Binary for AxisValueTableFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Binary::fmt(&self.bits, f)
    }
}

impl std::fmt::Octal for AxisValueTableFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Octal::fmt(&self.bits, f)
    }
}

impl std::fmt::LowerHex for AxisValueTableFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::LowerHex::fmt(&self.bits, f)
    }
}

impl std::fmt::UpperHex for AxisValueTableFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::UpperHex::fmt(&self.bits, f)
    }
}

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

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