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

/// An array of variable-sized objects in a `CFF` table.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct Index1Marker {
    offsets_byte_len: usize,
    data_byte_len: usize,
}

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

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

    pub fn offsets_byte_range(&self) -> Range<usize> {
        let start = self.off_size_byte_range().end;
        start..start + self.offsets_byte_len
    }

    pub fn data_byte_range(&self) -> Range<usize> {
        let start = self.offsets_byte_range().end;
        start..start + self.data_byte_len
    }
}

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

impl<'a> FontRead<'a> for Index1<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let count: u16 = cursor.read()?;
        let off_size: u8 = cursor.read()?;
        let offsets_byte_len = (transforms::add_multiply(count, 1_usize, off_size))
            .checked_mul(u8::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(offsets_byte_len);
        let data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
        cursor.advance_by(data_byte_len);
        cursor.finish(Index1Marker {
            offsets_byte_len,
            data_byte_len,
        })
    }
}

/// An array of variable-sized objects in a `CFF` table.
pub type Index1<'a> = TableRef<'a, Index1Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> Index1<'a> {
    /// Number of objects stored in INDEX.
    pub fn count(&self) -> u16 {
        let range = self.shape.count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Object array element size.
    pub fn off_size(&self) -> u8 {
        let range = self.shape.off_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Bytes containing `count + 1` offsets each of `off_size`.
    pub fn offsets(&self) -> &'a [u8] {
        let range = self.shape.offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Array containing the object data.
    pub fn data(&self) -> &'a [u8] {
        let range = self.shape.data_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// An array of variable-sized objects in a `CFF2` table.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct Index2Marker {
    offsets_byte_len: usize,
    data_byte_len: usize,
}

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

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

    pub fn offsets_byte_range(&self) -> Range<usize> {
        let start = self.off_size_byte_range().end;
        start..start + self.offsets_byte_len
    }

    pub fn data_byte_range(&self) -> Range<usize> {
        let start = self.offsets_byte_range().end;
        start..start + self.data_byte_len
    }
}

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

impl<'a> FontRead<'a> for Index2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        let count: u32 = cursor.read()?;
        let off_size: u8 = cursor.read()?;
        let offsets_byte_len = (transforms::add_multiply(count, 1_usize, off_size))
            .checked_mul(u8::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(offsets_byte_len);
        let data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
        cursor.advance_by(data_byte_len);
        cursor.finish(Index2Marker {
            offsets_byte_len,
            data_byte_len,
        })
    }
}

/// An array of variable-sized objects in a `CFF2` table.
pub type Index2<'a> = TableRef<'a, Index2Marker>;

#[allow(clippy::needless_lifetimes)]
impl<'a> Index2<'a> {
    /// Number of objects stored in INDEX.
    pub fn count(&self) -> u32 {
        let range = self.shape.count_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Object array element size.
    pub fn off_size(&self) -> u8 {
        let range = self.shape.off_size_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Bytes containing `count + 1` offsets each of `off_size`.
    pub fn offsets(&self) -> &'a [u8] {
        let range = self.shape.offsets_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Array containing the object data.
    pub fn data(&self) -> &'a [u8] {
        let range = self.shape.data_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Associates a glyph identifier with a Font DICT.
#[derive(Clone)]
pub enum FdSelect<'a> {
    Format0(FdSelectFormat0<'a>),
    Format3(FdSelectFormat3<'a>),
    Format4(FdSelectFormat4<'a>),
}

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

    /// Format = 0.
    pub fn format(&self) -> u8 {
        match self {
            Self::Format0(item) => item.format(),
            Self::Format3(item) => item.format(),
            Self::Format4(item) => item.format(),
        }
    }
}

impl<'a> FontRead<'a> for FdSelect<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u8 = data.read_at(0usize)?;
        match format {
            FdSelectFormat0Marker::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
            FdSelectFormat3Marker::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
            FdSelectFormat4Marker::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

impl MinByteRange for FdSelect<'_> {
    fn min_byte_range(&self) -> Range<usize> {
        match self {
            Self::Format0(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> FdSelect<'a> {
    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
        match self {
            Self::Format0(table) => table,
            Self::Format3(table) => table,
            Self::Format4(table) => table,
        }
    }
}

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for FdSelect<'_> {
    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 FdSelect<'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<u8> for FdSelectFormat0Marker {
    const FORMAT: u8 = 0;
}

/// FdSelect format 0.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FdSelectFormat0Marker {
    fds_byte_len: usize,
}

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

    pub fn fds_byte_range(&self) -> Range<usize> {
        let start = self.format_byte_range().end;
        start..start + self.fds_byte_len
    }
}

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

impl<'a> FontRead<'a> for FdSelectFormat0<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u8>();
        let fds_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
        cursor.advance_by(fds_byte_len);
        cursor.finish(FdSelectFormat0Marker { fds_byte_len })
    }
}

/// FdSelect format 0.
pub type FdSelectFormat0<'a> = TableRef<'a, FdSelectFormat0Marker>;

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

