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

/// OS/2 [selection flags](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection)
#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct SelectionFlags {
    bits: u16,
}

impl SelectionFlags {
    /// Bit 0: Font contains italic or oblique glyphs, otherwise they are
    /// upright.
    pub const ITALIC: Self = Self { bits: 0x0001 };

    /// Bit 1: Glyphs are underscored.
    pub const UNDERSCORE: Self = Self { bits: 0x0002 };

    /// Bit 2: Glyphs have their foreground and background reversed.
    pub const NEGATIVE: Self = Self { bits: 0x0004 };

    /// Bit 3: Outline (hollow) glyphs, otherwise they are solid.
    pub const OUTLINED: Self = Self { bits: 0x0008 };

    /// Bit 4: Glyphs are overstruck.
    pub const STRIKEOUT: Self = Self { bits: 0x0010 };

    /// Bit 5: Glyphs are emboldened.
    pub const BOLD: Self = Self { bits: 0x0020 };

    /// Bit 6: Glyphs are in the standard weight/style for the font.
    pub const REGULAR: Self = Self { bits: 0x0040 };

    /// Bit 7: If set, it is strongly recommended that applications use
    /// OS/2.sTypoAscender - OS/2.sTypoDescender + OS/2.sTypoLineGap as
    /// the default line spacing for this font.
    pub const USE_TYPO_METRICS: Self = Self { bits: 0x0080 };

    /// Bit 8: The font has 'name' table strings consistent with a
    /// weight/width/slope family without requiring use of name IDs 21 and 22.
    pub const WWS: Self = Self { bits: 0x0100 };

    /// Bit 9: Font contains oblique glyphs.
    pub const OBLIQUE: Self = Self { bits: 0x0200 };
}

