read_fonts/generated/
generated_aat.rs

1// THIS FILE IS AUTOGENERATED.
2// Any changes to this file will be overwritten.
3// For more information about how codegen works, see font-codegen/README.md
4
5#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8/// Lookup tables provide a way of looking up information about a glyph index.
9/// The different cmap subtable formats.
10#[derive(Clone)]
11pub enum Lookup<'a> {
12    Format0(Lookup0<'a>),
13    Format2(Lookup2<'a>),
14    Format4(Lookup4<'a>),
15    Format6(Lookup6<'a>),
16    Format8(Lookup8<'a>),
17    Format10(Lookup10<'a>),
18}
19
20impl<'a> Lookup<'a> {
21    ///Return the `FontData` used to resolve offsets for this table.
22    pub fn offset_data(&self) -> FontData<'a> {
23        match self {
24            Self::Format0(item) => item.offset_data(),
25            Self::Format2(item) => item.offset_data(),
26            Self::Format4(item) => item.offset_data(),
27            Self::Format6(item) => item.offset_data(),
28            Self::Format8(item) => item.offset_data(),
29            Self::Format10(item) => item.offset_data(),
30        }
31    }
32
33    /// Format number is set to 0.
34    pub fn format(&self) -> u16 {
35        match self {
36            Self::Format0(item) => item.format(),
37            Self::Format2(item) => item.format(),
38            Self::Format4(item) => item.format(),
39            Self::Format6(item) => item.format(),
40            Self::Format8(item) => item.format(),
41            Self::Format10(item) => item.format(),
42        }
43    }
44}
45
46impl<'a> FontRead<'a> for Lookup<'a> {
47    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
48        let format: u16 = data.read_at(0usize)?;
49        match format {
50            Lookup0Marker::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
51            Lookup2Marker::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
52            Lookup4Marker::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
53            Lookup6Marker::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
54            Lookup8Marker::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
55            Lookup10Marker::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
56            other => Err(ReadError::InvalidFormat(other.into())),
57        }
58    }
59}
60
61impl MinByteRange for Lookup<'_> {
62    fn min_byte_range(&self) -> Range<usize> {
63        match self {
64            Self::Format0(item) => item.min_byte_range(),
65            Self::Format2(item) => item.min_byte_range(),
66            Self::Format4(item) => item.min_byte_range(),
67            Self::Format6(item) => item.min_byte_range(),
68            Self::Format8(item) => item.min_byte_range(),
69            Self::Format10(item) => item.min_byte_range(),
70        }
71    }
72}
73
74#[cfg(feature = "experimental_traverse")]
75impl<'a> Lookup<'a> {
76    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
77        match self {
78            Self::Format0(table) => table,
79            Self::Format2(table) => table,
80            Self::Format4(table) => table,
81            Self::Format6(table) => table,
82            Self::Format8(table) => table,
83            Self::Format10(table) => table,
84        }
85    }
86}
87
88#[cfg(feature = "experimental_traverse")]
89impl std::fmt::Debug for Lookup<'_> {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        self.dyn_inner().fmt(f)
92    }
93}
94
95#[cfg(feature = "experimental_traverse")]
96impl<'a> SomeTable<'a> for Lookup<'a> {
97    fn type_name(&self) -> &str {
98        self.dyn_inner().type_name()
99    }
100    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
101        self.dyn_inner().get_field(idx)
102    }
103}
104
105impl Format<u16> for Lookup0Marker {
106    const FORMAT: u16 = 0;
107}
108
109/// Simple array format. The lookup data is an array of lookup values, indexed
110/// by glyph index.
111#[derive(Debug, Clone, Copy)]
112#[doc(hidden)]
113pub struct Lookup0Marker {
114    values_data_byte_len: usize,
115}
116
117impl Lookup0Marker {
118    pub fn format_byte_range(&self) -> Range<usize> {
119        let start = 0;
120        start..start + u16::RAW_BYTE_LEN
121    }
122
123    pub fn values_data_byte_range(&self) -> Range<usize> {
124        let start = self.format_byte_range().end;
125        start..start + self.values_data_byte_len
126    }
127}
128
129impl MinByteRange for Lookup0Marker {
130    fn min_byte_range(&self) -> Range<usize> {
131        0..self.values_data_byte_range().end
132    }
133}
134
135impl<'a> FontRead<'a> for Lookup0<'a> {
136    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
137        let mut cursor = data.cursor();
138        cursor.advance::<u16>();
139        let values_data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
140        cursor.advance_by(values_data_byte_len);
141        cursor.finish(Lookup0Marker {
142            values_data_byte_len,
143        })
144    }
145}
146
147/// Simple array format. The lookup data is an array of lookup values, indexed
148/// by glyph index.
149pub type Lookup0<'a> = TableRef<'a, Lookup0Marker>;
150
151#[allow(clippy::needless_lifetimes)]
152impl<'a> Lookup0<'a> {
153    /// Format number is set to 0.
154    pub fn format(&self) -> u16 {
155        let range = self.shape.format_byte_range();
156        self.data.read_at(range.start).unwrap()
157    }
158
159    /// Values, indexed by glyph index.
160    pub fn values_data(&self) -> &'a [u8] {
161        let range = self.shape.values_data_byte_range();
162        self.data.read_array(range).unwrap()
163    }
164}
165
166#[cfg(feature = "experimental_traverse")]
167impl<'a> SomeTable<'a> for Lookup0<'a> {
168    fn type_name(&self) -> &str {
169        "Lookup0"
170    }
171    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
172        match idx {
173            0usize => Some(Field::new("format", self.format())),
174            1usize => Some(Field::new("values_data", self.values_data())),
175            _ => None,
176        }
177    }
178}
179
180#[cfg(feature = "experimental_traverse")]
181#[allow(clippy::needless_lifetimes)]
182impl<'a> std::fmt::Debug for Lookup0<'a> {
183    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184        (self as &dyn SomeTable<'a>).fmt(f)
185    }
186}
187
188impl Format<u16> for Lookup2Marker {
189    const FORMAT: u16 = 2;
190}
191
192/// Segment single format. Each non-overlapping segment has a single lookup
193/// value that applies to all glyphs in the segment. A segment is defined as
194/// a contiguous range of glyph indexes.
195#[derive(Debug, Clone, Copy)]
196#[doc(hidden)]
197pub struct Lookup2Marker {
198    segments_data_byte_len: usize,
199}
200
201impl Lookup2Marker {
202    pub fn format_byte_range(&self) -> Range<usize> {
203        let start = 0;
204        start..start + u16::RAW_BYTE_LEN
205    }
206
207    pub fn unit_size_byte_range(&self) -> Range<usize> {
208        let start = self.format_byte_range().end;
209        start..start + u16::RAW_BYTE_LEN
210    }
211
212    pub fn n_units_byte_range(&self) -> Range<usize> {
213        let start = self.unit_size_byte_range().end;
214        start..start + u16::RAW_BYTE_LEN
215    }
216
217    pub fn search_range_byte_range(&self) -> Range<usize> {
218        let start = self.n_units_byte_range().end;
219        start..start + u16::RAW_BYTE_LEN
220    }
221
222    pub fn entry_selector_byte_range(&self) -> Range<usize> {
223        let start = self.search_range_byte_range().end;
224        start..start + u16::RAW_BYTE_LEN
225    }
226
227    pub fn range_shift_byte_range(&self) -> Range<usize> {
228        let start = self.entry_selector_byte_range().end;
229        start..start + u16::RAW_BYTE_LEN
230    }
231
232    pub fn segments_data_byte_range(&self) -> Range<usize> {
233        let start = self.range_shift_byte_range().end;
234        start..start + self.segments_data_byte_len
235    }
236}
237
238impl MinByteRange for Lookup2Marker {
239    fn min_byte_range(&self) -> Range<usize> {
240        0..self.segments_data_byte_range().end
241    }
242}
243
244impl<'a> FontRead<'a> for Lookup2<'a> {
245    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
246        let mut cursor = data.cursor();
247        cursor.advance::<u16>();
248        let unit_size: u16 = cursor.read()?;
249        let n_units: u16 = cursor.read()?;
250        cursor.advance::<u16>();
251        cursor.advance::<u16>();
252        cursor.advance::<u16>();
253        let segments_data_byte_len = (transforms::add_multiply(unit_size, 0_usize, n_units))
254            .checked_mul(u8::RAW_BYTE_LEN)
255            .ok_or(ReadError::OutOfBounds)?;
256        cursor.advance_by(segments_data_byte_len);
257        cursor.finish(Lookup2Marker {
258            segments_data_byte_len,
259        })
260    }
261}
262
263/// Segment single format. Each non-overlapping segment has a single lookup
264/// value that applies to all glyphs in the segment. A segment is defined as
265/// a contiguous range of glyph indexes.
266pub type Lookup2<'a> = TableRef<'a, Lookup2Marker>;
267
268#[allow(clippy::needless_lifetimes)]
269impl<'a> Lookup2<'a> {
270    /// Format number is set to 2.
271    pub fn format(&self) -> u16 {
272        let range = self.shape.format_byte_range();
273        self.data.read_at(range.start).unwrap()
274    }
275
276    /// Size of a lookup unit for this search in bytes.
277    pub fn unit_size(&self) -> u16 {
278        let range = self.shape.unit_size_byte_range();
279        self.data.read_at(range.start).unwrap()
280    }
281
282    /// Number of units of the preceding size to be searched.
283    pub fn n_units(&self) -> u16 {
284        let range = self.shape.n_units_byte_range();
285        self.data.read_at(range.start).unwrap()
286    }
287
288    /// The value of unitSize times the largest power of 2 that is less than or equal to the value of nUnits.
289    pub fn search_range(&self) -> u16 {
290        let range = self.shape.search_range_byte_range();
291        self.data.read_at(range.start).unwrap()
292    }
293
294    /// The log base 2 of the largest power of 2 less than or equal to the value of nUnits.
295    pub fn entry_selector(&self) -> u16 {
296        let range = self.shape.entry_selector_byte_range();
297        self.data.read_at(range.start).unwrap()
298    }
299
300    /// The value of unitSize times the difference of the value of nUnits minus the largest power of 2 less than or equal to the value of nUnits.
301    pub fn range_shift(&self) -> u16 {
302        let range = self.shape.range_shift_byte_range();
303        self.data.read_at(range.start).unwrap()
304    }
305
306    /// Segments.
307    pub fn segments_data(&self) -> &'a [u8] {
308        let range = self.shape.segments_data_byte_range();
309        self.data.read_array(range).unwrap()
310    }
311}
312
313#[cfg(feature = "experimental_traverse")]
314impl<'a> SomeTable<'a> for Lookup2<'a> {
315    fn type_name(&self) -> &str {
316        "Lookup2"
317    }
318    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
319        match idx {
320            0usize => Some(Field::new("format", self.format())),
321            1usize => Some(Field::new("unit_size", self.unit_size())),
322            2usize => Some(Field::new("n_units", self.n_units())),
323            3usize => Some(Field::new("search_range", self.search_range())),
324            4usize => Some(Field::new("entry_selector", self.entry_selector())),
325            5usize => Some(Field::new("range_shift", self.range_shift())),
326            6usize => Some(Field::new("segments_data", self.segments_data())),
327            _ => None,
328        }
329    }
330}
331
332#[cfg(feature = "experimental_traverse")]
333#[allow(clippy::needless_lifetimes)]
334impl<'a> std::fmt::Debug for Lookup2<'a> {
335    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336        (self as &dyn SomeTable<'a>).fmt(f)
337    }
338}
339
340impl Format<u16> for Lookup4Marker {
341    const FORMAT: u16 = 4;
342}
343
344/// Segment array format. A segment mapping is performed (as with Format 2),
345/// but instead of a single lookup value for all the glyphs in the segment,
346/// each glyph in the segment gets its own separate lookup value.
347#[derive(Debug, Clone, Copy)]
348#[doc(hidden)]
349pub struct Lookup4Marker {
350    segments_byte_len: usize,
351}
352
353impl Lookup4Marker {
354    pub fn format_byte_range(&self) -> Range<usize> {
355        let start = 0;
356        start..start + u16::RAW_BYTE_LEN
357    }
358
359    pub fn unit_size_byte_range(&self) -> Range<usize> {
360        let start = self.format_byte_range().end;
361        start..start + u16::RAW_BYTE_LEN
362    }
363
364    pub fn n_units_byte_range(&self) -> Range<usize> {
365        let start = self.unit_size_byte_range().end;
366        start..start + u16::RAW_BYTE_LEN
367    }
368
369    pub fn search_range_byte_range(&self) -> Range<usize> {
370        let start = self.n_units_byte_range().end;
371        start..start + u16::RAW_BYTE_LEN
372    }
373
374    pub fn entry_selector_byte_range(&self) -> Range<usize> {
375        let start = self.search_range_byte_range().end;
376        start..start + u16::RAW_BYTE_LEN
377    }
378
379    pub fn range_shift_byte_range(&self) -> Range<usize> {
380        let start = self.entry_selector_byte_range().end;
381        start..start + u16::RAW_BYTE_LEN
382    }
383
384    pub fn segments_byte_range(&self) -> Range<usize> {
385        let start = self.range_shift_byte_range().end;
386        start..start + self.segments_byte_len
387    }
388}
389
390impl MinByteRange for Lookup4Marker {
391    fn min_byte_range(&self) -> Range<usize> {
392        0..self.segments_byte_range().end
393    }
394}
395
396impl<'a> FontRead<'a> for Lookup4<'a> {
397    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
398        let mut cursor = data.cursor();
399        cursor.advance::<u16>();
400        cursor.advance::<u16>();
401        let n_units: u16 = cursor.read()?;
402        cursor.advance::<u16>();
403        cursor.advance::<u16>();
404        cursor.advance::<u16>();
405        let segments_byte_len = (n_units as usize)
406            .checked_mul(LookupSegment4::RAW_BYTE_LEN)
407            .ok_or(ReadError::OutOfBounds)?;
408        cursor.advance_by(segments_byte_len);
409        cursor.finish(Lookup4Marker { segments_byte_len })
410    }
411}
412
413/// Segment array format. A segment mapping is performed (as with Format 2),
414/// but instead of a single lookup value for all the glyphs in the segment,
415/// each glyph in the segment gets its own separate lookup value.
416pub type Lookup4<'a> = TableRef<'a, Lookup4Marker>;
417
418#[allow(clippy::needless_lifetimes)]
419impl<'a> Lookup4<'a> {
420    /// Format number is set to 4.
421    pub fn format(&self) -> u16 {
422        let range = self.shape.format_byte_range();
423        self.data.read_at(range.start).unwrap()
424    }
425
426    /// Size of a lookup unit for this search in bytes.
427    pub fn unit_size(&self) -> u16 {
428        let range = self.shape.unit_size_byte_range();
429        self.data.read_at(range.start).unwrap()
430    }
431
432    /// Number of units of the preceding size to be searched.
433    pub fn n_units(&self) -> u16 {
434        let range = self.shape.n_units_byte_range();
435        self.data.read_at(range.start).unwrap()
436    }
437
438    /// The value of unitSize times the largest power of 2 that is less than or equal to the value of nUnits.
439    pub fn search_range(&self) -> u16 {
440        let range = self.shape.search_range_byte_range();
441        self.data.read_at(range.start).unwrap()
442    }
443
444    /// The log base 2 of the largest power of 2 less than or equal to the value of nUnits.
445    pub fn entry_selector(&self) -> u16 {
446        let range = self.shape.entry_selector_byte_range();
447        self.data.read_at(range.start).unwrap()
448    }
449
450    /// The value of unitSize times the difference of the value of nUnits minus the largest power of 2 less than or equal to the value of nUnits.
451    pub fn range_shift(&self) -> u16 {
452        let range = self.shape.range_shift_byte_range();
453        self.data.read_at(range.start).unwrap()
454    }
455
456    /// Segments.
457    pub fn segments(&self) -> &'a [LookupSegment4] {
458        let range = self.shape.segments_byte_range();
459        self.data.read_array(range).unwrap()
460    }
461}
462
463#[cfg(feature = "experimental_traverse")]
464impl<'a> SomeTable<'a> for Lookup4<'a> {
465    fn type_name(&self) -> &str {
466        "Lookup4"
467    }
468    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
469        match idx {
470            0usize => Some(Field::new("format", self.format())),
471            1usize => Some(Field::new("unit_size", self.unit_size())),
472            2usize => Some(Field::new("n_units", self.n_units())),
473            3usize => Some(Field::new("search_range", self.search_range())),
474            4usize => Some(Field::new("entry_selector", self.entry_selector())),
475            5usize => Some(Field::new("range_shift", self.range_shift())),
476            6usize => Some(Field::new(
477                "segments",
478                traversal::FieldType::array_of_records(
479                    stringify!(LookupSegment4),
480                    self.segments(),
481                    self.offset_data(),
482                ),
483            )),
484            _ => None,
485        }
486    }
487}
488
489#[cfg(feature = "experimental_traverse")]
490#[allow(clippy::needless_lifetimes)]
491impl<'a> std::fmt::Debug for Lookup4<'a> {
492    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
493        (self as &dyn SomeTable<'a>).fmt(f)
494    }
495}
496
497/// Lookup segment for format 4.
498#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
499#[repr(C)]
500#[repr(packed)]
501pub struct LookupSegment4 {
502    /// Last glyph index in this segment.
503    pub last_glyph: BigEndian<u16>,
504    /// First glyph index in this segment.
505    pub first_glyph: BigEndian<u16>,
506    /// A 16-bit offset from the start of the table to the data.
507    pub value_offset: BigEndian<u16>,
508}
509
510impl LookupSegment4 {
511    /// Last glyph index in this segment.
512    pub fn last_glyph(&self) -> u16 {
513        self.last_glyph.get()
514    }
515
516    /// First glyph index in this segment.
517    pub fn first_glyph(&self) -> u16 {
518        self.first_glyph.get()
519    }
520
521    /// A 16-bit offset from the start of the table to the data.
522    pub fn value_offset(&self) -> u16 {
523        self.value_offset.get()
524    }
525}
526
527impl FixedSize for LookupSegment4 {
528    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
529}
530
531#[cfg(feature = "experimental_traverse")]
532impl<'a> SomeRecord<'a> for LookupSegment4 {
533    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
534        RecordResolver {
535            name: "LookupSegment4",
536            get_field: Box::new(move |idx, _data| match idx {
537                0usize => Some(Field::new("last_glyph", self.last_glyph())),
538                1usize => Some(Field::new("first_glyph", self.first_glyph())),
539                2usize => Some(Field::new("value_offset", self.value_offset())),
540                _ => None,
541            }),
542            data,
543        }
544    }
545}
546
547impl Format<u16> for Lookup6Marker {
548    const FORMAT: u16 = 6;
549}
550
551/// Single table format. The lookup data is a sorted list of
552/// <glyph index,lookup value> pairs.
553#[derive(Debug, Clone, Copy)]
554#[doc(hidden)]
555pub struct Lookup6Marker {
556    entries_data_byte_len: usize,
557}
558
559impl Lookup6Marker {
560    pub fn format_byte_range(&self) -> Range<usize> {
561        let start = 0;
562        start..start + u16::RAW_BYTE_LEN
563    }
564
565    pub fn unit_size_byte_range(&self) -> Range<usize> {
566        let start = self.format_byte_range().end;
567        start..start + u16::RAW_BYTE_LEN
568    }
569
570    pub fn n_units_byte_range(&self) -> Range<usize> {
571        let start = self.unit_size_byte_range().end;
572        start..start + u16::RAW_BYTE_LEN
573    }
574
575    pub fn search_range_byte_range(&self) -> Range<usize> {
576        let start = self.n_units_byte_range().end;
577        start..start + u16::RAW_BYTE_LEN
578    }
579
580    pub fn entry_selector_byte_range(&self) -> Range<usize> {
581        let start = self.search_range_byte_range().end;
582        start..start + u16::RAW_BYTE_LEN
583    }
584
585    pub fn range_shift_byte_range(&self) -> Range<usize> {
586        let start = self.entry_selector_byte_range().end;
587        start..start + u16::RAW_BYTE_LEN
588    }
589
590    pub fn entries_data_byte_range(&self) -> Range<usize> {
591        let start = self.range_shift_byte_range().end;
592        start..start + self.entries_data_byte_len
593    }
594}
595
596impl MinByteRange for Lookup6Marker {
597    fn min_byte_range(&self) -> Range<usize> {
598        0..self.entries_data_byte_range().end
599    }
600}
601
602impl<'a> FontRead<'a> for Lookup6<'a> {
603    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
604        let mut cursor = data.cursor();
605        cursor.advance::<u16>();
606        let unit_size: u16 = cursor.read()?;
607        let n_units: u16 = cursor.read()?;
608        cursor.advance::<u16>();
609        cursor.advance::<u16>();
610        cursor.advance::<u16>();
611        let entries_data_byte_len = (transforms::add_multiply(unit_size, 0_usize, n_units))
612            .checked_mul(u8::RAW_BYTE_LEN)
613            .ok_or(ReadError::OutOfBounds)?;
614        cursor.advance_by(entries_data_byte_len);
615        cursor.finish(Lookup6Marker {
616            entries_data_byte_len,
617        })
618    }
619}
620
621/// Single table format. The lookup data is a sorted list of
622/// <glyph index,lookup value> pairs.
623pub type Lookup6<'a> = TableRef<'a, Lookup6Marker>;
624
625#[allow(clippy::needless_lifetimes)]
626impl<'a> Lookup6<'a> {
627    /// Format number is set to 6.
628    pub fn format(&self) -> u16 {
629        let range = self.shape.format_byte_range();
630        self.data.read_at(range.start).unwrap()
631    }
632
633    /// Size of a lookup unit for this search in bytes.
634    pub fn unit_size(&self) -> u16 {
635        let range = self.shape.unit_size_byte_range();
636        self.data.read_at(range.start).unwrap()
637    }
638
639    /// Number of units of the preceding size to be searched.
640    pub fn n_units(&self) -> u16 {
641        let range = self.shape.n_units_byte_range();
642        self.data.read_at(range.start).unwrap()
643    }
644
645    /// The value of unitSize times the largest power of 2 that is less than or equal to the value of nUnits.
646    pub fn search_range(&self) -> u16 {
647        let range = self.shape.search_range_byte_range();
648        self.data.read_at(range.start).unwrap()
649    }
650
651    /// The log base 2 of the largest power of 2 less than or equal to the value of nUnits.
652    pub fn entry_selector(&self) -> u16 {
653        let range = self.shape.entry_selector_byte_range();
654        self.data.read_at(range.start).unwrap()
655    }
656
657    /// The value of unitSize times the difference of the value of nUnits minus the largest power of 2 less than or equal to the value of nUnits.
658    pub fn range_shift(&self) -> u16 {
659        let range = self.shape.range_shift_byte_range();
660        self.data.read_at(range.start).unwrap()
661    }
662
663    /// Values, indexed by glyph index.
664    pub fn entries_data(&self) -> &'a [u8] {
665        let range = self.shape.entries_data_byte_range();
666        self.data.read_array(range).unwrap()
667    }
668}
669
670#[cfg(feature = "experimental_traverse")]
671impl<'a> SomeTable<'a> for Lookup6<'a> {
672    fn type_name(&self) -> &str {
673        "Lookup6"
674    }
675    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
676        match idx {
677            0usize => Some(Field::new("format", self.format())),
678            1usize => Some(Field::new("unit_size", self.unit_size())),
679            2usize => Some(Field::new("n_units", self.n_units())),
680            3usize => Some(Field::new("search_range", self.search_range())),
681            4usize => Some(Field::new("entry_selector", self.entry_selector())),
682            5usize => Some(Field::new("range_shift", self.range_shift())),
683            6usize => Some(Field::new("entries_data", self.entries_data())),
684            _ => None,
685        }
686    }
687}
688
689#[cfg(feature = "experimental_traverse")]
690#[allow(clippy::needless_lifetimes)]
691impl<'a> std::fmt::Debug for Lookup6<'a> {
692    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
693        (self as &dyn SomeTable<'a>).fmt(f)
694    }
695}
696
697impl Format<u16> for Lookup8Marker {
698    const FORMAT: u16 = 8;
699}
700
701/// Trimmed array format. The lookup data is a simple trimmed array
702/// indexed by glyph index.
703#[derive(Debug, Clone, Copy)]
704#[doc(hidden)]
705pub struct Lookup8Marker {
706    value_array_byte_len: usize,
707}
708
709impl Lookup8Marker {
710    pub fn format_byte_range(&self) -> Range<usize> {
711        let start = 0;
712        start..start + u16::RAW_BYTE_LEN
713    }
714
715    pub fn first_glyph_byte_range(&self) -> Range<usize> {
716        let start = self.format_byte_range().end;
717        start..start + u16::RAW_BYTE_LEN
718    }
719
720    pub fn glyph_count_byte_range(&self) -> Range<usize> {
721        let start = self.first_glyph_byte_range().end;
722        start..start + u16::RAW_BYTE_LEN
723    }
724
725    pub fn value_array_byte_range(&self) -> Range<usize> {
726        let start = self.glyph_count_byte_range().end;
727        start..start + self.value_array_byte_len
728    }
729}
730
731impl MinByteRange for Lookup8Marker {
732    fn min_byte_range(&self) -> Range<usize> {
733        0..self.value_array_byte_range().end
734    }
735}
736
737impl<'a> FontRead<'a> for Lookup8<'a> {
738    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
739        let mut cursor = data.cursor();
740        cursor.advance::<u16>();
741        cursor.advance::<u16>();
742        let glyph_count: u16 = cursor.read()?;
743        let value_array_byte_len = (glyph_count as usize)
744            .checked_mul(u16::RAW_BYTE_LEN)
745            .ok_or(ReadError::OutOfBounds)?;
746        cursor.advance_by(value_array_byte_len);
747        cursor.finish(Lookup8Marker {
748            value_array_byte_len,
749        })
750    }
751}
752
753/// Trimmed array format. The lookup data is a simple trimmed array
754/// indexed by glyph index.
755pub type Lookup8<'a> = TableRef<'a, Lookup8Marker>;
756
757#[allow(clippy::needless_lifetimes)]
758impl<'a> Lookup8<'a> {
759    /// Format number is set to 8.
760    pub fn format(&self) -> u16 {
761        let range = self.shape.format_byte_range();
762        self.data.read_at(range.start).unwrap()
763    }
764
765    /// First glyph index included in the trimmed array.
766    pub fn first_glyph(&self) -> u16 {
767        let range = self.shape.first_glyph_byte_range();
768        self.data.read_at(range.start).unwrap()
769    }
770
771    /// Total number of glyphs (equivalent to the last glyph minus the value
772    /// of firstGlyph plus 1).
773    pub fn glyph_count(&self) -> u16 {
774        let range = self.shape.glyph_count_byte_range();
775        self.data.read_at(range.start).unwrap()
776    }
777
778    /// The lookup values (indexed by the glyph index minus the value of
779    /// firstGlyph). Entries in the value array must be two bytes.
780    pub fn value_array(&self) -> &'a [BigEndian<u16>] {
781        let range = self.shape.value_array_byte_range();
782        self.data.read_array(range).unwrap()
783    }
784}
785
786#[cfg(feature = "experimental_traverse")]
787impl<'a> SomeTable<'a> for Lookup8<'a> {
788    fn type_name(&self) -> &str {
789        "Lookup8"
790    }
791    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
792        match idx {
793            0usize => Some(Field::new("format", self.format())),
794            1usize => Some(Field::new("first_glyph", self.first_glyph())),
795            2usize => Some(Field::new("glyph_count", self.glyph_count())),
796            3usize => Some(Field::new("value_array", self.value_array())),
797            _ => None,
798        }
799    }
800}
801
802#[cfg(feature = "experimental_traverse")]
803#[allow(clippy::needless_lifetimes)]
804impl<'a> std::fmt::Debug for Lookup8<'a> {
805    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
806        (self as &dyn SomeTable<'a>).fmt(f)
807    }
808}
809
810impl Format<u16> for Lookup10Marker {
811    const FORMAT: u16 = 10;
812}
813
814/// Trimmed array format. The lookup data is a simple trimmed array
815/// indexed by glyph index.
816#[derive(Debug, Clone, Copy)]
817#[doc(hidden)]
818pub struct Lookup10Marker {
819    values_data_byte_len: usize,
820}
821
822impl Lookup10Marker {
823    pub fn format_byte_range(&self) -> Range<usize> {
824        let start = 0;
825        start..start + u16::RAW_BYTE_LEN
826    }
827
828    pub fn unit_size_byte_range(&self) -> Range<usize> {
829        let start = self.format_byte_range().end;
830        start..start + u16::RAW_BYTE_LEN
831    }
832
833    pub fn first_glyph_byte_range(&self) -> Range<usize> {
834        let start = self.unit_size_byte_range().end;
835        start..start + u16::RAW_BYTE_LEN
836    }
837
838    pub fn glyph_count_byte_range(&self) -> Range<usize> {
839        let start = self.first_glyph_byte_range().end;
840        start..start + u16::RAW_BYTE_LEN
841    }
842
843    pub fn values_data_byte_range(&self) -> Range<usize> {
844        let start = self.glyph_count_byte_range().end;
845        start..start + self.values_data_byte_len
846    }
847}
848
849impl MinByteRange for Lookup10Marker {
850    fn min_byte_range(&self) -> Range<usize> {
851        0..self.values_data_byte_range().end
852    }
853}
854
855impl<'a> FontRead<'a> for Lookup10<'a> {
856    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
857        let mut cursor = data.cursor();
858        cursor.advance::<u16>();
859        let unit_size: u16 = cursor.read()?;
860        cursor.advance::<u16>();
861        let glyph_count: u16 = cursor.read()?;
862        let values_data_byte_len = (transforms::add_multiply(glyph_count, 0_usize, unit_size))
863            .checked_mul(u8::RAW_BYTE_LEN)
864            .ok_or(ReadError::OutOfBounds)?;
865        cursor.advance_by(values_data_byte_len);
866        cursor.finish(Lookup10Marker {
867            values_data_byte_len,
868        })
869    }
870}
871
872/// Trimmed array format. The lookup data is a simple trimmed array
873/// indexed by glyph index.
874pub type Lookup10<'a> = TableRef<'a, Lookup10Marker>;
875
876#[allow(clippy::needless_lifetimes)]
877impl<'a> Lookup10<'a> {
878    /// Format number is set to 10.
879    pub fn format(&self) -> u16 {
880        let range = self.shape.format_byte_range();
881        self.data.read_at(range.start).unwrap()
882    }
883
884    /// Size of a lookup unit for this lookup table in bytes. Allowed values
885    /// are 1, 2, 4, and 8.
886    pub fn unit_size(&self) -> u16 {
887        let range = self.shape.unit_size_byte_range();
888        self.data.read_at(range.start).unwrap()
889    }
890
891    /// First glyph index included in the trimmed array.
892    pub fn first_glyph(&self) -> u16 {
893        let range = self.shape.first_glyph_byte_range();
894        self.data.read_at(range.start).unwrap()
895    }
896
897    /// Total number of glyphs (equivalent to the last glyph minus the value
898    /// of firstGlyph plus 1).
899    pub fn glyph_count(&self) -> u16 {
900        let range = self.shape.glyph_count_byte_range();
901        self.data.read_at(range.start).unwrap()
902    }
903
904    /// The lookup values (indexed by the glyph index minus the value of
905    /// firstGlyph).
906    pub fn values_data(&self) -> &'a [u8] {
907        let range = self.shape.values_data_byte_range();
908        self.data.read_array(range).unwrap()
909    }
910}
911
912#[cfg(feature = "experimental_traverse")]
913impl<'a> SomeTable<'a> for Lookup10<'a> {
914    fn type_name(&self) -> &str {
915        "Lookup10"
916    }
917    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
918        match idx {
919            0usize => Some(Field::new("format", self.format())),
920            1usize => Some(Field::new("unit_size", self.unit_size())),
921            2usize => Some(Field::new("first_glyph", self.first_glyph())),
922            3usize => Some(Field::new("glyph_count", self.glyph_count())),
923            4usize => Some(Field::new("values_data", self.values_data())),
924            _ => None,
925        }
926    }
927}
928
929#[cfg(feature = "experimental_traverse")]
930#[allow(clippy::needless_lifetimes)]
931impl<'a> std::fmt::Debug for Lookup10<'a> {
932    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
933        (self as &dyn SomeTable<'a>).fmt(f)
934    }
935}
936
937/// Header for a state table.
938#[derive(Debug, Clone, Copy)]
939#[doc(hidden)]
940pub struct StateHeaderMarker {}
941
942impl StateHeaderMarker {
943    pub fn state_size_byte_range(&self) -> Range<usize> {
944        let start = 0;
945        start..start + u16::RAW_BYTE_LEN
946    }
947
948    pub fn class_table_offset_byte_range(&self) -> Range<usize> {
949        let start = self.state_size_byte_range().end;
950        start..start + Offset16::RAW_BYTE_LEN
951    }
952
953    pub fn state_array_offset_byte_range(&self) -> Range<usize> {
954        let start = self.class_table_offset_byte_range().end;
955        start..start + Offset16::RAW_BYTE_LEN
956    }
957
958    pub fn entry_table_offset_byte_range(&self) -> Range<usize> {
959        let start = self.state_array_offset_byte_range().end;
960        start..start + Offset16::RAW_BYTE_LEN
961    }
962}
963
964impl MinByteRange for StateHeaderMarker {
965    fn min_byte_range(&self) -> Range<usize> {
966        0..self.entry_table_offset_byte_range().end
967    }
968}
969
970impl<'a> FontRead<'a> for StateHeader<'a> {
971    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
972        let mut cursor = data.cursor();
973        cursor.advance::<u16>();
974        cursor.advance::<Offset16>();
975        cursor.advance::<Offset16>();
976        cursor.advance::<Offset16>();
977        cursor.finish(StateHeaderMarker {})
978    }
979}
980
981/// Header for a state table.
982pub type StateHeader<'a> = TableRef<'a, StateHeaderMarker>;
983
984#[allow(clippy::needless_lifetimes)]
985impl<'a> StateHeader<'a> {
986    /// Size of a state, in bytes. The size is limited to 8 bits, although the
987    /// field is 16 bits for alignment.
988    pub fn state_size(&self) -> u16 {
989        let range = self.shape.state_size_byte_range();
990        self.data.read_at(range.start).unwrap()
991    }
992
993    /// Byte offset from the beginning of the state table to the class subtable.
994    pub fn class_table_offset(&self) -> Offset16 {
995        let range = self.shape.class_table_offset_byte_range();
996        self.data.read_at(range.start).unwrap()
997    }
998
999    /// Attempt to resolve [`class_table_offset`][Self::class_table_offset].
1000    pub fn class_table(&self) -> Result<ClassSubtable<'a>, ReadError> {
1001        let data = self.data;
1002        self.class_table_offset().resolve(data)
1003    }
1004
1005    /// Byte offset from the beginning of the state table to the state array.
1006    pub fn state_array_offset(&self) -> Offset16 {
1007        let range = self.shape.state_array_offset_byte_range();
1008        self.data.read_at(range.start).unwrap()
1009    }
1010
1011    /// Attempt to resolve [`state_array_offset`][Self::state_array_offset].
1012    pub fn state_array(&self) -> Result<RawBytes<'a>, ReadError> {
1013        let data = self.data;
1014        self.state_array_offset().resolve(data)
1015    }
1016
1017    /// Byte offset from the beginning of the state table to the entry subtable.
1018    pub fn entry_table_offset(&self) -> Offset16 {
1019        let range = self.shape.entry_table_offset_byte_range();
1020        self.data.read_at(range.start).unwrap()
1021    }
1022
1023    /// Attempt to resolve [`entry_table_offset`][Self::entry_table_offset].
1024    pub fn entry_table(&self) -> Result<RawBytes<'a>, ReadError> {
1025        let data = self.data;
1026        self.entry_table_offset().resolve(data)
1027    }
1028}
1029
1030#[cfg(feature = "experimental_traverse")]
1031impl<'a> SomeTable<'a> for StateHeader<'a> {
1032    fn type_name(&self) -> &str {
1033        "StateHeader"
1034    }
1035    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1036        match idx {
1037            0usize => Some(Field::new("state_size", self.state_size())),
1038            1usize => Some(Field::new(
1039                "class_table_offset",
1040                FieldType::offset(self.class_table_offset(), self.class_table()),
1041            )),
1042            2usize => Some(Field::new(
1043                "state_array_offset",
1044                FieldType::offset(self.state_array_offset(), self.state_array()),
1045            )),
1046            3usize => Some(Field::new(
1047                "entry_table_offset",
1048                FieldType::offset(self.entry_table_offset(), self.entry_table()),
1049            )),
1050            _ => None,
1051        }
1052    }
1053}
1054
1055#[cfg(feature = "experimental_traverse")]
1056#[allow(clippy::needless_lifetimes)]
1057impl<'a> std::fmt::Debug for StateHeader<'a> {
1058    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1059        (self as &dyn SomeTable<'a>).fmt(f)
1060    }
1061}
1062
1063/// Maps the glyph indexes of your font into classes.
1064#[derive(Debug, Clone, Copy)]
1065#[doc(hidden)]
1066pub struct ClassSubtableMarker {
1067    class_array_byte_len: usize,
1068}
1069
1070impl ClassSubtableMarker {
1071    pub fn first_glyph_byte_range(&self) -> Range<usize> {
1072        let start = 0;
1073        start..start + u16::RAW_BYTE_LEN
1074    }
1075
1076    pub fn n_glyphs_byte_range(&self) -> Range<usize> {
1077        let start = self.first_glyph_byte_range().end;
1078        start..start + u16::RAW_BYTE_LEN
1079    }
1080
1081    pub fn class_array_byte_range(&self) -> Range<usize> {
1082        let start = self.n_glyphs_byte_range().end;
1083        start..start + self.class_array_byte_len
1084    }
1085}
1086
1087impl MinByteRange for ClassSubtableMarker {
1088    fn min_byte_range(&self) -> Range<usize> {
1089        0..self.class_array_byte_range().end
1090    }
1091}
1092
1093impl<'a> FontRead<'a> for ClassSubtable<'a> {
1094    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1095        let mut cursor = data.cursor();
1096        cursor.advance::<u16>();
1097        let n_glyphs: u16 = cursor.read()?;
1098        let class_array_byte_len = (n_glyphs as usize)
1099            .checked_mul(u8::RAW_BYTE_LEN)
1100            .ok_or(ReadError::OutOfBounds)?;
1101        cursor.advance_by(class_array_byte_len);
1102        cursor.finish(ClassSubtableMarker {
1103            class_array_byte_len,
1104        })
1105    }
1106}
1107
1108/// Maps the glyph indexes of your font into classes.
1109pub type ClassSubtable<'a> = TableRef<'a, ClassSubtableMarker>;
1110
1111#[allow(clippy::needless_lifetimes)]
1112impl<'a> ClassSubtable<'a> {
1113    /// Glyph index of the first glyph in the class table.
1114    pub fn first_glyph(&self) -> u16 {
1115        let range = self.shape.first_glyph_byte_range();
1116        self.data.read_at(range.start).unwrap()
1117    }
1118
1119    /// Number of glyphs in class table.
1120    pub fn n_glyphs(&self) -> u16 {
1121        let range = self.shape.n_glyphs_byte_range();
1122        self.data.read_at(range.start).unwrap()
1123    }
1124
1125    /// The class codes (indexed by glyph index minus firstGlyph). Class codes
1126    /// range from 0 to the value of stateSize minus 1.
1127    pub fn class_array(&self) -> &'a [u8] {
1128        let range = self.shape.class_array_byte_range();
1129        self.data.read_array(range).unwrap()
1130    }
1131}
1132
1133#[cfg(feature = "experimental_traverse")]
1134impl<'a> SomeTable<'a> for ClassSubtable<'a> {
1135    fn type_name(&self) -> &str {
1136        "ClassSubtable"
1137    }
1138    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1139        match idx {
1140            0usize => Some(Field::new("first_glyph", self.first_glyph())),
1141            1usize => Some(Field::new("n_glyphs", self.n_glyphs())),
1142            2usize => Some(Field::new("class_array", self.class_array())),
1143            _ => None,
1144        }
1145    }
1146}
1147
1148#[cfg(feature = "experimental_traverse")]
1149#[allow(clippy::needless_lifetimes)]
1150impl<'a> std::fmt::Debug for ClassSubtable<'a> {
1151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1152        (self as &dyn SomeTable<'a>).fmt(f)
1153    }
1154}
1155
1156/// Used for the `state_array` and `entry_table` fields in [`StateHeader`].
1157#[derive(Debug, Clone, Copy)]
1158#[doc(hidden)]
1159pub struct RawBytesMarker {
1160    data_byte_len: usize,
1161}
1162
1163impl RawBytesMarker {
1164    pub fn data_byte_range(&self) -> Range<usize> {
1165        let start = 0;
1166        start..start + self.data_byte_len
1167    }
1168}
1169
1170impl MinByteRange for RawBytesMarker {
1171    fn min_byte_range(&self) -> Range<usize> {
1172        0..self.data_byte_range().end
1173    }
1174}
1175
1176impl<'a> FontRead<'a> for RawBytes<'a> {
1177    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1178        let mut cursor = data.cursor();
1179        let data_byte_len = cursor.remaining_bytes() / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
1180        cursor.advance_by(data_byte_len);
1181        cursor.finish(RawBytesMarker { data_byte_len })
1182    }
1183}
1184
1185/// Used for the `state_array` and `entry_table` fields in [`StateHeader`].
1186pub type RawBytes<'a> = TableRef<'a, RawBytesMarker>;
1187
1188#[allow(clippy::needless_lifetimes)]
1189impl<'a> RawBytes<'a> {
1190    pub fn data(&self) -> &'a [u8] {
1191        let range = self.shape.data_byte_range();
1192        self.data.read_array(range).unwrap()
1193    }
1194}
1195
1196#[cfg(feature = "experimental_traverse")]
1197impl<'a> SomeTable<'a> for RawBytes<'a> {
1198    fn type_name(&self) -> &str {
1199        "RawBytes"
1200    }
1201    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1202        match idx {
1203            0usize => Some(Field::new("data", self.data())),
1204            _ => None,
1205        }
1206    }
1207}
1208
1209#[cfg(feature = "experimental_traverse")]
1210#[allow(clippy::needless_lifetimes)]
1211impl<'a> std::fmt::Debug for RawBytes<'a> {
1212    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1213        (self as &dyn SomeTable<'a>).fmt(f)
1214    }
1215}
1216
1217/// Header for an extended state table.
1218#[derive(Debug, Clone, Copy)]
1219#[doc(hidden)]
1220pub struct StxHeaderMarker {}
1221
1222impl StxHeaderMarker {
1223    pub fn n_classes_byte_range(&self) -> Range<usize> {
1224        let start = 0;
1225        start..start + u32::RAW_BYTE_LEN
1226    }
1227
1228    pub fn class_table_offset_byte_range(&self) -> Range<usize> {
1229        let start = self.n_classes_byte_range().end;
1230        start..start + Offset32::RAW_BYTE_LEN
1231    }
1232
1233    pub fn state_array_offset_byte_range(&self) -> Range<usize> {
1234        let start = self.class_table_offset_byte_range().end;
1235        start..start + Offset32::RAW_BYTE_LEN
1236    }
1237
1238    pub fn entry_table_offset_byte_range(&self) -> Range<usize> {
1239        let start = self.state_array_offset_byte_range().end;
1240        start..start + Offset32::RAW_BYTE_LEN
1241    }
1242}
1243
1244impl MinByteRange for StxHeaderMarker {
1245    fn min_byte_range(&self) -> Range<usize> {
1246        0..self.entry_table_offset_byte_range().end
1247    }
1248}
1249
1250impl<'a> FontRead<'a> for StxHeader<'a> {
1251    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1252        let mut cursor = data.cursor();
1253        cursor.advance::<u32>();
1254        cursor.advance::<Offset32>();
1255        cursor.advance::<Offset32>();
1256        cursor.advance::<Offset32>();
1257        cursor.finish(StxHeaderMarker {})
1258    }
1259}
1260
1261/// Header for an extended state table.
1262pub type StxHeader<'a> = TableRef<'a, StxHeaderMarker>;
1263
1264#[allow(clippy::needless_lifetimes)]
1265impl<'a> StxHeader<'a> {
1266    /// Number of classes, which is the number of 16-bit entry indices in a single line in the state array.
1267    pub fn n_classes(&self) -> u32 {
1268        let range = self.shape.n_classes_byte_range();
1269        self.data.read_at(range.start).unwrap()
1270    }
1271
1272    /// Byte offset from the beginning of the state table to the class subtable.
1273    pub fn class_table_offset(&self) -> Offset32 {
1274        let range = self.shape.class_table_offset_byte_range();
1275        self.data.read_at(range.start).unwrap()
1276    }
1277
1278    /// Attempt to resolve [`class_table_offset`][Self::class_table_offset].
1279    pub fn class_table(&self) -> Result<LookupU16<'a>, ReadError> {
1280        let data = self.data;
1281        self.class_table_offset().resolve(data)
1282    }
1283
1284    /// Byte offset from the beginning of the state table to the state array.
1285    pub fn state_array_offset(&self) -> Offset32 {
1286        let range = self.shape.state_array_offset_byte_range();
1287        self.data.read_at(range.start).unwrap()
1288    }
1289
1290    /// Attempt to resolve [`state_array_offset`][Self::state_array_offset].
1291    pub fn state_array(&self) -> Result<RawWords<'a>, ReadError> {
1292        let data = self.data;
1293        self.state_array_offset().resolve(data)
1294    }
1295
1296    /// Byte offset from the beginning of the state table to the entry subtable.
1297    pub fn entry_table_offset(&self) -> Offset32 {
1298        let range = self.shape.entry_table_offset_byte_range();
1299        self.data.read_at(range.start).unwrap()
1300    }
1301
1302    /// Attempt to resolve [`entry_table_offset`][Self::entry_table_offset].
1303    pub fn entry_table(&self) -> Result<RawBytes<'a>, ReadError> {
1304        let data = self.data;
1305        self.entry_table_offset().resolve(data)
1306    }
1307}
1308
1309#[cfg(feature = "experimental_traverse")]
1310impl<'a> SomeTable<'a> for StxHeader<'a> {
1311    fn type_name(&self) -> &str {
1312        "StxHeader"
1313    }
1314    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1315        match idx {
1316            0usize => Some(Field::new("n_classes", self.n_classes())),
1317            1usize => Some(Field::new(
1318                "class_table_offset",
1319                FieldType::offset(self.class_table_offset(), self.class_table()),
1320            )),
1321            2usize => Some(Field::new(
1322                "state_array_offset",
1323                FieldType::offset(self.state_array_offset(), self.state_array()),
1324            )),
1325            3usize => Some(Field::new(
1326                "entry_table_offset",
1327                FieldType::offset(self.entry_table_offset(), self.entry_table()),
1328            )),
1329            _ => None,
1330        }
1331    }
1332}
1333
1334#[cfg(feature = "experimental_traverse")]
1335#[allow(clippy::needless_lifetimes)]
1336impl<'a> std::fmt::Debug for StxHeader<'a> {
1337    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1338        (self as &dyn SomeTable<'a>).fmt(f)
1339    }
1340}
1341
1342/// Used for the `state_array` in [`StxHeader`].
1343#[derive(Debug, Clone, Copy)]
1344#[doc(hidden)]
1345pub struct RawWordsMarker {
1346    data_byte_len: usize,
1347}
1348
1349impl RawWordsMarker {
1350    pub fn data_byte_range(&self) -> Range<usize> {
1351        let start = 0;
1352        start..start + self.data_byte_len
1353    }
1354}
1355
1356impl MinByteRange for RawWordsMarker {
1357    fn min_byte_range(&self) -> Range<usize> {
1358        0..self.data_byte_range().end
1359    }
1360}
1361
1362impl<'a> FontRead<'a> for RawWords<'a> {
1363    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1364        let mut cursor = data.cursor();
1365        let data_byte_len = cursor.remaining_bytes() / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
1366        cursor.advance_by(data_byte_len);
1367        cursor.finish(RawWordsMarker { data_byte_len })
1368    }
1369}
1370
1371/// Used for the `state_array` in [`StxHeader`].
1372pub type RawWords<'a> = TableRef<'a, RawWordsMarker>;
1373
1374#[allow(clippy::needless_lifetimes)]
1375impl<'a> RawWords<'a> {
1376    pub fn data(&self) -> &'a [BigEndian<u16>] {
1377        let range = self.shape.data_byte_range();
1378        self.data.read_array(range).unwrap()
1379    }
1380}
1381
1382#[cfg(feature = "experimental_traverse")]
1383impl<'a> SomeTable<'a> for RawWords<'a> {
1384    fn type_name(&self) -> &str {
1385        "RawWords"
1386    }
1387    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1388        match idx {
1389            0usize => Some(Field::new("data", self.data())),
1390            _ => None,
1391        }
1392    }
1393}
1394
1395#[cfg(feature = "experimental_traverse")]
1396#[allow(clippy::needless_lifetimes)]
1397impl<'a> std::fmt::Debug for RawWords<'a> {
1398    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1399        (self as &dyn SomeTable<'a>).fmt(f)
1400    }
1401}