    /// FD selector array (one entry for each glyph).
    pub fn fds(&self) -> &'a [u8] {
        let range = self.shape.fds_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

impl Format<u8> for FdSelectFormat3Marker {
    const FORMAT: u8 = 3;
}

/// FdSelect format 3.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FdSelectFormat3Marker {
    ranges_byte_len: usize,
}

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

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

    pub fn ranges_byte_range(&self) -> Range<usize> {
        let start = self.n_ranges_byte_range().end;
        start..start + self.ranges_byte_len
    }

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

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

impl<'a> FontRead<'a> for FdSelectFormat3<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u8>();
        let n_ranges: u16 = cursor.read()?;
        let ranges_byte_len = (n_ranges as usize)
            .checked_mul(FdSelectRange3::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(ranges_byte_len);
        cursor.advance::<u16>();
        cursor.finish(FdSelectFormat3Marker { ranges_byte_len })
    }
}

/// FdSelect format 3.
pub type FdSelectFormat3<'a> = TableRef<'a, FdSelectFormat3Marker>;

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

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

    /// Range3 array.
    pub fn ranges(&self) -> &'a [FdSelectRange3] {
        let range = self.shape.ranges_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Sentinel GID. Set equal to the number of glyphs in the font.
    pub fn sentinel(&self) -> u16 {
        let range = self.shape.sentinel_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

/// Range struct for FdSelect format 3.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FdSelectRange3 {
    /// First glyph index in range.
    pub first: BigEndian<u16>,
    /// FD index for all glyphs in range.
    pub fd: u8,
}

impl FdSelectRange3 {
    /// First glyph index in range.
    pub fn first(&self) -> u16 {
        self.first.get()
    }

    /// FD index for all glyphs in range.
    pub fn fd(&self) -> u8 {
        self.fd
    }
}

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

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

impl Format<u8> for FdSelectFormat4Marker {
    const FORMAT: u8 = 4;
}

/// FdSelect format 4.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct FdSelectFormat4Marker {
    ranges_byte_len: usize,
}

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

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

    pub fn ranges_byte_range(&self) -> Range<usize> {
        let start = self.n_ranges_byte_range().end;
        start..start + self.ranges_byte_len
    }

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

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

impl<'a> FontRead<'a> for FdSelectFormat4<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u8>();
        let n_ranges: u32 = cursor.read()?;
        let ranges_byte_len = (n_ranges as usize)
            .checked_mul(FdSelectRange4::RAW_BYTE_LEN)
            .ok_or(ReadError::OutOfBounds)?;
        cursor.advance_by(ranges_byte_len);
        cursor.advance::<u32>();
        cursor.finish(FdSelectFormat4Marker { ranges_byte_len })
    }
}

/// FdSelect format 4.
pub type FdSelectFormat4<'a> = TableRef<'a, FdSelectFormat4Marker>;

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

    /// Number of ranges.
    pub fn n_ranges(&self) -> u32 {
        let range = self.shape.n_ranges_byte_range();
        self.data.read_at(range.start).unwrap()
    }

    /// Range4 array.
    pub fn ranges(&self) -> &'a [FdSelectRange4] {
        let range = self.shape.ranges_byte_range();
        self.data.read_array(range).unwrap()
    }

    /// Sentinel GID. Set equal to the number of glyphs in the font.
    pub fn sentinel(&self) -> u32 {
        let range = self.shape.sentinel_byte_range();
        self.data.read_at(range.start).unwrap()
    }
}

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

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

/// Range struct for FdSelect format 4.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct FdSelectRange4 {
    /// First glyph index in range.
    pub first: BigEndian<u32>,
    /// FD index for all glyphs in range.
    pub fd: BigEndian<u16>,
}

impl FdSelectRange4 {
    /// First glyph index in range.
    pub fn first(&self) -> u32 {
        self.first.get()
    }

    /// FD index for all glyphs in range.
    pub fn fd(&self) -> u16 {
        self.fd.get()
    }
}

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

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