impl SelectionFlags {
    ///  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::ITALIC.bits
                | Self::UNDERSCORE.bits
                | Self::NEGATIVE.bits
                | Self::OUTLINED.bits
                | Self::STRIKEOUT.bits
                | Self::BOLD.bits
                | Self::REGULAR.bits
                | Self::USE_TYPO_METRICS.bits
                | Self::WWS.bits
                | Self::OBLIQUE.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 SelectionFlags {
    type Output = Self;

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

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

impl std::ops::BitXor for SelectionFlags {
    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 SelectionFlags {
    /// Toggles the set of flags.
    #[inline]
    fn bitxor_assign(&mut self, other: Self) {
        self.bits ^= other.bits;
    }
}

impl std::ops::BitAnd for SelectionFlags {
    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 SelectionFlags {
    /// Disables all flags disabled in the set.
    #[inline]
    fn bitand_assign(&mut self, other: Self) {
        self.bits &= other.bits;
    }
}

impl std::ops::Sub for SelectionFlags {
    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 SelectionFlags {
    /// Disables all flags enabled in the set.
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        self.bits &= !other.bits;
    }
}

impl std::ops::Not for SelectionFlags {
    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 SelectionFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let members: &[(&str, Self)] = &[
            ("ITALIC", Self::ITALIC),
            ("UNDERSCORE", Self::UNDERSCORE),
            ("NEGATIVE", Self::NEGATIVE),
            ("OUTLINED", Self::OUTLINED),
            ("STRIKEOUT", Self::STRIKEOUT),
            ("BOLD", Self::BOLD),
            ("REGULAR", Self::REGULAR),
            ("USE_TYPO_METRICS", Self::USE_TYPO_METRICS),
            ("WWS", Self::WWS),
            ("OBLIQUE", Self::OBLIQUE),
        ];
        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 SelectionFlags {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Binary::fmt(&self.bits, f)
    }
}

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

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

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

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

/// [`OS/2`](https://docs.microsoft.com/en-us/typography/opentype/spec/os2)
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct Os2Marker {
    panose_10_byte_len: usize,
    ul_code_page_range_1_byte_start: Option<usize>,
    ul_code_page_range_2_byte_start: Option<usize>,
    sx_height_byte_start: Option<usize>,
    s_cap_height_byte_start: Option<usize>,
    us_default_char_byte_start: Option<usize>,
    us_break_char_byte_start: Option<usize>,
    us_max_context_byte_start: Option<usize>,
    us_lower_optical_point_size_byte_start: Option<usize>,
    us_upper_optical_point_size_byte_start: Option<usize>,
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    pub fn panose_10_byte_range(&self) -> Range<usize> {
        let start = self.s_family_class_byte_range().end;
        start..start + self.panose_10_byte_len
    }

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

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

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

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

    pub fn ach_vend_id_byte_range(&self) -> Range<usize> {
        let start = self.ul_unicode_range_4_byte_range().end;
        start..start + Tag::RAW_BYTE_LEN
    }

    pub fn fs_selection_byte_range(&self) -> Range<usize> {
        let start = self.ach_vend_id_byte_range().end;
        start..start + SelectionFlags::RAW_BYTE_LEN
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

impl<'a> FontRead<'a> for Os2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let version: u16 = cursor.read()?;
        cursor.advance::<i16>();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        let panose_10_byte_len = (10_usize)
            .checked_mul(u8::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(panose_10_byte_len);
        cursor.advance::<u32>();
        cursor.advance::<u32>();
        cursor.advance::<u32>();
        cursor.advance::<u32>();
        cursor.advance::<Tag>();
        cursor.advance::<SelectionFlags>();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<i16>();
        cursor.advance::<u16>();
        cursor.advance::<u16>();
        let ul_code_page_range_1_byte_start = version
            .compatible(1u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(1u16).then(|| cursor.advance::<u32>());
        let ul_code_page_range_2_byte_start = version
            .compatible(1u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(1u16).then(|| cursor.advance::<u32>());
        let sx_height_byte_start = version
            .compatible(2u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(2u16).then(|| cursor.advance::<i16>());
        let s_cap_height_byte_start = version
            .compatible(2u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(2u16).then(|| cursor.advance::<i16>());
        let us_default_char_byte_start = version
            .compatible(2u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(2u16).then(|| cursor.advance::<u16>());
        let us_break_char_byte_start = version
            .compatible(2u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(2u16).then(|| cursor.advance::<u16>());
        let us_max_context_byte_start = version
            .compatible(2u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(2u16).then(|| cursor.advance::<u16>());
        let us_lower_optical_point_size_byte_start = version
            .compatible(5u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(5u16).then(|| cursor.advance::<u16>());
        let us_upper_optical_point_size_byte_start = version
            .compatible(5u16)
            .then(|| cursor.position())
            .transpose()?;
        version.compatible(5u16).then(|| cursor.advance::<u16>());
        cursor.finish(Os2Marker {
            panose_10_byte_len,
            ul_code_page_range_1_byte_start,
            ul_code_page_range_2_byte_start,
            sx_height_byte_start,
            s_cap_height_byte_start,
            us_default_char_byte_start,
            us_break_char_byte_start,
            us_max_context_byte_start,
            us_lower_optical_point_size_byte_start,
            us_upper_optical_point_size_byte_start,
        })
    }
}

/// [`OS/2`](https://docs.microsoft.com/en-us/typography/opentype/spec/os2)
pub type Os2<'a> = TableRef<'a, Os2Marker>;

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

    /// [Average weighted escapement](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#xavgcharwidth).
    ///
    /// The Average Character Width parameter specifies the arithmetic average
    /// of the escapement (width) of all non-zero width glyphs in the font.
    pub fn x_avg_char_width(&self) -> i16 {
        let range = self.shape.x_avg_char_width_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// [Weight class](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass).
    ///
    /// Indicates the visual weight (degree of blackness or thickness of
    /// strokes) of the characters in the font. Values from 1 to 1000 are valid.
    pub fn us_weight_class(&self) -> u16 {
        let range = self.shape.us_weight_class_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// [Width class](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#uswidthclass).
    ///
    /// Indicates a relative change from the normal aspect ratio (width to height
    /// ratio) as specified by a font designer for the glyphs in a font.
    pub fn us_width_class(&self) -> u16 {
        let range = self.shape.us_width_class_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// [Type flags](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fstype).
    ///
    /// Indicates font embedding licensing rights for the font.
    pub fn fs_type(&self) -> u16 {
        let range = self.shape.fs_type_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended horizontal size in font design units for subscripts for
    /// this font.
    pub fn y_subscript_x_size(&self) -> i16 {
        let range = self.shape.y_subscript_x_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended vertical size in font design units for subscripts for
    /// this font.
    pub fn y_subscript_y_size(&self) -> i16 {
        let range = self.shape.y_subscript_y_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended horizontal offset in font design units for subscripts
    /// for this font.
    pub fn y_subscript_x_offset(&self) -> i16 {
        let range = self.shape.y_subscript_x_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended vertical offset in font design units for subscripts
    /// for this font.
    pub fn y_subscript_y_offset(&self) -> i16 {
        let range = self.shape.y_subscript_y_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended horizontal size in font design units for superscripts
    /// for this font.
    pub fn y_superscript_x_size(&self) -> i16 {
        let range = self.shape.y_superscript_x_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended vertical size in font design units for superscripts
    /// for this font.
    pub fn y_superscript_y_size(&self) -> i16 {
        let range = self.shape.y_superscript_y_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended horizontal offset in font design units for superscripts
    /// for this font.
    pub fn y_superscript_x_offset(&self) -> i16 {
        let range = self.shape.y_superscript_x_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The recommended vertical offset in font design units for superscripts
    /// for this font.
    pub fn y_superscript_y_offset(&self) -> i16 {
        let range = self.shape.y_superscript_y_offset_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Thickness of the strikeout stroke in font design units.
    pub fn y_strikeout_size(&self) -> i16 {
        let range = self.shape.y_strikeout_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The position of the top of the strikeout stroke relative to the
    /// baseline in font design units.
    pub fn y_strikeout_position(&self) -> i16 {
        let range = self.shape.y_strikeout_position_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// [Font-family class and subclass](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#sfamilyclass).
    /// This parameter is a classification of font-family design.
    pub fn s_family_class(&self) -> i16 {
        let range = self.shape.s_family_class_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// [PANOSE classification number](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#panose).
    ///
    /// Additional specifications are required for PANOSE to classify non-Latin
    /// character sets.
    pub fn panose_10(&self) -> &'a [u8] {
        let range = self.shape.panose_10_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// [Unicode Character Range](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1-bits-031ulunicoderange2-bits-3263ulunicoderange3-bits-6495ulunicoderange4-bits-96127).
    ///
    /// Unicode Character Range (bits 0-31).
    pub fn ul_unicode_range_1(&self) -> u32 {
        let range = self.shape.ul_unicode_range_1_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Unicode Character Range (bits 32-63).
    pub fn ul_unicode_range_2(&self) -> u32 {
        let range = self.shape.ul_unicode_range_2_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Unicode Character Range (bits 64-95).
    pub fn ul_unicode_range_3(&self) -> u32 {
        let range = self.shape.ul_unicode_range_3_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Unicode Character Range (bits 96-127).
    pub fn ul_unicode_range_4(&self) -> u32 {
        let range = self.shape.ul_unicode_range_4_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// [Font Vendor Identification](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#achvendid).
    ///
    /// The four-character identifier for the vendor of the given type face.
    pub fn ach_vend_id(&self) -> Tag {
        let range = self.shape.ach_vend_id_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// [Font selection flags](https://learn.microsoft.com/en-us/typography/opentype/spec/os2#fsselection).
    ///
    /// Contains information concerning the nature of the font patterns.
    pub fn fs_selection(&self) -> SelectionFlags {
        let range = self.shape.fs_selection_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The minimum Unicode index (character code) in this font.
    pub fn us_first_char_index(&self) -> u16 {
        let range = self.shape.us_first_char_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The maximum Unicode index (character code) in this font.
    pub fn us_last_char_index(&self) -> u16 {
        let range = self.shape.us_last_char_index_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The typographic ascender for this font.
    pub fn s_typo_ascender(&self) -> i16 {
        let range = self.shape.s_typo_ascender_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The typographic descender for this font.
    pub fn s_typo_descender(&self) -> i16 {
        let range = self.shape.s_typo_descender_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The typographic line gap for this font.
    pub fn s_typo_line_gap(&self) -> i16 {
        let range = self.shape.s_typo_line_gap_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The “Windows ascender” metric.
    ///
    /// This should be used to specify the height above the baseline for a
    /// clipping region.
    pub fn us_win_ascent(&self) -> u16 {
        let range = self.shape.us_win_ascent_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// The “Windows descender” metric.
    ///
    /// This should be used to specify the vertical extent below the baseline
    /// for a clipping region.
    pub fn us_win_descent(&self) -> u16 {
        let range = self.shape.us_win_descent_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Code page character range bits 0-31.
    pub fn ul_code_page_range_1(&self) -> Option<u32> {
        let range = self.shape.ul_code_page_range_1_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// Code page character range bits 32-63.
    pub fn ul_code_page_range_2(&self) -> Option<u32> {
        let range = self.shape.ul_code_page_range_2_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// This metric specifies the distance between the baseline and the
    /// approximate height of non-ascending lowercase letters measured in
    /// FUnits.
    pub fn sx_height(&self) -> Option<i16> {
        let range = self.shape.sx_height_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// This metric specifies the distance between the baseline and the
    /// approximate height of uppercase letters measured in FUnits.
    pub fn s_cap_height(&self) -> Option<i16> {
        let range = self.shape.s_cap_height_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// This is the Unicode codepoint, in UTF-16 encoding, of a character that
    /// can be used for a default glyph.
    pub fn us_default_char(&self) -> Option<u16> {
        let range = self.shape.us_default_char_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// This is the Unicode codepoint, in UTF-16 encoding, of a character that
    /// can be used as a default break character.
    pub fn us_break_char(&self) -> Option<u16> {
        let range = self.shape.us_break_char_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// This field is used for fonts with multiple optical styles.
    pub fn us_max_context(&self) -> Option<u16> {
        let range = self.shape.us_max_context_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// This field is used for fonts with multiple optical styles.
    pub fn us_lower_optical_point_size(&self) -> Option<u16> {
        let range = self.shape.us_lower_optical_point_size_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }

    /// This field is used for fonts with multiple optical styles.
    pub fn us_upper_optical_point_size(&self) -> Option<u16> {
        let range = self.shape.us_upper_optical_point_size_byte_range()?;
        Some(self.data.read_at(range.start).unwrap())
    }
}

#[cfg(feature = "experimental_traverse")]
impl<'a> SomeTable<'a> for Os2<'a> {
    fn type_name(&self) -> &str {
        "Os2"
    }
    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("x_avg_char_width", self.x_avg_char_width())),
            2usize => Some(Field::new("us_weight_class", self.us_weight_class())),
            3usize => Some(Field::new("us_width_class", self.us_width_class())),
            4usize => Some(Field::new("fs_type", self.fs_type())),
            5usize => Some(Field::new("y_subscript_x_size", self.y_subscript_x_size())),
            6usize => Some(Field::new("y_subscript_y_size", self.y_subscript_y_size())),
            7usize => Some(Field::new(
                "y_subscript_x_offset",
                self.y_subscript_x_offset(),
            )),
            8usize => Some(Field::new(
                "y_subscript_y_offset",
                self.y_subscript_y_offset(),
            )),
            9usize => Some(Field::new(
                "y_superscript_x_size",
                self.y_superscript_x_size(),
            )),
            10usize => Some(Field::new(
                "y_superscript_y_size",
                self.y_superscript_y_size(),
            )),
            11usize => Some(Field::new(
                "y_superscript_x_offset",
                self.y_superscript_x_offset(),
            )),
            12usize => Some(Field::new(
                "y_superscript_y_offset",
                self.y_superscript_y_offset(),
            )),
            13usize => Some(Field::new("y_strikeout_size", self.y_strikeout_size())),
            14usize => Some(Field::new(
                "y_strikeout_position",
                self.y_strikeout_position(),
            )),
            15usize => Some(Field::new("s_family_class", self.s_family_class())),
            16usize => Some(Field::new("panose_10", self.panose_10())),
            17usize => Some(Field::new("ul_unicode_range_1", self.ul_unicode_range_1())),
            18usize => Some(Field::new("ul_unicode_range_2", self.ul_unicode_range_2())),
            19usize => Some(Field::new("ul_unicode_range_3", self.ul_unicode_range_3())),
            20usize => Some(Field::new("ul_unicode_range_4", self.ul_unicode_range_4())),
            21usize => Some(Field::new("ach_vend_id", self.ach_vend_id())),
            22usize => Some(Field::new("fs_selection", self.fs_selection())),
            23usize => Some(Field::new(
                "us_first_char_index",
                self.us_first_char_index(),
            )),
            24usize => Some(Field::new("us_last_char_index", self.us_last_char_index())),
            25usize => Some(Field::new("s_typo_ascender", self.s_typo_ascender())),
            26usize => Some(Field::new("s_typo_descender", self.s_typo_descender())),
            27usize => Some(Field::new("s_typo_line_gap", self.s_typo_line_gap())),
            28usize => Some(Field::new("us_win_ascent", self.us_win_ascent())),
            29usize => Some(Field::new("us_win_descent", self.us_win_descent())),
            30usize if version.compatible(1u16) => Some(Field::new(
                "ul_code_page_range_1",
                self.ul_code_page_range_1().unwrap(),
            )),
            31usize if version.compatible(1u16) => Some(Field::new(
                "ul_code_page_range_2",
                self.ul_code_page_range_2().unwrap(),
            )),
            32usize if version.compatible(2u16) => {
                Some(Field::new("sx_height", self.sx_height().unwrap()))
            }
            33usize if version.compatible(2u16) => {
                Some(Field::new("s_cap_height", self.s_cap_height().unwrap()))
            }
            34usize if version.compatible(2u16) => Some(Field::new(
                "us_default_char",
                self.us_default_char().unwrap(),
            )),
            35usize if version.compatible(2u16) => {
                Some(Field::new("us_break_char", self.us_break_char().unwrap()))
            }
            36usize if version.compatible(2u16) => {
                Some(Field::new("us_max_context", self.us_max_context().unwrap()))
            }
            37usize if version.compatible(5u16) => Some(Field::new(
                "us_lower_optical_point_size",
                self.us_lower_optical_point_size().unwrap(),
            )),
            38usize if version.compatible(5u16) => Some(Field::new(
                "us_upper_optical_point_size",
                self.us_upper_optical_point_size().unwrap(),
            )),
            _ => None,
        }
    }
}

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