/// Charset with custom glyph id to string id mappings.
#[derive(Clone)]
pub enum CustomCharset<'a> {
    Format0(CharsetFormat0<'a>),
    Format1(CharsetFormat1<'a>),
    Format2(CharsetFormat2<'a>),
}

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

    /// Format; =0
    pub fn format(&self) -> u8 {
        match self {
            Self::Format0(item) => item.format(),
            Self::Format1(item) => item.format(),
            Self::Format2(item) => item.format(),
        }
    }
}

impl<'a> FontRead<'a> for CustomCharset<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let format: u8 = data.read_at(0usize)?;
        match format {
            CharsetFormat0Marker::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
            CharsetFormat1Marker::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
            CharsetFormat2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
            other => Err(ReadError::InvalidFormat(other.into())),
        }
    }
}

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

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

#[cfg(feature = "experimental_traverse")]
impl std::fmt::Debug for CustomCharset<'_> {
    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 CustomCharset<'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<u8> for CharsetFormat0Marker {
    const FORMAT: u8 = 0;
}

/// Charset format 0.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CharsetFormat0Marker {
    glyph_byte_len: usize,
}

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

    pub fn glyph_byte_range(&self) -> Range<usize> {
        let start = self.format_byte_range().end;
        start..start + self.glyph_byte_len
    }
}

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

impl<'a> FontRead<'a> for CharsetFormat0<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u8>();
        let glyph_byte_len = cursor.remaining_bytes() / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
        cursor.advance_by(glyph_byte_len);
        cursor.finish(CharsetFormat0Marker { glyph_byte_len })
    }
}

/// Charset format 0.
pub type CharsetFormat0<'a> = TableRef<'a, CharsetFormat0Marker>;

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

    /// Glyph name array.
    pub fn glyph(&self) -> &'a [BigEndian<u16>] {
        let range = self.shape.glyph_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

impl Format<u8> for CharsetFormat1Marker {
    const FORMAT: u8 = 1;
}

/// Charset format 1.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CharsetFormat1Marker {
    ranges_byte_len: usize,
}

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

    pub fn ranges_byte_range(&self) -> Range<usize> {
        let start = self.format_byte_range().end;
        start..start + self.ranges_byte_len
    }
}

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

impl<'a> FontRead<'a> for CharsetFormat1<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u8>();
        let ranges_byte_len =
            cursor.remaining_bytes() / CharsetRange1::RAW_BYTE_LEN * CharsetRange1::RAW_BYTE_LEN;
        cursor.advance_by(ranges_byte_len);
        cursor.finish(CharsetFormat1Marker { ranges_byte_len })
    }
}

/// Charset format 1.
pub type CharsetFormat1<'a> = TableRef<'a, CharsetFormat1Marker>;

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

    /// Range1 array.
    pub fn ranges(&self) -> &'a [CharsetRange1] {
        let range = self.shape.ranges_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Range struct for Charset format 1.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct CharsetRange1 {
    /// First glyph in range.
    pub first: BigEndian<u16>,
    /// Glyphs left in range (excluding first).
    pub n_left: u8,
}

impl CharsetRange1 {
    /// First glyph in range.
    pub fn first(&self) -> u16 {
        self.first.get()
    }

    /// Glyphs left in range (excluding first).
    pub fn n_left(&self) -> u8 {
        self.n_left
    }
}

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

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

impl Format<u8> for CharsetFormat2Marker {
    const FORMAT: u8 = 2;
}

/// Charset format 2.
#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
pub struct CharsetFormat2Marker {
    ranges_byte_len: usize,
}

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

    pub fn ranges_byte_range(&self) -> Range<usize> {
        let start = self.format_byte_range().end;
        start..start + self.ranges_byte_len
    }
}

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

impl<'a> FontRead<'a> for CharsetFormat2<'a> {
    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
        let mut cursor = data.cursor();
        cursor.advance::<u8>();
        let ranges_byte_len =
            cursor.remaining_bytes() / CharsetRange2::RAW_BYTE_LEN * CharsetRange2::RAW_BYTE_LEN;
        cursor.advance_by(ranges_byte_len);
        cursor.finish(CharsetFormat2Marker { ranges_byte_len })
    }
}

/// Charset format 2.
pub type CharsetFormat2<'a> = TableRef<'a, CharsetFormat2Marker>;

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

    /// Range2 array.
    pub fn ranges(&self) -> &'a [CharsetRange2] {
        let range = self.shape.ranges_byte_range();
        self.data.read_array(range).unwrap()
    }
}

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

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

/// Range struct for Charset format 2.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
#[repr(C)]
#[repr(packed)]
pub struct CharsetRange2 {
    /// First glyph in range.
    pub first: BigEndian<u16>,
    /// Glyphs left in range (excluding first).
    pub n_left: BigEndian<u16>,
}

impl CharsetRange2 {
    /// First glyph in range.
    pub fn first(&self) -> u16 {
        self.first.get()
    }

    /// Glyphs left in range (excluding first).
    pub fn n_left(&self) -> u16 {
        self.n_left.get()
    }
}

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

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