Skip to main content

read_fonts/generated/
generated_layout.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
8impl<'a> MinByteRange<'a> for ScriptList<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.script_records_byte_range().end
11    }
12    fn min_table_bytes(&self) -> &'a [u8] {
13        let range = self.min_byte_range();
14        self.data.as_bytes().get(range).unwrap_or_default()
15    }
16}
17
18impl<'a> FontRead<'a> for ScriptList<'a> {
19    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
20        #[allow(clippy::absurd_extreme_comparisons)]
21        if data.len() < Self::MIN_SIZE {
22            return Err(ReadError::OutOfBounds);
23        }
24        Ok(Self { data })
25    }
26}
27
28/// [Script List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
29#[derive(Clone)]
30pub struct ScriptList<'a> {
31    data: FontData<'a>,
32}
33
34#[allow(clippy::needless_lifetimes)]
35impl<'a> ScriptList<'a> {
36    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
37    basic_table_impls!(impl_the_methods);
38
39    /// Number of ScriptRecords
40    pub fn script_count(&self) -> u16 {
41        let range = self.script_count_byte_range();
42        self.data.read_at(range.start).ok().unwrap()
43    }
44
45    /// Array of ScriptRecords, listed alphabetically by script tag
46    pub fn script_records(&self) -> &'a [ScriptRecord] {
47        let range = self.script_records_byte_range();
48        self.data.read_array(range).ok().unwrap_or_default()
49    }
50
51    pub fn script_count_byte_range(&self) -> Range<usize> {
52        let start = 0;
53        start..start + u16::RAW_BYTE_LEN
54    }
55
56    pub fn script_records_byte_range(&self) -> Range<usize> {
57        let script_count = self.script_count();
58        let start = self.script_count_byte_range().end;
59        start..start + (script_count as usize).saturating_mul(ScriptRecord::RAW_BYTE_LEN)
60    }
61}
62
63const _: () = assert!(FontData::default_data_long_enough(ScriptList::MIN_SIZE));
64
65impl Default for ScriptList<'_> {
66    fn default() -> Self {
67        Self {
68            data: FontData::default_table_data(),
69        }
70    }
71}
72
73#[cfg(feature = "experimental_traverse")]
74impl<'a> SomeTable<'a> for ScriptList<'a> {
75    fn type_name(&self) -> &str {
76        "ScriptList"
77    }
78    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
79        match idx {
80            0usize => Some(Field::new("script_count", self.script_count())),
81            1usize => Some(Field::new(
82                "script_records",
83                traversal::FieldType::array_of_records(
84                    stringify!(ScriptRecord),
85                    self.script_records(),
86                    self.offset_data(),
87                ),
88            )),
89            _ => None,
90        }
91    }
92}
93
94#[cfg(feature = "experimental_traverse")]
95#[allow(clippy::needless_lifetimes)]
96impl<'a> std::fmt::Debug for ScriptList<'a> {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        (self as &dyn SomeTable<'a>).fmt(f)
99    }
100}
101
102/// [Script Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-list-table-and-script-record)
103#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
104#[repr(C)]
105#[repr(packed)]
106pub struct ScriptRecord {
107    /// 4-byte script tag identifier
108    pub script_tag: BigEndian<Tag>,
109    /// Offset to Script table, from beginning of ScriptList
110    pub script_offset: BigEndian<Offset16>,
111}
112
113impl ScriptRecord {
114    /// 4-byte script tag identifier
115    pub fn script_tag(&self) -> Tag {
116        self.script_tag.get()
117    }
118
119    /// Offset to Script table, from beginning of ScriptList
120    pub fn script_offset(&self) -> Offset16 {
121        self.script_offset.get()
122    }
123
124    /// Offset to Script table, from beginning of ScriptList
125    ///
126    /// The `data` argument should be retrieved from the parent table
127    /// By calling its `offset_data` method.
128    pub fn script<'a>(&self, data: FontData<'a>) -> Result<Script<'a>, ReadError> {
129        self.script_offset().resolve(data)
130    }
131}
132
133impl FixedSize for ScriptRecord {
134    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
135}
136
137#[cfg(feature = "experimental_traverse")]
138impl<'a> SomeRecord<'a> for ScriptRecord {
139    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
140        RecordResolver {
141            name: "ScriptRecord",
142            get_field: Box::new(move |idx, _data| match idx {
143                0usize => Some(Field::new("script_tag", self.script_tag())),
144                1usize => Some(Field::new(
145                    "script_offset",
146                    FieldType::offset(self.script_offset(), self.script(_data)),
147                )),
148                _ => None,
149            }),
150            data,
151        }
152    }
153}
154
155impl<'a> MinByteRange<'a> for Script<'a> {
156    fn min_byte_range(&self) -> Range<usize> {
157        0..self.lang_sys_records_byte_range().end
158    }
159    fn min_table_bytes(&self) -> &'a [u8] {
160        let range = self.min_byte_range();
161        self.data.as_bytes().get(range).unwrap_or_default()
162    }
163}
164
165impl<'a> FontRead<'a> for Script<'a> {
166    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
167        #[allow(clippy::absurd_extreme_comparisons)]
168        if data.len() < Self::MIN_SIZE {
169            return Err(ReadError::OutOfBounds);
170        }
171        Ok(Self { data })
172    }
173}
174
175/// [Script Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#script-table-and-language-system-record)
176#[derive(Clone)]
177pub struct Script<'a> {
178    data: FontData<'a>,
179}
180
181#[allow(clippy::needless_lifetimes)]
182impl<'a> Script<'a> {
183    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
184    basic_table_impls!(impl_the_methods);
185
186    /// Offset to default LangSys table, from beginning of Script table
187    /// — may be NULL
188    pub fn default_lang_sys_offset(&self) -> Nullable<Offset16> {
189        let range = self.default_lang_sys_offset_byte_range();
190        self.data.read_at(range.start).ok().unwrap()
191    }
192
193    /// Attempt to resolve [`default_lang_sys_offset`][Self::default_lang_sys_offset].
194    pub fn default_lang_sys(&self) -> Option<Result<LangSys<'a>, ReadError>> {
195        let data = self.data;
196        self.default_lang_sys_offset().resolve(data)
197    }
198
199    /// Number of LangSysRecords for this script — excluding the
200    /// default LangSys
201    pub fn lang_sys_count(&self) -> u16 {
202        let range = self.lang_sys_count_byte_range();
203        self.data.read_at(range.start).ok().unwrap()
204    }
205
206    /// Array of LangSysRecords, listed alphabetically by LangSys tag
207    pub fn lang_sys_records(&self) -> &'a [LangSysRecord] {
208        let range = self.lang_sys_records_byte_range();
209        self.data.read_array(range).ok().unwrap_or_default()
210    }
211
212    pub fn default_lang_sys_offset_byte_range(&self) -> Range<usize> {
213        let start = 0;
214        start..start + Offset16::RAW_BYTE_LEN
215    }
216
217    pub fn lang_sys_count_byte_range(&self) -> Range<usize> {
218        let start = self.default_lang_sys_offset_byte_range().end;
219        start..start + u16::RAW_BYTE_LEN
220    }
221
222    pub fn lang_sys_records_byte_range(&self) -> Range<usize> {
223        let lang_sys_count = self.lang_sys_count();
224        let start = self.lang_sys_count_byte_range().end;
225        start..start + (lang_sys_count as usize).saturating_mul(LangSysRecord::RAW_BYTE_LEN)
226    }
227}
228
229const _: () = assert!(FontData::default_data_long_enough(Script::MIN_SIZE));
230
231impl Default for Script<'_> {
232    fn default() -> Self {
233        Self {
234            data: FontData::default_table_data(),
235        }
236    }
237}
238
239#[cfg(feature = "experimental_traverse")]
240impl<'a> SomeTable<'a> for Script<'a> {
241    fn type_name(&self) -> &str {
242        "Script"
243    }
244    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
245        match idx {
246            0usize => Some(Field::new(
247                "default_lang_sys_offset",
248                FieldType::offset(self.default_lang_sys_offset(), self.default_lang_sys()),
249            )),
250            1usize => Some(Field::new("lang_sys_count", self.lang_sys_count())),
251            2usize => Some(Field::new(
252                "lang_sys_records",
253                traversal::FieldType::array_of_records(
254                    stringify!(LangSysRecord),
255                    self.lang_sys_records(),
256                    self.offset_data(),
257                ),
258            )),
259            _ => None,
260        }
261    }
262}
263
264#[cfg(feature = "experimental_traverse")]
265#[allow(clippy::needless_lifetimes)]
266impl<'a> std::fmt::Debug for Script<'a> {
267    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
268        (self as &dyn SomeTable<'a>).fmt(f)
269    }
270}
271
272#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
273#[repr(C)]
274#[repr(packed)]
275pub struct LangSysRecord {
276    /// 4-byte LangSysTag identifier
277    pub lang_sys_tag: BigEndian<Tag>,
278    /// Offset to LangSys table, from beginning of Script table
279    pub lang_sys_offset: BigEndian<Offset16>,
280}
281
282impl LangSysRecord {
283    /// 4-byte LangSysTag identifier
284    pub fn lang_sys_tag(&self) -> Tag {
285        self.lang_sys_tag.get()
286    }
287
288    /// Offset to LangSys table, from beginning of Script table
289    pub fn lang_sys_offset(&self) -> Offset16 {
290        self.lang_sys_offset.get()
291    }
292
293    /// Offset to LangSys table, from beginning of Script table
294    ///
295    /// The `data` argument should be retrieved from the parent table
296    /// By calling its `offset_data` method.
297    pub fn lang_sys<'a>(&self, data: FontData<'a>) -> Result<LangSys<'a>, ReadError> {
298        self.lang_sys_offset().resolve(data)
299    }
300}
301
302impl FixedSize for LangSysRecord {
303    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
304}
305
306#[cfg(feature = "experimental_traverse")]
307impl<'a> SomeRecord<'a> for LangSysRecord {
308    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
309        RecordResolver {
310            name: "LangSysRecord",
311            get_field: Box::new(move |idx, _data| match idx {
312                0usize => Some(Field::new("lang_sys_tag", self.lang_sys_tag())),
313                1usize => Some(Field::new(
314                    "lang_sys_offset",
315                    FieldType::offset(self.lang_sys_offset(), self.lang_sys(_data)),
316                )),
317                _ => None,
318            }),
319            data,
320        }
321    }
322}
323
324impl<'a> MinByteRange<'a> for LangSys<'a> {
325    fn min_byte_range(&self) -> Range<usize> {
326        0..self.feature_indices_byte_range().end
327    }
328    fn min_table_bytes(&self) -> &'a [u8] {
329        let range = self.min_byte_range();
330        self.data.as_bytes().get(range).unwrap_or_default()
331    }
332}
333
334impl<'a> FontRead<'a> for LangSys<'a> {
335    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
336        #[allow(clippy::absurd_extreme_comparisons)]
337        if data.len() < Self::MIN_SIZE {
338            return Err(ReadError::OutOfBounds);
339        }
340        Ok(Self { data })
341    }
342}
343
344/// [Language System Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#language-system-table)
345#[derive(Clone)]
346pub struct LangSys<'a> {
347    data: FontData<'a>,
348}
349
350#[allow(clippy::needless_lifetimes)]
351impl<'a> LangSys<'a> {
352    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
353    basic_table_impls!(impl_the_methods);
354
355    /// Index of a feature required for this language system; if no
356    /// required features = 0xFFFF
357    pub fn required_feature_index(&self) -> u16 {
358        let range = self.required_feature_index_byte_range();
359        self.data.read_at(range.start).ok().unwrap()
360    }
361
362    /// Number of feature index values for this language system —
363    /// excludes the required feature
364    pub fn feature_index_count(&self) -> u16 {
365        let range = self.feature_index_count_byte_range();
366        self.data.read_at(range.start).ok().unwrap()
367    }
368
369    /// Array of indices into the FeatureList, in arbitrary order
370    pub fn feature_indices(&self) -> &'a [BigEndian<u16>] {
371        let range = self.feature_indices_byte_range();
372        self.data.read_array(range).ok().unwrap_or_default()
373    }
374
375    pub fn lookup_order_offset_byte_range(&self) -> Range<usize> {
376        let start = 0;
377        start..start + u16::RAW_BYTE_LEN
378    }
379
380    pub fn required_feature_index_byte_range(&self) -> Range<usize> {
381        let start = self.lookup_order_offset_byte_range().end;
382        start..start + u16::RAW_BYTE_LEN
383    }
384
385    pub fn feature_index_count_byte_range(&self) -> Range<usize> {
386        let start = self.required_feature_index_byte_range().end;
387        start..start + u16::RAW_BYTE_LEN
388    }
389
390    pub fn feature_indices_byte_range(&self) -> Range<usize> {
391        let feature_index_count = self.feature_index_count();
392        let start = self.feature_index_count_byte_range().end;
393        start..start + (feature_index_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
394    }
395}
396
397const _: () = assert!(FontData::default_data_long_enough(LangSys::MIN_SIZE));
398
399impl Default for LangSys<'_> {
400    fn default() -> Self {
401        Self {
402            data: FontData::default_table_data(),
403        }
404    }
405}
406
407#[cfg(feature = "experimental_traverse")]
408impl<'a> SomeTable<'a> for LangSys<'a> {
409    fn type_name(&self) -> &str {
410        "LangSys"
411    }
412    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
413        match idx {
414            0usize => Some(Field::new(
415                "required_feature_index",
416                self.required_feature_index(),
417            )),
418            1usize => Some(Field::new(
419                "feature_index_count",
420                self.feature_index_count(),
421            )),
422            2usize => Some(Field::new("feature_indices", self.feature_indices())),
423            _ => None,
424        }
425    }
426}
427
428#[cfg(feature = "experimental_traverse")]
429#[allow(clippy::needless_lifetimes)]
430impl<'a> std::fmt::Debug for LangSys<'a> {
431    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
432        (self as &dyn SomeTable<'a>).fmt(f)
433    }
434}
435
436impl<'a> MinByteRange<'a> for FeatureList<'a> {
437    fn min_byte_range(&self) -> Range<usize> {
438        0..self.feature_records_byte_range().end
439    }
440    fn min_table_bytes(&self) -> &'a [u8] {
441        let range = self.min_byte_range();
442        self.data.as_bytes().get(range).unwrap_or_default()
443    }
444}
445
446impl<'a> FontRead<'a> for FeatureList<'a> {
447    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
448        #[allow(clippy::absurd_extreme_comparisons)]
449        if data.len() < Self::MIN_SIZE {
450            return Err(ReadError::OutOfBounds);
451        }
452        Ok(Self { data })
453    }
454}
455
456/// [Feature List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-list-table)
457#[derive(Clone)]
458pub struct FeatureList<'a> {
459    data: FontData<'a>,
460}
461
462#[allow(clippy::needless_lifetimes)]
463impl<'a> FeatureList<'a> {
464    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
465    basic_table_impls!(impl_the_methods);
466
467    /// Number of FeatureRecords in this table
468    pub fn feature_count(&self) -> u16 {
469        let range = self.feature_count_byte_range();
470        self.data.read_at(range.start).ok().unwrap()
471    }
472
473    /// Array of FeatureRecords — zero-based (first feature has
474    /// FeatureIndex = 0), listed alphabetically by feature tag
475    pub fn feature_records(&self) -> &'a [FeatureRecord] {
476        let range = self.feature_records_byte_range();
477        self.data.read_array(range).ok().unwrap_or_default()
478    }
479
480    pub fn feature_count_byte_range(&self) -> Range<usize> {
481        let start = 0;
482        start..start + u16::RAW_BYTE_LEN
483    }
484
485    pub fn feature_records_byte_range(&self) -> Range<usize> {
486        let feature_count = self.feature_count();
487        let start = self.feature_count_byte_range().end;
488        start..start + (feature_count as usize).saturating_mul(FeatureRecord::RAW_BYTE_LEN)
489    }
490}
491
492const _: () = assert!(FontData::default_data_long_enough(FeatureList::MIN_SIZE));
493
494impl Default for FeatureList<'_> {
495    fn default() -> Self {
496        Self {
497            data: FontData::default_table_data(),
498        }
499    }
500}
501
502#[cfg(feature = "experimental_traverse")]
503impl<'a> SomeTable<'a> for FeatureList<'a> {
504    fn type_name(&self) -> &str {
505        "FeatureList"
506    }
507    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
508        match idx {
509            0usize => Some(Field::new("feature_count", self.feature_count())),
510            1usize => Some(Field::new(
511                "feature_records",
512                traversal::FieldType::array_of_records(
513                    stringify!(FeatureRecord),
514                    self.feature_records(),
515                    self.offset_data(),
516                ),
517            )),
518            _ => None,
519        }
520    }
521}
522
523#[cfg(feature = "experimental_traverse")]
524#[allow(clippy::needless_lifetimes)]
525impl<'a> std::fmt::Debug for FeatureList<'a> {
526    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
527        (self as &dyn SomeTable<'a>).fmt(f)
528    }
529}
530
531/// Part of [FeatureList]
532#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
533#[repr(C)]
534#[repr(packed)]
535pub struct FeatureRecord {
536    /// 4-byte feature identification tag
537    pub feature_tag: BigEndian<Tag>,
538    /// Offset to Feature table, from beginning of FeatureList
539    pub feature_offset: BigEndian<Offset16>,
540}
541
542impl FeatureRecord {
543    /// 4-byte feature identification tag
544    pub fn feature_tag(&self) -> Tag {
545        self.feature_tag.get()
546    }
547
548    /// Offset to Feature table, from beginning of FeatureList
549    pub fn feature_offset(&self) -> Offset16 {
550        self.feature_offset.get()
551    }
552
553    /// Offset to Feature table, from beginning of FeatureList
554    ///
555    /// The `data` argument should be retrieved from the parent table
556    /// By calling its `offset_data` method.
557    pub fn feature<'a>(&self, data: FontData<'a>) -> Result<Feature<'a>, ReadError> {
558        let args = self.feature_tag();
559        self.feature_offset().resolve_with_args(data, &args)
560    }
561}
562
563impl FixedSize for FeatureRecord {
564    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
565}
566
567#[cfg(feature = "experimental_traverse")]
568impl<'a> SomeRecord<'a> for FeatureRecord {
569    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
570        RecordResolver {
571            name: "FeatureRecord",
572            get_field: Box::new(move |idx, _data| match idx {
573                0usize => Some(Field::new("feature_tag", self.feature_tag())),
574                1usize => Some(Field::new(
575                    "feature_offset",
576                    FieldType::offset(self.feature_offset(), self.feature(_data)),
577                )),
578                _ => None,
579            }),
580            data,
581        }
582    }
583}
584
585impl<'a> MinByteRange<'a> for Feature<'a> {
586    fn min_byte_range(&self) -> Range<usize> {
587        0..self.lookup_list_indices_byte_range().end
588    }
589    fn min_table_bytes(&self) -> &'a [u8] {
590        let range = self.min_byte_range();
591        self.data.as_bytes().get(range).unwrap_or_default()
592    }
593}
594
595impl ReadArgs for Feature<'_> {
596    type Args = Tag;
597}
598
599impl<'a> FontReadWithArgs<'a> for Feature<'a> {
600    fn read_with_args(data: FontData<'a>, args: &Tag) -> Result<Self, ReadError> {
601        let feature_tag = *args;
602
603        #[allow(clippy::absurd_extreme_comparisons)]
604        if data.len() < Self::MIN_SIZE {
605            return Err(ReadError::OutOfBounds);
606        }
607        Ok(Self { data, feature_tag })
608    }
609}
610
611impl<'a> Feature<'a> {
612    /// A constructor that requires additional arguments.
613    ///
614    /// This type requires some external state in order to be
615    /// parsed.
616    pub fn read(data: FontData<'a>, feature_tag: Tag) -> Result<Self, ReadError> {
617        let args = feature_tag;
618        Self::read_with_args(data, &args)
619    }
620}
621
622/// [Feature Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#feature-table)
623#[derive(Clone)]
624pub struct Feature<'a> {
625    data: FontData<'a>,
626    feature_tag: Tag,
627}
628
629#[allow(clippy::needless_lifetimes)]
630impl<'a> Feature<'a> {
631    pub const MIN_SIZE: usize = (Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
632    basic_table_impls!(impl_the_methods);
633
634    /// Offset from start of Feature table to FeatureParams table, if defined for the feature and present, else NULL
635    pub fn feature_params_offset(&self) -> Nullable<Offset16> {
636        let range = self.feature_params_offset_byte_range();
637        self.data.read_at(range.start).ok().unwrap()
638    }
639
640    /// Attempt to resolve [`feature_params_offset`][Self::feature_params_offset].
641    pub fn feature_params(&self) -> Option<Result<FeatureParams<'a>, ReadError>> {
642        let data = self.data;
643        let args = self.feature_tag();
644        self.feature_params_offset().resolve_with_args(data, &args)
645    }
646
647    /// Number of LookupList indices for this feature
648    pub fn lookup_index_count(&self) -> u16 {
649        let range = self.lookup_index_count_byte_range();
650        self.data.read_at(range.start).ok().unwrap()
651    }
652
653    /// Array of indices into the LookupList — zero-based (first
654    /// lookup is LookupListIndex = 0)
655    pub fn lookup_list_indices(&self) -> &'a [BigEndian<u16>] {
656        let range = self.lookup_list_indices_byte_range();
657        self.data.read_array(range).ok().unwrap_or_default()
658    }
659
660    pub(crate) fn feature_tag(&self) -> Tag {
661        self.feature_tag
662    }
663
664    pub fn feature_params_offset_byte_range(&self) -> Range<usize> {
665        let start = 0;
666        start..start + Offset16::RAW_BYTE_LEN
667    }
668
669    pub fn lookup_index_count_byte_range(&self) -> Range<usize> {
670        let start = self.feature_params_offset_byte_range().end;
671        start..start + u16::RAW_BYTE_LEN
672    }
673
674    pub fn lookup_list_indices_byte_range(&self) -> Range<usize> {
675        let lookup_index_count = self.lookup_index_count();
676        let start = self.lookup_index_count_byte_range().end;
677        start..start + (lookup_index_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
678    }
679}
680
681const _: () = assert!(FontData::default_data_long_enough(Feature::MIN_SIZE));
682
683impl Default for Feature<'_> {
684    fn default() -> Self {
685        Self {
686            data: FontData::default_table_data(),
687            feature_tag: Default::default(),
688        }
689    }
690}
691
692#[cfg(feature = "experimental_traverse")]
693impl<'a> SomeTable<'a> for Feature<'a> {
694    fn type_name(&self) -> &str {
695        "Feature"
696    }
697    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
698        match idx {
699            0usize => Some(Field::new(
700                "feature_params_offset",
701                FieldType::offset(self.feature_params_offset(), self.feature_params()),
702            )),
703            1usize => Some(Field::new("lookup_index_count", self.lookup_index_count())),
704            2usize => Some(Field::new(
705                "lookup_list_indices",
706                self.lookup_list_indices(),
707            )),
708            _ => None,
709        }
710    }
711}
712
713#[cfg(feature = "experimental_traverse")]
714#[allow(clippy::needless_lifetimes)]
715impl<'a> std::fmt::Debug for Feature<'a> {
716    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
717        (self as &dyn SomeTable<'a>).fmt(f)
718    }
719}
720
721impl<'a, T> MinByteRange<'a> for LookupList<'a, T> {
722    fn min_byte_range(&self) -> Range<usize> {
723        0..self.lookup_offsets_byte_range().end
724    }
725    fn min_table_bytes(&self) -> &'a [u8] {
726        let range = self.min_byte_range();
727        self.data.as_bytes().get(range).unwrap_or_default()
728    }
729}
730
731impl<'a, T> FontRead<'a> for LookupList<'a, T> {
732    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
733        #[allow(clippy::absurd_extreme_comparisons)]
734        if data.len() < Self::MIN_SIZE {
735            return Err(ReadError::OutOfBounds);
736        }
737        Ok(Self {
738            data,
739            offset_type: std::marker::PhantomData,
740        })
741    }
742}
743
744impl<'a, T> LookupList<'a, T> {
745    #[allow(dead_code)]
746    /// Replace the specific generic type on this implementation with `()`
747    pub(crate) fn of_unit_type(&self) -> LookupList<'a, ()> {
748        LookupList {
749            data: self.data,
750            offset_type: std::marker::PhantomData,
751        }
752    }
753}
754
755/// [Lookup List Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-list-table)
756#[derive(Clone)]
757pub struct LookupList<'a, T = ()> {
758    data: FontData<'a>,
759    offset_type: std::marker::PhantomData<*const T>,
760}
761
762#[allow(clippy::needless_lifetimes)]
763impl<'a, T> LookupList<'a, T> {
764    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
765    basic_table_impls!(impl_the_methods);
766
767    /// Number of lookups in this table
768    pub fn lookup_count(&self) -> u16 {
769        let range = self.lookup_count_byte_range();
770        self.data.read_at(range.start).ok().unwrap()
771    }
772
773    /// Array of offsets to Lookup tables, from beginning of LookupList
774    /// — zero based (first lookup is Lookup index = 0)
775    pub fn lookup_offsets(&self) -> &'a [BigEndian<Offset16>] {
776        let range = self.lookup_offsets_byte_range();
777        self.data.read_array(range).ok().unwrap_or_default()
778    }
779
780    /// A dynamically resolving wrapper for [`lookup_offsets`][Self::lookup_offsets].
781    pub fn lookups(&self) -> ArrayOfOffsets<'a, T, Offset16>
782    where
783        T: FontRead<'a>,
784    {
785        let data = self.data;
786        let offsets = self.lookup_offsets();
787        ArrayOfOffsets::new(offsets, data, ())
788    }
789
790    pub fn lookup_count_byte_range(&self) -> Range<usize> {
791        let start = 0;
792        start..start + u16::RAW_BYTE_LEN
793    }
794
795    pub fn lookup_offsets_byte_range(&self) -> Range<usize> {
796        let lookup_count = self.lookup_count();
797        let start = self.lookup_count_byte_range().end;
798        start..start + (lookup_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
799    }
800}
801
802const _: () = assert!(FontData::default_data_long_enough(
803    LookupList::<()>::MIN_SIZE
804));
805
806impl<T> Default for LookupList<'_, T> {
807    fn default() -> Self {
808        Self {
809            data: FontData::default_table_data(),
810            offset_type: std::marker::PhantomData,
811        }
812    }
813}
814
815#[cfg(feature = "experimental_traverse")]
816impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for LookupList<'a, T> {
817    fn type_name(&self) -> &str {
818        "LookupList"
819    }
820    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
821        match idx {
822            0usize => Some(Field::new("lookup_count", self.lookup_count())),
823            1usize => Some(Field::new(
824                "lookup_offsets",
825                FieldType::from(self.lookups()),
826            )),
827            _ => None,
828        }
829    }
830}
831
832#[cfg(feature = "experimental_traverse")]
833#[allow(clippy::needless_lifetimes)]
834impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for LookupList<'a, T> {
835    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
836        (self as &dyn SomeTable<'a>).fmt(f)
837    }
838}
839
840impl Discriminant for Lookup<'_, ()> {
841    fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
842        data.read_at(0)
843    }
844}
845
846impl<'a, T> MinByteRange<'a> for Lookup<'a, T> {
847    fn min_byte_range(&self) -> Range<usize> {
848        0..self.subtable_offsets_byte_range().end
849    }
850    fn min_table_bytes(&self) -> &'a [u8] {
851        let range = self.min_byte_range();
852        self.data.as_bytes().get(range).unwrap_or_default()
853    }
854}
855
856impl<'a, T> FontRead<'a> for Lookup<'a, T> {
857    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
858        #[allow(clippy::absurd_extreme_comparisons)]
859        if data.len() < Self::MIN_SIZE {
860            return Err(ReadError::OutOfBounds);
861        }
862        Ok(Self {
863            data,
864            offset_type: std::marker::PhantomData,
865        })
866    }
867}
868
869impl<'a, T> Lookup<'a, T> {
870    #[allow(dead_code)]
871    /// Replace the specific generic type on this implementation with `()`
872    pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
873        Lookup {
874            data: self.data,
875            offset_type: std::marker::PhantomData,
876        }
877    }
878}
879
880/// [Lookup Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#lookup-table)
881#[derive(Clone)]
882pub struct Lookup<'a, T = ()> {
883    data: FontData<'a>,
884    offset_type: std::marker::PhantomData<*const T>,
885}
886
887#[allow(clippy::needless_lifetimes)]
888impl<'a, T> Lookup<'a, T> {
889    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + LookupFlag::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
890    basic_table_impls!(impl_the_methods);
891
892    /// Different enumerations for GSUB and GPOS
893    pub fn lookup_type(&self) -> u16 {
894        let range = self.lookup_type_byte_range();
895        self.data.read_at(range.start).ok().unwrap()
896    }
897
898    /// Lookup qualifiers
899    pub fn lookup_flag(&self) -> LookupFlag {
900        let range = self.lookup_flag_byte_range();
901        self.data.read_at(range.start).ok().unwrap()
902    }
903
904    /// Number of subtables for this lookup
905    pub fn sub_table_count(&self) -> u16 {
906        let range = self.sub_table_count_byte_range();
907        self.data.read_at(range.start).ok().unwrap()
908    }
909
910    /// Array of offsets to lookup subtables, from beginning of Lookup
911    /// table
912    pub fn subtable_offsets(&self) -> &'a [BigEndian<Offset16>] {
913        let range = self.subtable_offsets_byte_range();
914        self.data.read_array(range).ok().unwrap_or_default()
915    }
916
917    /// A dynamically resolving wrapper for [`subtable_offsets`][Self::subtable_offsets].
918    pub fn subtables(&self) -> ArrayOfOffsets<'a, T, Offset16>
919    where
920        T: FontRead<'a>,
921    {
922        let data = self.data;
923        let offsets = self.subtable_offsets();
924        ArrayOfOffsets::new(offsets, data, ())
925    }
926
927    /// Index (base 0) into GDEF mark glyph sets structure. This field
928    /// is only present if the USE_MARK_FILTERING_SET lookup flag is
929    /// set.
930    pub fn mark_filtering_set(&self) -> Option<u16> {
931        let range = self.mark_filtering_set_byte_range();
932        (!range.is_empty())
933            .then(|| self.data.read_at(range.start).ok())
934            .flatten()
935    }
936
937    pub fn lookup_type_byte_range(&self) -> Range<usize> {
938        let start = 0;
939        start..start + u16::RAW_BYTE_LEN
940    }
941
942    pub fn lookup_flag_byte_range(&self) -> Range<usize> {
943        let start = self.lookup_type_byte_range().end;
944        start..start + LookupFlag::RAW_BYTE_LEN
945    }
946
947    pub fn sub_table_count_byte_range(&self) -> Range<usize> {
948        let start = self.lookup_flag_byte_range().end;
949        start..start + u16::RAW_BYTE_LEN
950    }
951
952    pub fn subtable_offsets_byte_range(&self) -> Range<usize> {
953        let sub_table_count = self.sub_table_count();
954        let start = self.sub_table_count_byte_range().end;
955        start..start + (sub_table_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
956    }
957
958    pub fn mark_filtering_set_byte_range(&self) -> Range<usize> {
959        let start = self.subtable_offsets_byte_range().end;
960        start
961            ..(self
962                .lookup_flag()
963                .contains(LookupFlag::USE_MARK_FILTERING_SET))
964            .then(|| start + u16::RAW_BYTE_LEN)
965            .unwrap_or(start)
966    }
967}
968
969const _: () = assert!(FontData::default_data_long_enough(Lookup::<()>::MIN_SIZE));
970
971impl<T> Default for Lookup<'_, T> {
972    fn default() -> Self {
973        Self {
974            data: FontData::default_table_data(),
975            offset_type: std::marker::PhantomData,
976        }
977    }
978}
979
980#[cfg(feature = "experimental_traverse")]
981impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> SomeTable<'a> for Lookup<'a, T> {
982    fn type_name(&self) -> &str {
983        "Lookup"
984    }
985    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
986        match idx {
987            0usize => Some(Field::new("lookup_type", self.lookup_type())),
988            1usize => Some(Field::new("lookup_flag", self.traverse_lookup_flag())),
989            2usize => Some(Field::new("sub_table_count", self.sub_table_count())),
990            3usize => Some(Field::new(
991                "subtable_offsets",
992                FieldType::from(self.subtables()),
993            )),
994            4usize
995                if self
996                    .lookup_flag()
997                    .contains(LookupFlag::USE_MARK_FILTERING_SET) =>
998            {
999                Some(Field::new(
1000                    "mark_filtering_set",
1001                    self.mark_filtering_set().unwrap(),
1002                ))
1003            }
1004            _ => None,
1005        }
1006    }
1007}
1008
1009#[cfg(feature = "experimental_traverse")]
1010#[allow(clippy::needless_lifetimes)]
1011impl<'a, T: FontRead<'a> + SomeTable<'a> + 'a> std::fmt::Debug for Lookup<'a, T> {
1012    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1013        (self as &dyn SomeTable<'a>).fmt(f)
1014    }
1015}
1016
1017impl Format<u16> for CoverageFormat1<'_> {
1018    const FORMAT: u16 = 1;
1019}
1020
1021impl<'a> MinByteRange<'a> for CoverageFormat1<'a> {
1022    fn min_byte_range(&self) -> Range<usize> {
1023        0..self.glyph_array_byte_range().end
1024    }
1025    fn min_table_bytes(&self) -> &'a [u8] {
1026        let range = self.min_byte_range();
1027        self.data.as_bytes().get(range).unwrap_or_default()
1028    }
1029}
1030
1031impl<'a> FontRead<'a> for CoverageFormat1<'a> {
1032    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1033        #[allow(clippy::absurd_extreme_comparisons)]
1034        if data.len() < Self::MIN_SIZE {
1035            return Err(ReadError::OutOfBounds);
1036        }
1037        Ok(Self { data })
1038    }
1039}
1040
1041/// [Coverage Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-1)
1042#[derive(Clone)]
1043pub struct CoverageFormat1<'a> {
1044    data: FontData<'a>,
1045}
1046
1047#[allow(clippy::needless_lifetimes)]
1048impl<'a> CoverageFormat1<'a> {
1049    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1050    basic_table_impls!(impl_the_methods);
1051
1052    /// Format identifier — format = 1
1053    pub fn coverage_format(&self) -> u16 {
1054        let range = self.coverage_format_byte_range();
1055        self.data.read_at(range.start).ok().unwrap()
1056    }
1057
1058    /// Number of glyphs in the glyph array
1059    pub fn glyph_count(&self) -> u16 {
1060        let range = self.glyph_count_byte_range();
1061        self.data.read_at(range.start).ok().unwrap()
1062    }
1063
1064    /// Array of glyph IDs — in numerical order
1065    pub fn glyph_array(&self) -> &'a [BigEndian<GlyphId16>] {
1066        let range = self.glyph_array_byte_range();
1067        self.data.read_array(range).ok().unwrap_or_default()
1068    }
1069
1070    pub fn coverage_format_byte_range(&self) -> Range<usize> {
1071        let start = 0;
1072        start..start + u16::RAW_BYTE_LEN
1073    }
1074
1075    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1076        let start = self.coverage_format_byte_range().end;
1077        start..start + u16::RAW_BYTE_LEN
1078    }
1079
1080    pub fn glyph_array_byte_range(&self) -> Range<usize> {
1081        let glyph_count = self.glyph_count();
1082        let start = self.glyph_count_byte_range().end;
1083        start..start + (glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
1084    }
1085}
1086
1087const _: () = assert!(FontData::default_data_long_enough(
1088    CoverageFormat1::MIN_SIZE
1089));
1090
1091impl Default for CoverageFormat1<'_> {
1092    fn default() -> Self {
1093        Self {
1094            data: FontData::default_format_1_u16_table_data(),
1095        }
1096    }
1097}
1098
1099#[cfg(feature = "experimental_traverse")]
1100impl<'a> SomeTable<'a> for CoverageFormat1<'a> {
1101    fn type_name(&self) -> &str {
1102        "CoverageFormat1"
1103    }
1104    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1105        match idx {
1106            0usize => Some(Field::new("coverage_format", self.coverage_format())),
1107            1usize => Some(Field::new("glyph_count", self.glyph_count())),
1108            2usize => Some(Field::new("glyph_array", self.glyph_array())),
1109            _ => None,
1110        }
1111    }
1112}
1113
1114#[cfg(feature = "experimental_traverse")]
1115#[allow(clippy::needless_lifetimes)]
1116impl<'a> std::fmt::Debug for CoverageFormat1<'a> {
1117    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1118        (self as &dyn SomeTable<'a>).fmt(f)
1119    }
1120}
1121
1122impl Format<u16> for CoverageFormat2<'_> {
1123    const FORMAT: u16 = 2;
1124}
1125
1126impl<'a> MinByteRange<'a> for CoverageFormat2<'a> {
1127    fn min_byte_range(&self) -> Range<usize> {
1128        0..self.range_records_byte_range().end
1129    }
1130    fn min_table_bytes(&self) -> &'a [u8] {
1131        let range = self.min_byte_range();
1132        self.data.as_bytes().get(range).unwrap_or_default()
1133    }
1134}
1135
1136impl<'a> FontRead<'a> for CoverageFormat2<'a> {
1137    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1138        #[allow(clippy::absurd_extreme_comparisons)]
1139        if data.len() < Self::MIN_SIZE {
1140            return Err(ReadError::OutOfBounds);
1141        }
1142        Ok(Self { data })
1143    }
1144}
1145
1146/// [Coverage Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-format-2)
1147#[derive(Clone)]
1148pub struct CoverageFormat2<'a> {
1149    data: FontData<'a>,
1150}
1151
1152#[allow(clippy::needless_lifetimes)]
1153impl<'a> CoverageFormat2<'a> {
1154    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1155    basic_table_impls!(impl_the_methods);
1156
1157    /// Format identifier — format = 2
1158    pub fn coverage_format(&self) -> u16 {
1159        let range = self.coverage_format_byte_range();
1160        self.data.read_at(range.start).ok().unwrap()
1161    }
1162
1163    /// Number of RangeRecords
1164    pub fn range_count(&self) -> u16 {
1165        let range = self.range_count_byte_range();
1166        self.data.read_at(range.start).ok().unwrap()
1167    }
1168
1169    /// Array of glyph ranges — ordered by startGlyphID.
1170    pub fn range_records(&self) -> &'a [RangeRecord] {
1171        let range = self.range_records_byte_range();
1172        self.data.read_array(range).ok().unwrap_or_default()
1173    }
1174
1175    pub fn coverage_format_byte_range(&self) -> Range<usize> {
1176        let start = 0;
1177        start..start + u16::RAW_BYTE_LEN
1178    }
1179
1180    pub fn range_count_byte_range(&self) -> Range<usize> {
1181        let start = self.coverage_format_byte_range().end;
1182        start..start + u16::RAW_BYTE_LEN
1183    }
1184
1185    pub fn range_records_byte_range(&self) -> Range<usize> {
1186        let range_count = self.range_count();
1187        let start = self.range_count_byte_range().end;
1188        start..start + (range_count as usize).saturating_mul(RangeRecord::RAW_BYTE_LEN)
1189    }
1190}
1191
1192#[cfg(feature = "experimental_traverse")]
1193impl<'a> SomeTable<'a> for CoverageFormat2<'a> {
1194    fn type_name(&self) -> &str {
1195        "CoverageFormat2"
1196    }
1197    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1198        match idx {
1199            0usize => Some(Field::new("coverage_format", self.coverage_format())),
1200            1usize => Some(Field::new("range_count", self.range_count())),
1201            2usize => Some(Field::new(
1202                "range_records",
1203                traversal::FieldType::array_of_records(
1204                    stringify!(RangeRecord),
1205                    self.range_records(),
1206                    self.offset_data(),
1207                ),
1208            )),
1209            _ => None,
1210        }
1211    }
1212}
1213
1214#[cfg(feature = "experimental_traverse")]
1215#[allow(clippy::needless_lifetimes)]
1216impl<'a> std::fmt::Debug for CoverageFormat2<'a> {
1217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1218        (self as &dyn SomeTable<'a>).fmt(f)
1219    }
1220}
1221
1222/// Used in [CoverageFormat2]
1223#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1224#[repr(C)]
1225#[repr(packed)]
1226pub struct RangeRecord {
1227    /// First glyph ID in the range
1228    pub start_glyph_id: BigEndian<GlyphId16>,
1229    /// Last glyph ID in the range
1230    pub end_glyph_id: BigEndian<GlyphId16>,
1231    /// Coverage Index of first glyph ID in range
1232    pub start_coverage_index: BigEndian<u16>,
1233}
1234
1235impl RangeRecord {
1236    /// First glyph ID in the range
1237    pub fn start_glyph_id(&self) -> GlyphId16 {
1238        self.start_glyph_id.get()
1239    }
1240
1241    /// Last glyph ID in the range
1242    pub fn end_glyph_id(&self) -> GlyphId16 {
1243        self.end_glyph_id.get()
1244    }
1245
1246    /// Coverage Index of first glyph ID in range
1247    pub fn start_coverage_index(&self) -> u16 {
1248        self.start_coverage_index.get()
1249    }
1250}
1251
1252impl FixedSize for RangeRecord {
1253    const RAW_BYTE_LEN: usize =
1254        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1255}
1256
1257#[cfg(feature = "experimental_traverse")]
1258impl<'a> SomeRecord<'a> for RangeRecord {
1259    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1260        RecordResolver {
1261            name: "RangeRecord",
1262            get_field: Box::new(move |idx, _data| match idx {
1263                0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1264                1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
1265                2usize => Some(Field::new(
1266                    "start_coverage_index",
1267                    self.start_coverage_index(),
1268                )),
1269                _ => None,
1270            }),
1271            data,
1272        }
1273    }
1274}
1275
1276/// [Coverage Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#coverage-table)
1277#[derive(Clone)]
1278pub enum CoverageTable<'a> {
1279    Format1(CoverageFormat1<'a>),
1280    Format2(CoverageFormat2<'a>),
1281}
1282
1283impl Default for CoverageTable<'_> {
1284    fn default() -> Self {
1285        Self::Format1(Default::default())
1286    }
1287}
1288
1289impl<'a> CoverageTable<'a> {
1290    ///Return the `FontData` used to resolve offsets for this table.
1291    pub fn offset_data(&self) -> FontData<'a> {
1292        match self {
1293            Self::Format1(item) => item.offset_data(),
1294            Self::Format2(item) => item.offset_data(),
1295        }
1296    }
1297
1298    /// Format identifier — format = 1
1299    pub fn coverage_format(&self) -> u16 {
1300        match self {
1301            Self::Format1(item) => item.coverage_format(),
1302            Self::Format2(item) => item.coverage_format(),
1303        }
1304    }
1305}
1306
1307impl<'a> FontRead<'a> for CoverageTable<'a> {
1308    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1309        let format: u16 = data.read_at(0usize)?;
1310        match format {
1311            CoverageFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1312            CoverageFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1313            other => Err(ReadError::InvalidFormat(other.into())),
1314        }
1315    }
1316}
1317
1318impl<'a> MinByteRange<'a> for CoverageTable<'a> {
1319    fn min_byte_range(&self) -> Range<usize> {
1320        match self {
1321            Self::Format1(item) => item.min_byte_range(),
1322            Self::Format2(item) => item.min_byte_range(),
1323        }
1324    }
1325    fn min_table_bytes(&self) -> &'a [u8] {
1326        match self {
1327            Self::Format1(item) => item.min_table_bytes(),
1328            Self::Format2(item) => item.min_table_bytes(),
1329        }
1330    }
1331}
1332
1333#[cfg(feature = "experimental_traverse")]
1334impl<'a> CoverageTable<'a> {
1335    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1336        match self {
1337            Self::Format1(table) => table,
1338            Self::Format2(table) => table,
1339        }
1340    }
1341}
1342
1343#[cfg(feature = "experimental_traverse")]
1344impl std::fmt::Debug for CoverageTable<'_> {
1345    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1346        self.dyn_inner().fmt(f)
1347    }
1348}
1349
1350#[cfg(feature = "experimental_traverse")]
1351impl<'a> SomeTable<'a> for CoverageTable<'a> {
1352    fn type_name(&self) -> &str {
1353        self.dyn_inner().type_name()
1354    }
1355    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1356        self.dyn_inner().get_field(idx)
1357    }
1358}
1359
1360impl Format<u16> for ClassDefFormat1<'_> {
1361    const FORMAT: u16 = 1;
1362}
1363
1364impl<'a> MinByteRange<'a> for ClassDefFormat1<'a> {
1365    fn min_byte_range(&self) -> Range<usize> {
1366        0..self.class_value_array_byte_range().end
1367    }
1368    fn min_table_bytes(&self) -> &'a [u8] {
1369        let range = self.min_byte_range();
1370        self.data.as_bytes().get(range).unwrap_or_default()
1371    }
1372}
1373
1374impl<'a> FontRead<'a> for ClassDefFormat1<'a> {
1375    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1376        #[allow(clippy::absurd_extreme_comparisons)]
1377        if data.len() < Self::MIN_SIZE {
1378            return Err(ReadError::OutOfBounds);
1379        }
1380        Ok(Self { data })
1381    }
1382}
1383
1384/// [Class Definition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-1)
1385#[derive(Clone)]
1386pub struct ClassDefFormat1<'a> {
1387    data: FontData<'a>,
1388}
1389
1390#[allow(clippy::needless_lifetimes)]
1391impl<'a> ClassDefFormat1<'a> {
1392    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1393    basic_table_impls!(impl_the_methods);
1394
1395    /// Format identifier — format = 1
1396    pub fn class_format(&self) -> u16 {
1397        let range = self.class_format_byte_range();
1398        self.data.read_at(range.start).ok().unwrap()
1399    }
1400
1401    /// First glyph ID of the classValueArray
1402    pub fn start_glyph_id(&self) -> GlyphId16 {
1403        let range = self.start_glyph_id_byte_range();
1404        self.data.read_at(range.start).ok().unwrap()
1405    }
1406
1407    /// Size of the classValueArray
1408    pub fn glyph_count(&self) -> u16 {
1409        let range = self.glyph_count_byte_range();
1410        self.data.read_at(range.start).ok().unwrap()
1411    }
1412
1413    /// Array of Class Values — one per glyph ID
1414    pub fn class_value_array(&self) -> &'a [BigEndian<u16>] {
1415        let range = self.class_value_array_byte_range();
1416        self.data.read_array(range).ok().unwrap_or_default()
1417    }
1418
1419    pub fn class_format_byte_range(&self) -> Range<usize> {
1420        let start = 0;
1421        start..start + u16::RAW_BYTE_LEN
1422    }
1423
1424    pub fn start_glyph_id_byte_range(&self) -> Range<usize> {
1425        let start = self.class_format_byte_range().end;
1426        start..start + GlyphId16::RAW_BYTE_LEN
1427    }
1428
1429    pub fn glyph_count_byte_range(&self) -> Range<usize> {
1430        let start = self.start_glyph_id_byte_range().end;
1431        start..start + u16::RAW_BYTE_LEN
1432    }
1433
1434    pub fn class_value_array_byte_range(&self) -> Range<usize> {
1435        let glyph_count = self.glyph_count();
1436        let start = self.glyph_count_byte_range().end;
1437        start..start + (glyph_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
1438    }
1439}
1440
1441const _: () = assert!(FontData::default_data_long_enough(
1442    ClassDefFormat1::MIN_SIZE
1443));
1444
1445impl Default for ClassDefFormat1<'_> {
1446    fn default() -> Self {
1447        Self {
1448            data: FontData::default_format_1_u16_table_data(),
1449        }
1450    }
1451}
1452
1453#[cfg(feature = "experimental_traverse")]
1454impl<'a> SomeTable<'a> for ClassDefFormat1<'a> {
1455    fn type_name(&self) -> &str {
1456        "ClassDefFormat1"
1457    }
1458    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1459        match idx {
1460            0usize => Some(Field::new("class_format", self.class_format())),
1461            1usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1462            2usize => Some(Field::new("glyph_count", self.glyph_count())),
1463            3usize => Some(Field::new("class_value_array", self.class_value_array())),
1464            _ => None,
1465        }
1466    }
1467}
1468
1469#[cfg(feature = "experimental_traverse")]
1470#[allow(clippy::needless_lifetimes)]
1471impl<'a> std::fmt::Debug for ClassDefFormat1<'a> {
1472    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1473        (self as &dyn SomeTable<'a>).fmt(f)
1474    }
1475}
1476
1477impl Format<u16> for ClassDefFormat2<'_> {
1478    const FORMAT: u16 = 2;
1479}
1480
1481impl<'a> MinByteRange<'a> for ClassDefFormat2<'a> {
1482    fn min_byte_range(&self) -> Range<usize> {
1483        0..self.class_range_records_byte_range().end
1484    }
1485    fn min_table_bytes(&self) -> &'a [u8] {
1486        let range = self.min_byte_range();
1487        self.data.as_bytes().get(range).unwrap_or_default()
1488    }
1489}
1490
1491impl<'a> FontRead<'a> for ClassDefFormat2<'a> {
1492    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1493        #[allow(clippy::absurd_extreme_comparisons)]
1494        if data.len() < Self::MIN_SIZE {
1495            return Err(ReadError::OutOfBounds);
1496        }
1497        Ok(Self { data })
1498    }
1499}
1500
1501/// [Class Definition Table Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table-format-2)
1502#[derive(Clone)]
1503pub struct ClassDefFormat2<'a> {
1504    data: FontData<'a>,
1505}
1506
1507#[allow(clippy::needless_lifetimes)]
1508impl<'a> ClassDefFormat2<'a> {
1509    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1510    basic_table_impls!(impl_the_methods);
1511
1512    /// Format identifier — format = 2
1513    pub fn class_format(&self) -> u16 {
1514        let range = self.class_format_byte_range();
1515        self.data.read_at(range.start).ok().unwrap()
1516    }
1517
1518    /// Number of ClassRangeRecords
1519    pub fn class_range_count(&self) -> u16 {
1520        let range = self.class_range_count_byte_range();
1521        self.data.read_at(range.start).ok().unwrap()
1522    }
1523
1524    /// Array of ClassRangeRecords — ordered by startGlyphID
1525    pub fn class_range_records(&self) -> &'a [ClassRangeRecord] {
1526        let range = self.class_range_records_byte_range();
1527        self.data.read_array(range).ok().unwrap_or_default()
1528    }
1529
1530    pub fn class_format_byte_range(&self) -> Range<usize> {
1531        let start = 0;
1532        start..start + u16::RAW_BYTE_LEN
1533    }
1534
1535    pub fn class_range_count_byte_range(&self) -> Range<usize> {
1536        let start = self.class_format_byte_range().end;
1537        start..start + u16::RAW_BYTE_LEN
1538    }
1539
1540    pub fn class_range_records_byte_range(&self) -> Range<usize> {
1541        let class_range_count = self.class_range_count();
1542        let start = self.class_range_count_byte_range().end;
1543        start..start + (class_range_count as usize).saturating_mul(ClassRangeRecord::RAW_BYTE_LEN)
1544    }
1545}
1546
1547#[cfg(feature = "experimental_traverse")]
1548impl<'a> SomeTable<'a> for ClassDefFormat2<'a> {
1549    fn type_name(&self) -> &str {
1550        "ClassDefFormat2"
1551    }
1552    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1553        match idx {
1554            0usize => Some(Field::new("class_format", self.class_format())),
1555            1usize => Some(Field::new("class_range_count", self.class_range_count())),
1556            2usize => Some(Field::new(
1557                "class_range_records",
1558                traversal::FieldType::array_of_records(
1559                    stringify!(ClassRangeRecord),
1560                    self.class_range_records(),
1561                    self.offset_data(),
1562                ),
1563            )),
1564            _ => None,
1565        }
1566    }
1567}
1568
1569#[cfg(feature = "experimental_traverse")]
1570#[allow(clippy::needless_lifetimes)]
1571impl<'a> std::fmt::Debug for ClassDefFormat2<'a> {
1572    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1573        (self as &dyn SomeTable<'a>).fmt(f)
1574    }
1575}
1576
1577/// Used in [ClassDefFormat2]
1578#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1579#[repr(C)]
1580#[repr(packed)]
1581pub struct ClassRangeRecord {
1582    /// First glyph ID in the range
1583    pub start_glyph_id: BigEndian<GlyphId16>,
1584    /// Last glyph ID in the range
1585    pub end_glyph_id: BigEndian<GlyphId16>,
1586    /// Applied to all glyphs in the range
1587    pub class: BigEndian<u16>,
1588}
1589
1590impl ClassRangeRecord {
1591    /// First glyph ID in the range
1592    pub fn start_glyph_id(&self) -> GlyphId16 {
1593        self.start_glyph_id.get()
1594    }
1595
1596    /// Last glyph ID in the range
1597    pub fn end_glyph_id(&self) -> GlyphId16 {
1598        self.end_glyph_id.get()
1599    }
1600
1601    /// Applied to all glyphs in the range
1602    pub fn class(&self) -> u16 {
1603        self.class.get()
1604    }
1605}
1606
1607impl FixedSize for ClassRangeRecord {
1608    const RAW_BYTE_LEN: usize =
1609        GlyphId16::RAW_BYTE_LEN + GlyphId16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1610}
1611
1612#[cfg(feature = "experimental_traverse")]
1613impl<'a> SomeRecord<'a> for ClassRangeRecord {
1614    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1615        RecordResolver {
1616            name: "ClassRangeRecord",
1617            get_field: Box::new(move |idx, _data| match idx {
1618                0usize => Some(Field::new("start_glyph_id", self.start_glyph_id())),
1619                1usize => Some(Field::new("end_glyph_id", self.end_glyph_id())),
1620                2usize => Some(Field::new("class", self.class())),
1621                _ => None,
1622            }),
1623            data,
1624        }
1625    }
1626}
1627
1628/// A [Class Definition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#class-definition-table)
1629#[derive(Clone)]
1630pub enum ClassDef<'a> {
1631    Format1(ClassDefFormat1<'a>),
1632    Format2(ClassDefFormat2<'a>),
1633}
1634
1635impl Default for ClassDef<'_> {
1636    fn default() -> Self {
1637        Self::Format1(Default::default())
1638    }
1639}
1640
1641impl<'a> ClassDef<'a> {
1642    ///Return the `FontData` used to resolve offsets for this table.
1643    pub fn offset_data(&self) -> FontData<'a> {
1644        match self {
1645            Self::Format1(item) => item.offset_data(),
1646            Self::Format2(item) => item.offset_data(),
1647        }
1648    }
1649
1650    /// Format identifier — format = 1
1651    pub fn class_format(&self) -> u16 {
1652        match self {
1653            Self::Format1(item) => item.class_format(),
1654            Self::Format2(item) => item.class_format(),
1655        }
1656    }
1657}
1658
1659impl<'a> FontRead<'a> for ClassDef<'a> {
1660    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1661        let format: u16 = data.read_at(0usize)?;
1662        match format {
1663            ClassDefFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1664            ClassDefFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1665            other => Err(ReadError::InvalidFormat(other.into())),
1666        }
1667    }
1668}
1669
1670impl<'a> MinByteRange<'a> for ClassDef<'a> {
1671    fn min_byte_range(&self) -> Range<usize> {
1672        match self {
1673            Self::Format1(item) => item.min_byte_range(),
1674            Self::Format2(item) => item.min_byte_range(),
1675        }
1676    }
1677    fn min_table_bytes(&self) -> &'a [u8] {
1678        match self {
1679            Self::Format1(item) => item.min_table_bytes(),
1680            Self::Format2(item) => item.min_table_bytes(),
1681        }
1682    }
1683}
1684
1685#[cfg(feature = "experimental_traverse")]
1686impl<'a> ClassDef<'a> {
1687    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1688        match self {
1689            Self::Format1(table) => table,
1690            Self::Format2(table) => table,
1691        }
1692    }
1693}
1694
1695#[cfg(feature = "experimental_traverse")]
1696impl std::fmt::Debug for ClassDef<'_> {
1697    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1698        self.dyn_inner().fmt(f)
1699    }
1700}
1701
1702#[cfg(feature = "experimental_traverse")]
1703impl<'a> SomeTable<'a> for ClassDef<'a> {
1704    fn type_name(&self) -> &str {
1705        self.dyn_inner().type_name()
1706    }
1707    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1708        self.dyn_inner().get_field(idx)
1709    }
1710}
1711
1712/// [Sequence Lookup Record](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-lookup-record)
1713#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1714#[repr(C)]
1715#[repr(packed)]
1716pub struct SequenceLookupRecord {
1717    /// Index (zero-based) into the input glyph sequence
1718    pub sequence_index: BigEndian<u16>,
1719    /// Index (zero-based) into the LookupList
1720    pub lookup_list_index: BigEndian<u16>,
1721}
1722
1723impl SequenceLookupRecord {
1724    /// Index (zero-based) into the input glyph sequence
1725    pub fn sequence_index(&self) -> u16 {
1726        self.sequence_index.get()
1727    }
1728
1729    /// Index (zero-based) into the LookupList
1730    pub fn lookup_list_index(&self) -> u16 {
1731        self.lookup_list_index.get()
1732    }
1733}
1734
1735impl FixedSize for SequenceLookupRecord {
1736    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1737}
1738
1739#[cfg(feature = "experimental_traverse")]
1740impl<'a> SomeRecord<'a> for SequenceLookupRecord {
1741    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1742        RecordResolver {
1743            name: "SequenceLookupRecord",
1744            get_field: Box::new(move |idx, _data| match idx {
1745                0usize => Some(Field::new("sequence_index", self.sequence_index())),
1746                1usize => Some(Field::new("lookup_list_index", self.lookup_list_index())),
1747                _ => None,
1748            }),
1749            data,
1750        }
1751    }
1752}
1753
1754impl Format<u16> for SequenceContextFormat1<'_> {
1755    const FORMAT: u16 = 1;
1756}
1757
1758impl<'a> MinByteRange<'a> for SequenceContextFormat1<'a> {
1759    fn min_byte_range(&self) -> Range<usize> {
1760        0..self.seq_rule_set_offsets_byte_range().end
1761    }
1762    fn min_table_bytes(&self) -> &'a [u8] {
1763        let range = self.min_byte_range();
1764        self.data.as_bytes().get(range).unwrap_or_default()
1765    }
1766}
1767
1768impl<'a> FontRead<'a> for SequenceContextFormat1<'a> {
1769    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1770        #[allow(clippy::absurd_extreme_comparisons)]
1771        if data.len() < Self::MIN_SIZE {
1772            return Err(ReadError::OutOfBounds);
1773        }
1774        Ok(Self { data })
1775    }
1776}
1777
1778/// [Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-1-simple-glyph-contexts)
1779#[derive(Clone)]
1780pub struct SequenceContextFormat1<'a> {
1781    data: FontData<'a>,
1782}
1783
1784#[allow(clippy::needless_lifetimes)]
1785impl<'a> SequenceContextFormat1<'a> {
1786    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1787    basic_table_impls!(impl_the_methods);
1788
1789    /// Format identifier: format = 1
1790    pub fn format(&self) -> u16 {
1791        let range = self.format_byte_range();
1792        self.data.read_at(range.start).ok().unwrap()
1793    }
1794
1795    /// Offset to Coverage table, from beginning of
1796    /// SequenceContextFormat1 table
1797    pub fn coverage_offset(&self) -> Offset16 {
1798        let range = self.coverage_offset_byte_range();
1799        self.data.read_at(range.start).ok().unwrap()
1800    }
1801
1802    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
1803    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1804        let data = self.data;
1805        self.coverage_offset().resolve(data)
1806    }
1807
1808    /// Number of SequenceRuleSet tables
1809    pub fn seq_rule_set_count(&self) -> u16 {
1810        let range = self.seq_rule_set_count_byte_range();
1811        self.data.read_at(range.start).ok().unwrap()
1812    }
1813
1814    /// Array of offsets to SequenceRuleSet tables, from beginning of
1815    /// SequenceContextFormat1 table (offsets may be NULL)
1816    pub fn seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
1817        let range = self.seq_rule_set_offsets_byte_range();
1818        self.data.read_array(range).ok().unwrap_or_default()
1819    }
1820
1821    /// A dynamically resolving wrapper for [`seq_rule_set_offsets`][Self::seq_rule_set_offsets].
1822    pub fn seq_rule_sets(&self) -> ArrayOfNullableOffsets<'a, SequenceRuleSet<'a>, Offset16> {
1823        let data = self.data;
1824        let offsets = self.seq_rule_set_offsets();
1825        ArrayOfNullableOffsets::new(offsets, data, ())
1826    }
1827
1828    pub fn format_byte_range(&self) -> Range<usize> {
1829        let start = 0;
1830        start..start + u16::RAW_BYTE_LEN
1831    }
1832
1833    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1834        let start = self.format_byte_range().end;
1835        start..start + Offset16::RAW_BYTE_LEN
1836    }
1837
1838    pub fn seq_rule_set_count_byte_range(&self) -> Range<usize> {
1839        let start = self.coverage_offset_byte_range().end;
1840        start..start + u16::RAW_BYTE_LEN
1841    }
1842
1843    pub fn seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
1844        let seq_rule_set_count = self.seq_rule_set_count();
1845        let start = self.seq_rule_set_count_byte_range().end;
1846        start..start + (seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1847    }
1848}
1849
1850const _: () = assert!(FontData::default_data_long_enough(
1851    SequenceContextFormat1::MIN_SIZE
1852));
1853
1854impl Default for SequenceContextFormat1<'_> {
1855    fn default() -> Self {
1856        Self {
1857            data: FontData::default_format_1_u16_table_data(),
1858        }
1859    }
1860}
1861
1862#[cfg(feature = "experimental_traverse")]
1863impl<'a> SomeTable<'a> for SequenceContextFormat1<'a> {
1864    fn type_name(&self) -> &str {
1865        "SequenceContextFormat1"
1866    }
1867    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1868        match idx {
1869            0usize => Some(Field::new("format", self.format())),
1870            1usize => Some(Field::new(
1871                "coverage_offset",
1872                FieldType::offset(self.coverage_offset(), self.coverage()),
1873            )),
1874            2usize => Some(Field::new("seq_rule_set_count", self.seq_rule_set_count())),
1875            3usize => Some(Field::new(
1876                "seq_rule_set_offsets",
1877                FieldType::from(self.seq_rule_sets()),
1878            )),
1879            _ => None,
1880        }
1881    }
1882}
1883
1884#[cfg(feature = "experimental_traverse")]
1885#[allow(clippy::needless_lifetimes)]
1886impl<'a> std::fmt::Debug for SequenceContextFormat1<'a> {
1887    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1888        (self as &dyn SomeTable<'a>).fmt(f)
1889    }
1890}
1891
1892impl<'a> MinByteRange<'a> for SequenceRuleSet<'a> {
1893    fn min_byte_range(&self) -> Range<usize> {
1894        0..self.seq_rule_offsets_byte_range().end
1895    }
1896    fn min_table_bytes(&self) -> &'a [u8] {
1897        let range = self.min_byte_range();
1898        self.data.as_bytes().get(range).unwrap_or_default()
1899    }
1900}
1901
1902impl<'a> FontRead<'a> for SequenceRuleSet<'a> {
1903    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1904        #[allow(clippy::absurd_extreme_comparisons)]
1905        if data.len() < Self::MIN_SIZE {
1906            return Err(ReadError::OutOfBounds);
1907        }
1908        Ok(Self { data })
1909    }
1910}
1911
1912/// Part of [SequenceContextFormat1]
1913#[derive(Clone)]
1914pub struct SequenceRuleSet<'a> {
1915    data: FontData<'a>,
1916}
1917
1918#[allow(clippy::needless_lifetimes)]
1919impl<'a> SequenceRuleSet<'a> {
1920    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1921    basic_table_impls!(impl_the_methods);
1922
1923    /// Number of SequenceRule tables
1924    pub fn seq_rule_count(&self) -> u16 {
1925        let range = self.seq_rule_count_byte_range();
1926        self.data.read_at(range.start).ok().unwrap()
1927    }
1928
1929    /// Array of offsets to SequenceRule tables, from beginning of the
1930    /// SequenceRuleSet table
1931    pub fn seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
1932        let range = self.seq_rule_offsets_byte_range();
1933        self.data.read_array(range).ok().unwrap_or_default()
1934    }
1935
1936    /// A dynamically resolving wrapper for [`seq_rule_offsets`][Self::seq_rule_offsets].
1937    pub fn seq_rules(&self) -> ArrayOfOffsets<'a, SequenceRule<'a>, Offset16> {
1938        let data = self.data;
1939        let offsets = self.seq_rule_offsets();
1940        ArrayOfOffsets::new(offsets, data, ())
1941    }
1942
1943    pub fn seq_rule_count_byte_range(&self) -> Range<usize> {
1944        let start = 0;
1945        start..start + u16::RAW_BYTE_LEN
1946    }
1947
1948    pub fn seq_rule_offsets_byte_range(&self) -> Range<usize> {
1949        let seq_rule_count = self.seq_rule_count();
1950        let start = self.seq_rule_count_byte_range().end;
1951        start..start + (seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
1952    }
1953}
1954
1955const _: () = assert!(FontData::default_data_long_enough(
1956    SequenceRuleSet::MIN_SIZE
1957));
1958
1959impl Default for SequenceRuleSet<'_> {
1960    fn default() -> Self {
1961        Self {
1962            data: FontData::default_table_data(),
1963        }
1964    }
1965}
1966
1967#[cfg(feature = "experimental_traverse")]
1968impl<'a> SomeTable<'a> for SequenceRuleSet<'a> {
1969    fn type_name(&self) -> &str {
1970        "SequenceRuleSet"
1971    }
1972    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1973        match idx {
1974            0usize => Some(Field::new("seq_rule_count", self.seq_rule_count())),
1975            1usize => Some(Field::new(
1976                "seq_rule_offsets",
1977                FieldType::from(self.seq_rules()),
1978            )),
1979            _ => None,
1980        }
1981    }
1982}
1983
1984#[cfg(feature = "experimental_traverse")]
1985#[allow(clippy::needless_lifetimes)]
1986impl<'a> std::fmt::Debug for SequenceRuleSet<'a> {
1987    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1988        (self as &dyn SomeTable<'a>).fmt(f)
1989    }
1990}
1991
1992impl<'a> MinByteRange<'a> for SequenceRule<'a> {
1993    fn min_byte_range(&self) -> Range<usize> {
1994        0..self.seq_lookup_records_byte_range().end
1995    }
1996    fn min_table_bytes(&self) -> &'a [u8] {
1997        let range = self.min_byte_range();
1998        self.data.as_bytes().get(range).unwrap_or_default()
1999    }
2000}
2001
2002impl<'a> FontRead<'a> for SequenceRule<'a> {
2003    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2004        #[allow(clippy::absurd_extreme_comparisons)]
2005        if data.len() < Self::MIN_SIZE {
2006            return Err(ReadError::OutOfBounds);
2007        }
2008        Ok(Self { data })
2009    }
2010}
2011
2012/// Part of [SequenceContextFormat1]
2013#[derive(Clone)]
2014pub struct SequenceRule<'a> {
2015    data: FontData<'a>,
2016}
2017
2018#[allow(clippy::needless_lifetimes)]
2019impl<'a> SequenceRule<'a> {
2020    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2021    basic_table_impls!(impl_the_methods);
2022
2023    /// Number of glyphs in the input glyph sequence
2024    pub fn glyph_count(&self) -> u16 {
2025        let range = self.glyph_count_byte_range();
2026        self.data.read_at(range.start).ok().unwrap()
2027    }
2028
2029    /// Number of SequenceLookupRecords
2030    pub fn seq_lookup_count(&self) -> u16 {
2031        let range = self.seq_lookup_count_byte_range();
2032        self.data.read_at(range.start).ok().unwrap()
2033    }
2034
2035    /// Array of input glyph IDs—starting with the second glyph
2036    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
2037        let range = self.input_sequence_byte_range();
2038        self.data.read_array(range).ok().unwrap_or_default()
2039    }
2040
2041    /// Array of Sequence lookup records
2042    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2043        let range = self.seq_lookup_records_byte_range();
2044        self.data.read_array(range).ok().unwrap_or_default()
2045    }
2046
2047    pub fn glyph_count_byte_range(&self) -> Range<usize> {
2048        let start = 0;
2049        start..start + u16::RAW_BYTE_LEN
2050    }
2051
2052    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2053        let start = self.glyph_count_byte_range().end;
2054        start..start + u16::RAW_BYTE_LEN
2055    }
2056
2057    pub fn input_sequence_byte_range(&self) -> Range<usize> {
2058        let glyph_count = self.glyph_count();
2059        let start = self.seq_lookup_count_byte_range().end;
2060        start
2061            ..start
2062                + (transforms::subtract(glyph_count, 1_usize))
2063                    .saturating_mul(GlyphId16::RAW_BYTE_LEN)
2064    }
2065
2066    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2067        let seq_lookup_count = self.seq_lookup_count();
2068        let start = self.input_sequence_byte_range().end;
2069        start
2070            ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2071    }
2072}
2073
2074const _: () = assert!(FontData::default_data_long_enough(SequenceRule::MIN_SIZE));
2075
2076impl Default for SequenceRule<'_> {
2077    fn default() -> Self {
2078        Self {
2079            data: FontData::default_table_data(),
2080        }
2081    }
2082}
2083
2084#[cfg(feature = "experimental_traverse")]
2085impl<'a> SomeTable<'a> for SequenceRule<'a> {
2086    fn type_name(&self) -> &str {
2087        "SequenceRule"
2088    }
2089    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2090        match idx {
2091            0usize => Some(Field::new("glyph_count", self.glyph_count())),
2092            1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2093            2usize => Some(Field::new("input_sequence", self.input_sequence())),
2094            3usize => Some(Field::new(
2095                "seq_lookup_records",
2096                traversal::FieldType::array_of_records(
2097                    stringify!(SequenceLookupRecord),
2098                    self.seq_lookup_records(),
2099                    self.offset_data(),
2100                ),
2101            )),
2102            _ => None,
2103        }
2104    }
2105}
2106
2107#[cfg(feature = "experimental_traverse")]
2108#[allow(clippy::needless_lifetimes)]
2109impl<'a> std::fmt::Debug for SequenceRule<'a> {
2110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2111        (self as &dyn SomeTable<'a>).fmt(f)
2112    }
2113}
2114
2115impl Format<u16> for SequenceContextFormat2<'_> {
2116    const FORMAT: u16 = 2;
2117}
2118
2119impl<'a> MinByteRange<'a> for SequenceContextFormat2<'a> {
2120    fn min_byte_range(&self) -> Range<usize> {
2121        0..self.class_seq_rule_set_offsets_byte_range().end
2122    }
2123    fn min_table_bytes(&self) -> &'a [u8] {
2124        let range = self.min_byte_range();
2125        self.data.as_bytes().get(range).unwrap_or_default()
2126    }
2127}
2128
2129impl<'a> FontRead<'a> for SequenceContextFormat2<'a> {
2130    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2131        #[allow(clippy::absurd_extreme_comparisons)]
2132        if data.len() < Self::MIN_SIZE {
2133            return Err(ReadError::OutOfBounds);
2134        }
2135        Ok(Self { data })
2136    }
2137}
2138
2139/// [Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-2-class-based-glyph-contexts)
2140#[derive(Clone)]
2141pub struct SequenceContextFormat2<'a> {
2142    data: FontData<'a>,
2143}
2144
2145#[allow(clippy::needless_lifetimes)]
2146impl<'a> SequenceContextFormat2<'a> {
2147    pub const MIN_SIZE: usize =
2148        (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2149    basic_table_impls!(impl_the_methods);
2150
2151    /// Format identifier: format = 2
2152    pub fn format(&self) -> u16 {
2153        let range = self.format_byte_range();
2154        self.data.read_at(range.start).ok().unwrap()
2155    }
2156
2157    /// Offset to Coverage table, from beginning of
2158    /// SequenceContextFormat2 table
2159    pub fn coverage_offset(&self) -> Offset16 {
2160        let range = self.coverage_offset_byte_range();
2161        self.data.read_at(range.start).ok().unwrap()
2162    }
2163
2164    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2165    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2166        let data = self.data;
2167        self.coverage_offset().resolve(data)
2168    }
2169
2170    /// Offset to ClassDef table, from beginning of
2171    /// SequenceContextFormat2 table
2172    pub fn class_def_offset(&self) -> Offset16 {
2173        let range = self.class_def_offset_byte_range();
2174        self.data.read_at(range.start).ok().unwrap()
2175    }
2176
2177    /// Attempt to resolve [`class_def_offset`][Self::class_def_offset].
2178    pub fn class_def(&self) -> Result<ClassDef<'a>, ReadError> {
2179        let data = self.data;
2180        self.class_def_offset().resolve(data)
2181    }
2182
2183    /// Number of ClassSequenceRuleSet tables
2184    pub fn class_seq_rule_set_count(&self) -> u16 {
2185        let range = self.class_seq_rule_set_count_byte_range();
2186        self.data.read_at(range.start).ok().unwrap()
2187    }
2188
2189    /// Array of offsets to ClassSequenceRuleSet tables, from beginning
2190    /// of SequenceContextFormat2 table (may be NULL)
2191    pub fn class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2192        let range = self.class_seq_rule_set_offsets_byte_range();
2193        self.data.read_array(range).ok().unwrap_or_default()
2194    }
2195
2196    /// A dynamically resolving wrapper for [`class_seq_rule_set_offsets`][Self::class_seq_rule_set_offsets].
2197    pub fn class_seq_rule_sets(
2198        &self,
2199    ) -> ArrayOfNullableOffsets<'a, ClassSequenceRuleSet<'a>, Offset16> {
2200        let data = self.data;
2201        let offsets = self.class_seq_rule_set_offsets();
2202        ArrayOfNullableOffsets::new(offsets, data, ())
2203    }
2204
2205    pub fn format_byte_range(&self) -> Range<usize> {
2206        let start = 0;
2207        start..start + u16::RAW_BYTE_LEN
2208    }
2209
2210    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2211        let start = self.format_byte_range().end;
2212        start..start + Offset16::RAW_BYTE_LEN
2213    }
2214
2215    pub fn class_def_offset_byte_range(&self) -> Range<usize> {
2216        let start = self.coverage_offset_byte_range().end;
2217        start..start + Offset16::RAW_BYTE_LEN
2218    }
2219
2220    pub fn class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2221        let start = self.class_def_offset_byte_range().end;
2222        start..start + u16::RAW_BYTE_LEN
2223    }
2224
2225    pub fn class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2226        let class_seq_rule_set_count = self.class_seq_rule_set_count();
2227        let start = self.class_seq_rule_set_count_byte_range().end;
2228        start..start + (class_seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2229    }
2230}
2231
2232#[cfg(feature = "experimental_traverse")]
2233impl<'a> SomeTable<'a> for SequenceContextFormat2<'a> {
2234    fn type_name(&self) -> &str {
2235        "SequenceContextFormat2"
2236    }
2237    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2238        match idx {
2239            0usize => Some(Field::new("format", self.format())),
2240            1usize => Some(Field::new(
2241                "coverage_offset",
2242                FieldType::offset(self.coverage_offset(), self.coverage()),
2243            )),
2244            2usize => Some(Field::new(
2245                "class_def_offset",
2246                FieldType::offset(self.class_def_offset(), self.class_def()),
2247            )),
2248            3usize => Some(Field::new(
2249                "class_seq_rule_set_count",
2250                self.class_seq_rule_set_count(),
2251            )),
2252            4usize => Some(Field::new(
2253                "class_seq_rule_set_offsets",
2254                FieldType::from(self.class_seq_rule_sets()),
2255            )),
2256            _ => None,
2257        }
2258    }
2259}
2260
2261#[cfg(feature = "experimental_traverse")]
2262#[allow(clippy::needless_lifetimes)]
2263impl<'a> std::fmt::Debug for SequenceContextFormat2<'a> {
2264    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2265        (self as &dyn SomeTable<'a>).fmt(f)
2266    }
2267}
2268
2269impl<'a> MinByteRange<'a> for ClassSequenceRuleSet<'a> {
2270    fn min_byte_range(&self) -> Range<usize> {
2271        0..self.class_seq_rule_offsets_byte_range().end
2272    }
2273    fn min_table_bytes(&self) -> &'a [u8] {
2274        let range = self.min_byte_range();
2275        self.data.as_bytes().get(range).unwrap_or_default()
2276    }
2277}
2278
2279impl<'a> FontRead<'a> for ClassSequenceRuleSet<'a> {
2280    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2281        #[allow(clippy::absurd_extreme_comparisons)]
2282        if data.len() < Self::MIN_SIZE {
2283            return Err(ReadError::OutOfBounds);
2284        }
2285        Ok(Self { data })
2286    }
2287}
2288
2289/// Part of [SequenceContextFormat2]
2290#[derive(Clone)]
2291pub struct ClassSequenceRuleSet<'a> {
2292    data: FontData<'a>,
2293}
2294
2295#[allow(clippy::needless_lifetimes)]
2296impl<'a> ClassSequenceRuleSet<'a> {
2297    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2298    basic_table_impls!(impl_the_methods);
2299
2300    /// Number of ClassSequenceRule tables
2301    pub fn class_seq_rule_count(&self) -> u16 {
2302        let range = self.class_seq_rule_count_byte_range();
2303        self.data.read_at(range.start).ok().unwrap()
2304    }
2305
2306    /// Array of offsets to ClassSequenceRule tables, from beginning of
2307    /// ClassSequenceRuleSet table
2308    pub fn class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2309        let range = self.class_seq_rule_offsets_byte_range();
2310        self.data.read_array(range).ok().unwrap_or_default()
2311    }
2312
2313    /// A dynamically resolving wrapper for [`class_seq_rule_offsets`][Self::class_seq_rule_offsets].
2314    pub fn class_seq_rules(&self) -> ArrayOfOffsets<'a, ClassSequenceRule<'a>, Offset16> {
2315        let data = self.data;
2316        let offsets = self.class_seq_rule_offsets();
2317        ArrayOfOffsets::new(offsets, data, ())
2318    }
2319
2320    pub fn class_seq_rule_count_byte_range(&self) -> Range<usize> {
2321        let start = 0;
2322        start..start + u16::RAW_BYTE_LEN
2323    }
2324
2325    pub fn class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2326        let class_seq_rule_count = self.class_seq_rule_count();
2327        let start = self.class_seq_rule_count_byte_range().end;
2328        start..start + (class_seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2329    }
2330}
2331
2332const _: () = assert!(FontData::default_data_long_enough(
2333    ClassSequenceRuleSet::MIN_SIZE
2334));
2335
2336impl Default for ClassSequenceRuleSet<'_> {
2337    fn default() -> Self {
2338        Self {
2339            data: FontData::default_table_data(),
2340        }
2341    }
2342}
2343
2344#[cfg(feature = "experimental_traverse")]
2345impl<'a> SomeTable<'a> for ClassSequenceRuleSet<'a> {
2346    fn type_name(&self) -> &str {
2347        "ClassSequenceRuleSet"
2348    }
2349    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2350        match idx {
2351            0usize => Some(Field::new(
2352                "class_seq_rule_count",
2353                self.class_seq_rule_count(),
2354            )),
2355            1usize => Some(Field::new(
2356                "class_seq_rule_offsets",
2357                FieldType::from(self.class_seq_rules()),
2358            )),
2359            _ => None,
2360        }
2361    }
2362}
2363
2364#[cfg(feature = "experimental_traverse")]
2365#[allow(clippy::needless_lifetimes)]
2366impl<'a> std::fmt::Debug for ClassSequenceRuleSet<'a> {
2367    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2368        (self as &dyn SomeTable<'a>).fmt(f)
2369    }
2370}
2371
2372impl<'a> MinByteRange<'a> for ClassSequenceRule<'a> {
2373    fn min_byte_range(&self) -> Range<usize> {
2374        0..self.seq_lookup_records_byte_range().end
2375    }
2376    fn min_table_bytes(&self) -> &'a [u8] {
2377        let range = self.min_byte_range();
2378        self.data.as_bytes().get(range).unwrap_or_default()
2379    }
2380}
2381
2382impl<'a> FontRead<'a> for ClassSequenceRule<'a> {
2383    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2384        #[allow(clippy::absurd_extreme_comparisons)]
2385        if data.len() < Self::MIN_SIZE {
2386            return Err(ReadError::OutOfBounds);
2387        }
2388        Ok(Self { data })
2389    }
2390}
2391
2392/// Part of [SequenceContextFormat2]
2393#[derive(Clone)]
2394pub struct ClassSequenceRule<'a> {
2395    data: FontData<'a>,
2396}
2397
2398#[allow(clippy::needless_lifetimes)]
2399impl<'a> ClassSequenceRule<'a> {
2400    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2401    basic_table_impls!(impl_the_methods);
2402
2403    /// Number of glyphs to be matched
2404    pub fn glyph_count(&self) -> u16 {
2405        let range = self.glyph_count_byte_range();
2406        self.data.read_at(range.start).ok().unwrap()
2407    }
2408
2409    /// Number of SequenceLookupRecords
2410    pub fn seq_lookup_count(&self) -> u16 {
2411        let range = self.seq_lookup_count_byte_range();
2412        self.data.read_at(range.start).ok().unwrap()
2413    }
2414
2415    /// Sequence of classes to be matched to the input glyph sequence,
2416    /// beginning with the second glyph position
2417    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
2418        let range = self.input_sequence_byte_range();
2419        self.data.read_array(range).ok().unwrap_or_default()
2420    }
2421
2422    /// Array of SequenceLookupRecords
2423    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2424        let range = self.seq_lookup_records_byte_range();
2425        self.data.read_array(range).ok().unwrap_or_default()
2426    }
2427
2428    pub fn glyph_count_byte_range(&self) -> Range<usize> {
2429        let start = 0;
2430        start..start + u16::RAW_BYTE_LEN
2431    }
2432
2433    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2434        let start = self.glyph_count_byte_range().end;
2435        start..start + u16::RAW_BYTE_LEN
2436    }
2437
2438    pub fn input_sequence_byte_range(&self) -> Range<usize> {
2439        let glyph_count = self.glyph_count();
2440        let start = self.seq_lookup_count_byte_range().end;
2441        start
2442            ..start + (transforms::subtract(glyph_count, 1_usize)).saturating_mul(u16::RAW_BYTE_LEN)
2443    }
2444
2445    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2446        let seq_lookup_count = self.seq_lookup_count();
2447        let start = self.input_sequence_byte_range().end;
2448        start
2449            ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2450    }
2451}
2452
2453const _: () = assert!(FontData::default_data_long_enough(
2454    ClassSequenceRule::MIN_SIZE
2455));
2456
2457impl Default for ClassSequenceRule<'_> {
2458    fn default() -> Self {
2459        Self {
2460            data: FontData::default_table_data(),
2461        }
2462    }
2463}
2464
2465#[cfg(feature = "experimental_traverse")]
2466impl<'a> SomeTable<'a> for ClassSequenceRule<'a> {
2467    fn type_name(&self) -> &str {
2468        "ClassSequenceRule"
2469    }
2470    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2471        match idx {
2472            0usize => Some(Field::new("glyph_count", self.glyph_count())),
2473            1usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2474            2usize => Some(Field::new("input_sequence", self.input_sequence())),
2475            3usize => Some(Field::new(
2476                "seq_lookup_records",
2477                traversal::FieldType::array_of_records(
2478                    stringify!(SequenceLookupRecord),
2479                    self.seq_lookup_records(),
2480                    self.offset_data(),
2481                ),
2482            )),
2483            _ => None,
2484        }
2485    }
2486}
2487
2488#[cfg(feature = "experimental_traverse")]
2489#[allow(clippy::needless_lifetimes)]
2490impl<'a> std::fmt::Debug for ClassSequenceRule<'a> {
2491    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2492        (self as &dyn SomeTable<'a>).fmt(f)
2493    }
2494}
2495
2496impl Format<u16> for SequenceContextFormat3<'_> {
2497    const FORMAT: u16 = 3;
2498}
2499
2500impl<'a> MinByteRange<'a> for SequenceContextFormat3<'a> {
2501    fn min_byte_range(&self) -> Range<usize> {
2502        0..self.seq_lookup_records_byte_range().end
2503    }
2504    fn min_table_bytes(&self) -> &'a [u8] {
2505        let range = self.min_byte_range();
2506        self.data.as_bytes().get(range).unwrap_or_default()
2507    }
2508}
2509
2510impl<'a> FontRead<'a> for SequenceContextFormat3<'a> {
2511    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2512        #[allow(clippy::absurd_extreme_comparisons)]
2513        if data.len() < Self::MIN_SIZE {
2514            return Err(ReadError::OutOfBounds);
2515        }
2516        Ok(Self { data })
2517    }
2518}
2519
2520/// [Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#sequence-context-format-3-coverage-based-glyph-contexts)
2521#[derive(Clone)]
2522pub struct SequenceContextFormat3<'a> {
2523    data: FontData<'a>,
2524}
2525
2526#[allow(clippy::needless_lifetimes)]
2527impl<'a> SequenceContextFormat3<'a> {
2528    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2529    basic_table_impls!(impl_the_methods);
2530
2531    /// Format identifier: format = 3
2532    pub fn format(&self) -> u16 {
2533        let range = self.format_byte_range();
2534        self.data.read_at(range.start).ok().unwrap()
2535    }
2536
2537    /// Number of glyphs in the input sequence
2538    pub fn glyph_count(&self) -> u16 {
2539        let range = self.glyph_count_byte_range();
2540        self.data.read_at(range.start).ok().unwrap()
2541    }
2542
2543    /// Number of SequenceLookupRecords
2544    pub fn seq_lookup_count(&self) -> u16 {
2545        let range = self.seq_lookup_count_byte_range();
2546        self.data.read_at(range.start).ok().unwrap()
2547    }
2548
2549    /// Array of offsets to Coverage tables, from beginning of
2550    /// SequenceContextFormat3 subtable
2551    pub fn coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
2552        let range = self.coverage_offsets_byte_range();
2553        self.data.read_array(range).ok().unwrap_or_default()
2554    }
2555
2556    /// A dynamically resolving wrapper for [`coverage_offsets`][Self::coverage_offsets].
2557    pub fn coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
2558        let data = self.data;
2559        let offsets = self.coverage_offsets();
2560        ArrayOfOffsets::new(offsets, data, ())
2561    }
2562
2563    /// Array of SequenceLookupRecords
2564    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
2565        let range = self.seq_lookup_records_byte_range();
2566        self.data.read_array(range).ok().unwrap_or_default()
2567    }
2568
2569    pub fn format_byte_range(&self) -> Range<usize> {
2570        let start = 0;
2571        start..start + u16::RAW_BYTE_LEN
2572    }
2573
2574    pub fn glyph_count_byte_range(&self) -> Range<usize> {
2575        let start = self.format_byte_range().end;
2576        start..start + u16::RAW_BYTE_LEN
2577    }
2578
2579    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
2580        let start = self.glyph_count_byte_range().end;
2581        start..start + u16::RAW_BYTE_LEN
2582    }
2583
2584    pub fn coverage_offsets_byte_range(&self) -> Range<usize> {
2585        let glyph_count = self.glyph_count();
2586        let start = self.seq_lookup_count_byte_range().end;
2587        start..start + (glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2588    }
2589
2590    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
2591        let seq_lookup_count = self.seq_lookup_count();
2592        let start = self.coverage_offsets_byte_range().end;
2593        start
2594            ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
2595    }
2596}
2597
2598#[cfg(feature = "experimental_traverse")]
2599impl<'a> SomeTable<'a> for SequenceContextFormat3<'a> {
2600    fn type_name(&self) -> &str {
2601        "SequenceContextFormat3"
2602    }
2603    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2604        match idx {
2605            0usize => Some(Field::new("format", self.format())),
2606            1usize => Some(Field::new("glyph_count", self.glyph_count())),
2607            2usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
2608            3usize => Some(Field::new(
2609                "coverage_offsets",
2610                FieldType::from(self.coverages()),
2611            )),
2612            4usize => Some(Field::new(
2613                "seq_lookup_records",
2614                traversal::FieldType::array_of_records(
2615                    stringify!(SequenceLookupRecord),
2616                    self.seq_lookup_records(),
2617                    self.offset_data(),
2618                ),
2619            )),
2620            _ => None,
2621        }
2622    }
2623}
2624
2625#[cfg(feature = "experimental_traverse")]
2626#[allow(clippy::needless_lifetimes)]
2627impl<'a> std::fmt::Debug for SequenceContextFormat3<'a> {
2628    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2629        (self as &dyn SomeTable<'a>).fmt(f)
2630    }
2631}
2632
2633#[derive(Clone)]
2634pub enum SequenceContext<'a> {
2635    Format1(SequenceContextFormat1<'a>),
2636    Format2(SequenceContextFormat2<'a>),
2637    Format3(SequenceContextFormat3<'a>),
2638}
2639
2640impl Default for SequenceContext<'_> {
2641    fn default() -> Self {
2642        Self::Format1(Default::default())
2643    }
2644}
2645
2646impl<'a> SequenceContext<'a> {
2647    ///Return the `FontData` used to resolve offsets for this table.
2648    pub fn offset_data(&self) -> FontData<'a> {
2649        match self {
2650            Self::Format1(item) => item.offset_data(),
2651            Self::Format2(item) => item.offset_data(),
2652            Self::Format3(item) => item.offset_data(),
2653        }
2654    }
2655
2656    /// Format identifier: format = 1
2657    pub fn format(&self) -> u16 {
2658        match self {
2659            Self::Format1(item) => item.format(),
2660            Self::Format2(item) => item.format(),
2661            Self::Format3(item) => item.format(),
2662        }
2663    }
2664}
2665
2666impl<'a> FontRead<'a> for SequenceContext<'a> {
2667    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2668        let format: u16 = data.read_at(0usize)?;
2669        match format {
2670            SequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
2671            SequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
2672            SequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
2673            other => Err(ReadError::InvalidFormat(other.into())),
2674        }
2675    }
2676}
2677
2678impl<'a> MinByteRange<'a> for SequenceContext<'a> {
2679    fn min_byte_range(&self) -> Range<usize> {
2680        match self {
2681            Self::Format1(item) => item.min_byte_range(),
2682            Self::Format2(item) => item.min_byte_range(),
2683            Self::Format3(item) => item.min_byte_range(),
2684        }
2685    }
2686    fn min_table_bytes(&self) -> &'a [u8] {
2687        match self {
2688            Self::Format1(item) => item.min_table_bytes(),
2689            Self::Format2(item) => item.min_table_bytes(),
2690            Self::Format3(item) => item.min_table_bytes(),
2691        }
2692    }
2693}
2694
2695#[cfg(feature = "experimental_traverse")]
2696impl<'a> SequenceContext<'a> {
2697    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
2698        match self {
2699            Self::Format1(table) => table,
2700            Self::Format2(table) => table,
2701            Self::Format3(table) => table,
2702        }
2703    }
2704}
2705
2706#[cfg(feature = "experimental_traverse")]
2707impl std::fmt::Debug for SequenceContext<'_> {
2708    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2709        self.dyn_inner().fmt(f)
2710    }
2711}
2712
2713#[cfg(feature = "experimental_traverse")]
2714impl<'a> SomeTable<'a> for SequenceContext<'a> {
2715    fn type_name(&self) -> &str {
2716        self.dyn_inner().type_name()
2717    }
2718    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2719        self.dyn_inner().get_field(idx)
2720    }
2721}
2722
2723impl Format<u16> for ChainedSequenceContextFormat1<'_> {
2724    const FORMAT: u16 = 1;
2725}
2726
2727impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat1<'a> {
2728    fn min_byte_range(&self) -> Range<usize> {
2729        0..self.chained_seq_rule_set_offsets_byte_range().end
2730    }
2731    fn min_table_bytes(&self) -> &'a [u8] {
2732        let range = self.min_byte_range();
2733        self.data.as_bytes().get(range).unwrap_or_default()
2734    }
2735}
2736
2737impl<'a> FontRead<'a> for ChainedSequenceContextFormat1<'a> {
2738    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2739        #[allow(clippy::absurd_extreme_comparisons)]
2740        if data.len() < Self::MIN_SIZE {
2741            return Err(ReadError::OutOfBounds);
2742        }
2743        Ok(Self { data })
2744    }
2745}
2746
2747/// [Chained Sequence Context Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-1-simple-glyph-contexts)
2748#[derive(Clone)]
2749pub struct ChainedSequenceContextFormat1<'a> {
2750    data: FontData<'a>,
2751}
2752
2753#[allow(clippy::needless_lifetimes)]
2754impl<'a> ChainedSequenceContextFormat1<'a> {
2755    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2756    basic_table_impls!(impl_the_methods);
2757
2758    /// Format identifier: format = 1
2759    pub fn format(&self) -> u16 {
2760        let range = self.format_byte_range();
2761        self.data.read_at(range.start).ok().unwrap()
2762    }
2763
2764    /// Offset to Coverage table, from beginning of
2765    /// ChainSequenceContextFormat1 table
2766    pub fn coverage_offset(&self) -> Offset16 {
2767        let range = self.coverage_offset_byte_range();
2768        self.data.read_at(range.start).ok().unwrap()
2769    }
2770
2771    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
2772    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2773        let data = self.data;
2774        self.coverage_offset().resolve(data)
2775    }
2776
2777    /// Number of ChainedSequenceRuleSet tables
2778    pub fn chained_seq_rule_set_count(&self) -> u16 {
2779        let range = self.chained_seq_rule_set_count_byte_range();
2780        self.data.read_at(range.start).ok().unwrap()
2781    }
2782
2783    /// Array of offsets to ChainedSeqRuleSet tables, from beginning of
2784    /// ChainedSequenceContextFormat1 table (may be NULL)
2785    pub fn chained_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
2786        let range = self.chained_seq_rule_set_offsets_byte_range();
2787        self.data.read_array(range).ok().unwrap_or_default()
2788    }
2789
2790    /// A dynamically resolving wrapper for [`chained_seq_rule_set_offsets`][Self::chained_seq_rule_set_offsets].
2791    pub fn chained_seq_rule_sets(
2792        &self,
2793    ) -> ArrayOfNullableOffsets<'a, ChainedSequenceRuleSet<'a>, Offset16> {
2794        let data = self.data;
2795        let offsets = self.chained_seq_rule_set_offsets();
2796        ArrayOfNullableOffsets::new(offsets, data, ())
2797    }
2798
2799    pub fn format_byte_range(&self) -> Range<usize> {
2800        let start = 0;
2801        start..start + u16::RAW_BYTE_LEN
2802    }
2803
2804    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2805        let start = self.format_byte_range().end;
2806        start..start + Offset16::RAW_BYTE_LEN
2807    }
2808
2809    pub fn chained_seq_rule_set_count_byte_range(&self) -> Range<usize> {
2810        let start = self.coverage_offset_byte_range().end;
2811        start..start + u16::RAW_BYTE_LEN
2812    }
2813
2814    pub fn chained_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
2815        let chained_seq_rule_set_count = self.chained_seq_rule_set_count();
2816        let start = self.chained_seq_rule_set_count_byte_range().end;
2817        start..start + (chained_seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2818    }
2819}
2820
2821const _: () = assert!(FontData::default_data_long_enough(
2822    ChainedSequenceContextFormat1::MIN_SIZE
2823));
2824
2825impl Default for ChainedSequenceContextFormat1<'_> {
2826    fn default() -> Self {
2827        Self {
2828            data: FontData::default_format_1_u16_table_data(),
2829        }
2830    }
2831}
2832
2833#[cfg(feature = "experimental_traverse")]
2834impl<'a> SomeTable<'a> for ChainedSequenceContextFormat1<'a> {
2835    fn type_name(&self) -> &str {
2836        "ChainedSequenceContextFormat1"
2837    }
2838    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2839        match idx {
2840            0usize => Some(Field::new("format", self.format())),
2841            1usize => Some(Field::new(
2842                "coverage_offset",
2843                FieldType::offset(self.coverage_offset(), self.coverage()),
2844            )),
2845            2usize => Some(Field::new(
2846                "chained_seq_rule_set_count",
2847                self.chained_seq_rule_set_count(),
2848            )),
2849            3usize => Some(Field::new(
2850                "chained_seq_rule_set_offsets",
2851                FieldType::from(self.chained_seq_rule_sets()),
2852            )),
2853            _ => None,
2854        }
2855    }
2856}
2857
2858#[cfg(feature = "experimental_traverse")]
2859#[allow(clippy::needless_lifetimes)]
2860impl<'a> std::fmt::Debug for ChainedSequenceContextFormat1<'a> {
2861    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2862        (self as &dyn SomeTable<'a>).fmt(f)
2863    }
2864}
2865
2866impl<'a> MinByteRange<'a> for ChainedSequenceRuleSet<'a> {
2867    fn min_byte_range(&self) -> Range<usize> {
2868        0..self.chained_seq_rule_offsets_byte_range().end
2869    }
2870    fn min_table_bytes(&self) -> &'a [u8] {
2871        let range = self.min_byte_range();
2872        self.data.as_bytes().get(range).unwrap_or_default()
2873    }
2874}
2875
2876impl<'a> FontRead<'a> for ChainedSequenceRuleSet<'a> {
2877    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2878        #[allow(clippy::absurd_extreme_comparisons)]
2879        if data.len() < Self::MIN_SIZE {
2880            return Err(ReadError::OutOfBounds);
2881        }
2882        Ok(Self { data })
2883    }
2884}
2885
2886/// Part of [ChainedSequenceContextFormat1]
2887#[derive(Clone)]
2888pub struct ChainedSequenceRuleSet<'a> {
2889    data: FontData<'a>,
2890}
2891
2892#[allow(clippy::needless_lifetimes)]
2893impl<'a> ChainedSequenceRuleSet<'a> {
2894    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2895    basic_table_impls!(impl_the_methods);
2896
2897    /// Number of ChainedSequenceRule tables
2898    pub fn chained_seq_rule_count(&self) -> u16 {
2899        let range = self.chained_seq_rule_count_byte_range();
2900        self.data.read_at(range.start).ok().unwrap()
2901    }
2902
2903    /// Array of offsets to ChainedSequenceRule tables, from beginning
2904    /// of ChainedSequenceRuleSet table
2905    pub fn chained_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
2906        let range = self.chained_seq_rule_offsets_byte_range();
2907        self.data.read_array(range).ok().unwrap_or_default()
2908    }
2909
2910    /// A dynamically resolving wrapper for [`chained_seq_rule_offsets`][Self::chained_seq_rule_offsets].
2911    pub fn chained_seq_rules(&self) -> ArrayOfOffsets<'a, ChainedSequenceRule<'a>, Offset16> {
2912        let data = self.data;
2913        let offsets = self.chained_seq_rule_offsets();
2914        ArrayOfOffsets::new(offsets, data, ())
2915    }
2916
2917    pub fn chained_seq_rule_count_byte_range(&self) -> Range<usize> {
2918        let start = 0;
2919        start..start + u16::RAW_BYTE_LEN
2920    }
2921
2922    pub fn chained_seq_rule_offsets_byte_range(&self) -> Range<usize> {
2923        let chained_seq_rule_count = self.chained_seq_rule_count();
2924        let start = self.chained_seq_rule_count_byte_range().end;
2925        start..start + (chained_seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
2926    }
2927}
2928
2929const _: () = assert!(FontData::default_data_long_enough(
2930    ChainedSequenceRuleSet::MIN_SIZE
2931));
2932
2933impl Default for ChainedSequenceRuleSet<'_> {
2934    fn default() -> Self {
2935        Self {
2936            data: FontData::default_table_data(),
2937        }
2938    }
2939}
2940
2941#[cfg(feature = "experimental_traverse")]
2942impl<'a> SomeTable<'a> for ChainedSequenceRuleSet<'a> {
2943    fn type_name(&self) -> &str {
2944        "ChainedSequenceRuleSet"
2945    }
2946    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2947        match idx {
2948            0usize => Some(Field::new(
2949                "chained_seq_rule_count",
2950                self.chained_seq_rule_count(),
2951            )),
2952            1usize => Some(Field::new(
2953                "chained_seq_rule_offsets",
2954                FieldType::from(self.chained_seq_rules()),
2955            )),
2956            _ => None,
2957        }
2958    }
2959}
2960
2961#[cfg(feature = "experimental_traverse")]
2962#[allow(clippy::needless_lifetimes)]
2963impl<'a> std::fmt::Debug for ChainedSequenceRuleSet<'a> {
2964    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2965        (self as &dyn SomeTable<'a>).fmt(f)
2966    }
2967}
2968
2969impl<'a> MinByteRange<'a> for ChainedSequenceRule<'a> {
2970    fn min_byte_range(&self) -> Range<usize> {
2971        0..self.seq_lookup_records_byte_range().end
2972    }
2973    fn min_table_bytes(&self) -> &'a [u8] {
2974        let range = self.min_byte_range();
2975        self.data.as_bytes().get(range).unwrap_or_default()
2976    }
2977}
2978
2979impl<'a> FontRead<'a> for ChainedSequenceRule<'a> {
2980    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
2981        #[allow(clippy::absurd_extreme_comparisons)]
2982        if data.len() < Self::MIN_SIZE {
2983            return Err(ReadError::OutOfBounds);
2984        }
2985        Ok(Self { data })
2986    }
2987}
2988
2989/// Part of [ChainedSequenceContextFormat1]
2990#[derive(Clone)]
2991pub struct ChainedSequenceRule<'a> {
2992    data: FontData<'a>,
2993}
2994
2995#[allow(clippy::needless_lifetimes)]
2996impl<'a> ChainedSequenceRule<'a> {
2997    pub const MIN_SIZE: usize =
2998        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2999    basic_table_impls!(impl_the_methods);
3000
3001    /// Number of glyphs in the backtrack sequence
3002    pub fn backtrack_glyph_count(&self) -> u16 {
3003        let range = self.backtrack_glyph_count_byte_range();
3004        self.data.read_at(range.start).ok().unwrap()
3005    }
3006
3007    /// Array of backtrack glyph IDs
3008    pub fn backtrack_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
3009        let range = self.backtrack_sequence_byte_range();
3010        self.data.read_array(range).ok().unwrap_or_default()
3011    }
3012
3013    /// Number of glyphs in the input sequence
3014    pub fn input_glyph_count(&self) -> u16 {
3015        let range = self.input_glyph_count_byte_range();
3016        self.data.read_at(range.start).ok().unwrap_or_default()
3017    }
3018
3019    /// Array of input glyph IDs—start with second glyph
3020    pub fn input_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
3021        let range = self.input_sequence_byte_range();
3022        self.data.read_array(range).ok().unwrap_or_default()
3023    }
3024
3025    /// Number of glyphs in the lookahead sequence
3026    pub fn lookahead_glyph_count(&self) -> u16 {
3027        let range = self.lookahead_glyph_count_byte_range();
3028        self.data.read_at(range.start).ok().unwrap_or_default()
3029    }
3030
3031    /// Array of lookahead glyph IDs
3032    pub fn lookahead_sequence(&self) -> &'a [BigEndian<GlyphId16>] {
3033        let range = self.lookahead_sequence_byte_range();
3034        self.data.read_array(range).ok().unwrap_or_default()
3035    }
3036
3037    /// Number of SequenceLookupRecords
3038    pub fn seq_lookup_count(&self) -> u16 {
3039        let range = self.seq_lookup_count_byte_range();
3040        self.data.read_at(range.start).ok().unwrap_or_default()
3041    }
3042
3043    /// Array of SequenceLookupRecords
3044    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3045        let range = self.seq_lookup_records_byte_range();
3046        self.data.read_array(range).ok().unwrap_or_default()
3047    }
3048
3049    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3050        let start = 0;
3051        start..start + u16::RAW_BYTE_LEN
3052    }
3053
3054    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
3055        let backtrack_glyph_count = self.backtrack_glyph_count();
3056        let start = self.backtrack_glyph_count_byte_range().end;
3057        start..start + (backtrack_glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
3058    }
3059
3060    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3061        let start = self.backtrack_sequence_byte_range().end;
3062        start..start + u16::RAW_BYTE_LEN
3063    }
3064
3065    pub fn input_sequence_byte_range(&self) -> Range<usize> {
3066        let input_glyph_count = self.input_glyph_count();
3067        let start = self.input_glyph_count_byte_range().end;
3068        start
3069            ..start
3070                + (transforms::subtract(input_glyph_count, 1_usize))
3071                    .saturating_mul(GlyphId16::RAW_BYTE_LEN)
3072    }
3073
3074    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3075        let start = self.input_sequence_byte_range().end;
3076        start..start + u16::RAW_BYTE_LEN
3077    }
3078
3079    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
3080        let lookahead_glyph_count = self.lookahead_glyph_count();
3081        let start = self.lookahead_glyph_count_byte_range().end;
3082        start..start + (lookahead_glyph_count as usize).saturating_mul(GlyphId16::RAW_BYTE_LEN)
3083    }
3084
3085    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3086        let start = self.lookahead_sequence_byte_range().end;
3087        start..start + u16::RAW_BYTE_LEN
3088    }
3089
3090    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3091        let seq_lookup_count = self.seq_lookup_count();
3092        let start = self.seq_lookup_count_byte_range().end;
3093        start
3094            ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3095    }
3096}
3097
3098const _: () = assert!(FontData::default_data_long_enough(
3099    ChainedSequenceRule::MIN_SIZE
3100));
3101
3102impl Default for ChainedSequenceRule<'_> {
3103    fn default() -> Self {
3104        Self {
3105            data: FontData::default_table_data(),
3106        }
3107    }
3108}
3109
3110#[cfg(feature = "experimental_traverse")]
3111impl<'a> SomeTable<'a> for ChainedSequenceRule<'a> {
3112    fn type_name(&self) -> &str {
3113        "ChainedSequenceRule"
3114    }
3115    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3116        match idx {
3117            0usize => Some(Field::new(
3118                "backtrack_glyph_count",
3119                self.backtrack_glyph_count(),
3120            )),
3121            1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
3122            2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3123            3usize => Some(Field::new("input_sequence", self.input_sequence())),
3124            4usize => Some(Field::new(
3125                "lookahead_glyph_count",
3126                self.lookahead_glyph_count(),
3127            )),
3128            5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
3129            6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3130            7usize => Some(Field::new(
3131                "seq_lookup_records",
3132                traversal::FieldType::array_of_records(
3133                    stringify!(SequenceLookupRecord),
3134                    self.seq_lookup_records(),
3135                    self.offset_data(),
3136                ),
3137            )),
3138            _ => None,
3139        }
3140    }
3141}
3142
3143#[cfg(feature = "experimental_traverse")]
3144#[allow(clippy::needless_lifetimes)]
3145impl<'a> std::fmt::Debug for ChainedSequenceRule<'a> {
3146    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3147        (self as &dyn SomeTable<'a>).fmt(f)
3148    }
3149}
3150
3151impl Format<u16> for ChainedSequenceContextFormat2<'_> {
3152    const FORMAT: u16 = 2;
3153}
3154
3155impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat2<'a> {
3156    fn min_byte_range(&self) -> Range<usize> {
3157        0..self.chained_class_seq_rule_set_offsets_byte_range().end
3158    }
3159    fn min_table_bytes(&self) -> &'a [u8] {
3160        let range = self.min_byte_range();
3161        self.data.as_bytes().get(range).unwrap_or_default()
3162    }
3163}
3164
3165impl<'a> FontRead<'a> for ChainedSequenceContextFormat2<'a> {
3166    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3167        #[allow(clippy::absurd_extreme_comparisons)]
3168        if data.len() < Self::MIN_SIZE {
3169            return Err(ReadError::OutOfBounds);
3170        }
3171        Ok(Self { data })
3172    }
3173}
3174
3175/// [Chained Sequence Context Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-2-class-based-glyph-contexts)
3176#[derive(Clone)]
3177pub struct ChainedSequenceContextFormat2<'a> {
3178    data: FontData<'a>,
3179}
3180
3181#[allow(clippy::needless_lifetimes)]
3182impl<'a> ChainedSequenceContextFormat2<'a> {
3183    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3184        + Offset16::RAW_BYTE_LEN
3185        + Offset16::RAW_BYTE_LEN
3186        + Offset16::RAW_BYTE_LEN
3187        + Offset16::RAW_BYTE_LEN
3188        + u16::RAW_BYTE_LEN);
3189    basic_table_impls!(impl_the_methods);
3190
3191    /// Format identifier: format = 2
3192    pub fn format(&self) -> u16 {
3193        let range = self.format_byte_range();
3194        self.data.read_at(range.start).ok().unwrap()
3195    }
3196
3197    /// Offset to Coverage table, from beginning of
3198    /// ChainedSequenceContextFormat2 table
3199    pub fn coverage_offset(&self) -> Offset16 {
3200        let range = self.coverage_offset_byte_range();
3201        self.data.read_at(range.start).ok().unwrap()
3202    }
3203
3204    /// Attempt to resolve [`coverage_offset`][Self::coverage_offset].
3205    pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3206        let data = self.data;
3207        self.coverage_offset().resolve(data)
3208    }
3209
3210    /// Offset to ClassDef table containing backtrack sequence context,
3211    /// from beginning of ChainedSequenceContextFormat2 table
3212    pub fn backtrack_class_def_offset(&self) -> Offset16 {
3213        let range = self.backtrack_class_def_offset_byte_range();
3214        self.data.read_at(range.start).ok().unwrap()
3215    }
3216
3217    /// Attempt to resolve [`backtrack_class_def_offset`][Self::backtrack_class_def_offset].
3218    pub fn backtrack_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3219        let data = self.data;
3220        self.backtrack_class_def_offset().resolve(data)
3221    }
3222
3223    /// Offset to ClassDef table containing input sequence context,
3224    /// from beginning of ChainedSequenceContextFormat2 table
3225    pub fn input_class_def_offset(&self) -> Offset16 {
3226        let range = self.input_class_def_offset_byte_range();
3227        self.data.read_at(range.start).ok().unwrap()
3228    }
3229
3230    /// Attempt to resolve [`input_class_def_offset`][Self::input_class_def_offset].
3231    pub fn input_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3232        let data = self.data;
3233        self.input_class_def_offset().resolve(data)
3234    }
3235
3236    /// Offset to ClassDef table containing lookahead sequence context,
3237    /// from beginning of ChainedSequenceContextFormat2 table
3238    pub fn lookahead_class_def_offset(&self) -> Offset16 {
3239        let range = self.lookahead_class_def_offset_byte_range();
3240        self.data.read_at(range.start).ok().unwrap()
3241    }
3242
3243    /// Attempt to resolve [`lookahead_class_def_offset`][Self::lookahead_class_def_offset].
3244    pub fn lookahead_class_def(&self) -> Result<ClassDef<'a>, ReadError> {
3245        let data = self.data;
3246        self.lookahead_class_def_offset().resolve(data)
3247    }
3248
3249    /// Number of ChainedClassSequenceRuleSet tables
3250    pub fn chained_class_seq_rule_set_count(&self) -> u16 {
3251        let range = self.chained_class_seq_rule_set_count_byte_range();
3252        self.data.read_at(range.start).ok().unwrap()
3253    }
3254
3255    /// Array of offsets to ChainedClassSequenceRuleSet tables, from
3256    /// beginning of ChainedSequenceContextFormat2 table (may be NULL)
3257    pub fn chained_class_seq_rule_set_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3258        let range = self.chained_class_seq_rule_set_offsets_byte_range();
3259        self.data.read_array(range).ok().unwrap_or_default()
3260    }
3261
3262    /// A dynamically resolving wrapper for [`chained_class_seq_rule_set_offsets`][Self::chained_class_seq_rule_set_offsets].
3263    pub fn chained_class_seq_rule_sets(
3264        &self,
3265    ) -> ArrayOfNullableOffsets<'a, ChainedClassSequenceRuleSet<'a>, Offset16> {
3266        let data = self.data;
3267        let offsets = self.chained_class_seq_rule_set_offsets();
3268        ArrayOfNullableOffsets::new(offsets, data, ())
3269    }
3270
3271    pub fn format_byte_range(&self) -> Range<usize> {
3272        let start = 0;
3273        start..start + u16::RAW_BYTE_LEN
3274    }
3275
3276    pub fn coverage_offset_byte_range(&self) -> Range<usize> {
3277        let start = self.format_byte_range().end;
3278        start..start + Offset16::RAW_BYTE_LEN
3279    }
3280
3281    pub fn backtrack_class_def_offset_byte_range(&self) -> Range<usize> {
3282        let start = self.coverage_offset_byte_range().end;
3283        start..start + Offset16::RAW_BYTE_LEN
3284    }
3285
3286    pub fn input_class_def_offset_byte_range(&self) -> Range<usize> {
3287        let start = self.backtrack_class_def_offset_byte_range().end;
3288        start..start + Offset16::RAW_BYTE_LEN
3289    }
3290
3291    pub fn lookahead_class_def_offset_byte_range(&self) -> Range<usize> {
3292        let start = self.input_class_def_offset_byte_range().end;
3293        start..start + Offset16::RAW_BYTE_LEN
3294    }
3295
3296    pub fn chained_class_seq_rule_set_count_byte_range(&self) -> Range<usize> {
3297        let start = self.lookahead_class_def_offset_byte_range().end;
3298        start..start + u16::RAW_BYTE_LEN
3299    }
3300
3301    pub fn chained_class_seq_rule_set_offsets_byte_range(&self) -> Range<usize> {
3302        let chained_class_seq_rule_set_count = self.chained_class_seq_rule_set_count();
3303        let start = self.chained_class_seq_rule_set_count_byte_range().end;
3304        start
3305            ..start
3306                + (chained_class_seq_rule_set_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3307    }
3308}
3309
3310#[cfg(feature = "experimental_traverse")]
3311impl<'a> SomeTable<'a> for ChainedSequenceContextFormat2<'a> {
3312    fn type_name(&self) -> &str {
3313        "ChainedSequenceContextFormat2"
3314    }
3315    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3316        match idx {
3317            0usize => Some(Field::new("format", self.format())),
3318            1usize => Some(Field::new(
3319                "coverage_offset",
3320                FieldType::offset(self.coverage_offset(), self.coverage()),
3321            )),
3322            2usize => Some(Field::new(
3323                "backtrack_class_def_offset",
3324                FieldType::offset(
3325                    self.backtrack_class_def_offset(),
3326                    self.backtrack_class_def(),
3327                ),
3328            )),
3329            3usize => Some(Field::new(
3330                "input_class_def_offset",
3331                FieldType::offset(self.input_class_def_offset(), self.input_class_def()),
3332            )),
3333            4usize => Some(Field::new(
3334                "lookahead_class_def_offset",
3335                FieldType::offset(
3336                    self.lookahead_class_def_offset(),
3337                    self.lookahead_class_def(),
3338                ),
3339            )),
3340            5usize => Some(Field::new(
3341                "chained_class_seq_rule_set_count",
3342                self.chained_class_seq_rule_set_count(),
3343            )),
3344            6usize => Some(Field::new(
3345                "chained_class_seq_rule_set_offsets",
3346                FieldType::from(self.chained_class_seq_rule_sets()),
3347            )),
3348            _ => None,
3349        }
3350    }
3351}
3352
3353#[cfg(feature = "experimental_traverse")]
3354#[allow(clippy::needless_lifetimes)]
3355impl<'a> std::fmt::Debug for ChainedSequenceContextFormat2<'a> {
3356    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3357        (self as &dyn SomeTable<'a>).fmt(f)
3358    }
3359}
3360
3361impl<'a> MinByteRange<'a> for ChainedClassSequenceRuleSet<'a> {
3362    fn min_byte_range(&self) -> Range<usize> {
3363        0..self.chained_class_seq_rule_offsets_byte_range().end
3364    }
3365    fn min_table_bytes(&self) -> &'a [u8] {
3366        let range = self.min_byte_range();
3367        self.data.as_bytes().get(range).unwrap_or_default()
3368    }
3369}
3370
3371impl<'a> FontRead<'a> for ChainedClassSequenceRuleSet<'a> {
3372    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3373        #[allow(clippy::absurd_extreme_comparisons)]
3374        if data.len() < Self::MIN_SIZE {
3375            return Err(ReadError::OutOfBounds);
3376        }
3377        Ok(Self { data })
3378    }
3379}
3380
3381/// Part of [ChainedSequenceContextFormat2]
3382#[derive(Clone)]
3383pub struct ChainedClassSequenceRuleSet<'a> {
3384    data: FontData<'a>,
3385}
3386
3387#[allow(clippy::needless_lifetimes)]
3388impl<'a> ChainedClassSequenceRuleSet<'a> {
3389    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3390    basic_table_impls!(impl_the_methods);
3391
3392    /// Number of ChainedClassSequenceRule tables
3393    pub fn chained_class_seq_rule_count(&self) -> u16 {
3394        let range = self.chained_class_seq_rule_count_byte_range();
3395        self.data.read_at(range.start).ok().unwrap()
3396    }
3397
3398    /// Array of offsets to ChainedClassSequenceRule tables, from
3399    /// beginning of ChainedClassSequenceRuleSet
3400    pub fn chained_class_seq_rule_offsets(&self) -> &'a [BigEndian<Offset16>] {
3401        let range = self.chained_class_seq_rule_offsets_byte_range();
3402        self.data.read_array(range).ok().unwrap_or_default()
3403    }
3404
3405    /// A dynamically resolving wrapper for [`chained_class_seq_rule_offsets`][Self::chained_class_seq_rule_offsets].
3406    pub fn chained_class_seq_rules(
3407        &self,
3408    ) -> ArrayOfOffsets<'a, ChainedClassSequenceRule<'a>, Offset16> {
3409        let data = self.data;
3410        let offsets = self.chained_class_seq_rule_offsets();
3411        ArrayOfOffsets::new(offsets, data, ())
3412    }
3413
3414    pub fn chained_class_seq_rule_count_byte_range(&self) -> Range<usize> {
3415        let start = 0;
3416        start..start + u16::RAW_BYTE_LEN
3417    }
3418
3419    pub fn chained_class_seq_rule_offsets_byte_range(&self) -> Range<usize> {
3420        let chained_class_seq_rule_count = self.chained_class_seq_rule_count();
3421        let start = self.chained_class_seq_rule_count_byte_range().end;
3422        start
3423            ..start + (chained_class_seq_rule_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3424    }
3425}
3426
3427const _: () = assert!(FontData::default_data_long_enough(
3428    ChainedClassSequenceRuleSet::MIN_SIZE
3429));
3430
3431impl Default for ChainedClassSequenceRuleSet<'_> {
3432    fn default() -> Self {
3433        Self {
3434            data: FontData::default_table_data(),
3435        }
3436    }
3437}
3438
3439#[cfg(feature = "experimental_traverse")]
3440impl<'a> SomeTable<'a> for ChainedClassSequenceRuleSet<'a> {
3441    fn type_name(&self) -> &str {
3442        "ChainedClassSequenceRuleSet"
3443    }
3444    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3445        match idx {
3446            0usize => Some(Field::new(
3447                "chained_class_seq_rule_count",
3448                self.chained_class_seq_rule_count(),
3449            )),
3450            1usize => Some(Field::new(
3451                "chained_class_seq_rule_offsets",
3452                FieldType::from(self.chained_class_seq_rules()),
3453            )),
3454            _ => None,
3455        }
3456    }
3457}
3458
3459#[cfg(feature = "experimental_traverse")]
3460#[allow(clippy::needless_lifetimes)]
3461impl<'a> std::fmt::Debug for ChainedClassSequenceRuleSet<'a> {
3462    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3463        (self as &dyn SomeTable<'a>).fmt(f)
3464    }
3465}
3466
3467impl<'a> MinByteRange<'a> for ChainedClassSequenceRule<'a> {
3468    fn min_byte_range(&self) -> Range<usize> {
3469        0..self.seq_lookup_records_byte_range().end
3470    }
3471    fn min_table_bytes(&self) -> &'a [u8] {
3472        let range = self.min_byte_range();
3473        self.data.as_bytes().get(range).unwrap_or_default()
3474    }
3475}
3476
3477impl<'a> FontRead<'a> for ChainedClassSequenceRule<'a> {
3478    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3479        #[allow(clippy::absurd_extreme_comparisons)]
3480        if data.len() < Self::MIN_SIZE {
3481            return Err(ReadError::OutOfBounds);
3482        }
3483        Ok(Self { data })
3484    }
3485}
3486
3487/// Part of [ChainedSequenceContextFormat2]
3488#[derive(Clone)]
3489pub struct ChainedClassSequenceRule<'a> {
3490    data: FontData<'a>,
3491}
3492
3493#[allow(clippy::needless_lifetimes)]
3494impl<'a> ChainedClassSequenceRule<'a> {
3495    pub const MIN_SIZE: usize =
3496        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
3497    basic_table_impls!(impl_the_methods);
3498
3499    /// Number of glyphs in the backtrack sequence
3500    pub fn backtrack_glyph_count(&self) -> u16 {
3501        let range = self.backtrack_glyph_count_byte_range();
3502        self.data.read_at(range.start).ok().unwrap()
3503    }
3504
3505    /// Array of backtrack-sequence classes
3506    pub fn backtrack_sequence(&self) -> &'a [BigEndian<u16>] {
3507        let range = self.backtrack_sequence_byte_range();
3508        self.data.read_array(range).ok().unwrap_or_default()
3509    }
3510
3511    /// Total number of glyphs in the input sequence
3512    pub fn input_glyph_count(&self) -> u16 {
3513        let range = self.input_glyph_count_byte_range();
3514        self.data.read_at(range.start).ok().unwrap_or_default()
3515    }
3516
3517    /// Array of input sequence classes, beginning with the second
3518    /// glyph position
3519    pub fn input_sequence(&self) -> &'a [BigEndian<u16>] {
3520        let range = self.input_sequence_byte_range();
3521        self.data.read_array(range).ok().unwrap_or_default()
3522    }
3523
3524    /// Number of glyphs in the lookahead sequence
3525    pub fn lookahead_glyph_count(&self) -> u16 {
3526        let range = self.lookahead_glyph_count_byte_range();
3527        self.data.read_at(range.start).ok().unwrap_or_default()
3528    }
3529
3530    /// Array of lookahead-sequence classes
3531    pub fn lookahead_sequence(&self) -> &'a [BigEndian<u16>] {
3532        let range = self.lookahead_sequence_byte_range();
3533        self.data.read_array(range).ok().unwrap_or_default()
3534    }
3535
3536    /// Number of SequenceLookupRecords
3537    pub fn seq_lookup_count(&self) -> u16 {
3538        let range = self.seq_lookup_count_byte_range();
3539        self.data.read_at(range.start).ok().unwrap_or_default()
3540    }
3541
3542    /// Array of SequenceLookupRecords
3543    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3544        let range = self.seq_lookup_records_byte_range();
3545        self.data.read_array(range).ok().unwrap_or_default()
3546    }
3547
3548    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3549        let start = 0;
3550        start..start + u16::RAW_BYTE_LEN
3551    }
3552
3553    pub fn backtrack_sequence_byte_range(&self) -> Range<usize> {
3554        let backtrack_glyph_count = self.backtrack_glyph_count();
3555        let start = self.backtrack_glyph_count_byte_range().end;
3556        start..start + (backtrack_glyph_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
3557    }
3558
3559    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3560        let start = self.backtrack_sequence_byte_range().end;
3561        start..start + u16::RAW_BYTE_LEN
3562    }
3563
3564    pub fn input_sequence_byte_range(&self) -> Range<usize> {
3565        let input_glyph_count = self.input_glyph_count();
3566        let start = self.input_glyph_count_byte_range().end;
3567        start
3568            ..start
3569                + (transforms::subtract(input_glyph_count, 1_usize))
3570                    .saturating_mul(u16::RAW_BYTE_LEN)
3571    }
3572
3573    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3574        let start = self.input_sequence_byte_range().end;
3575        start..start + u16::RAW_BYTE_LEN
3576    }
3577
3578    pub fn lookahead_sequence_byte_range(&self) -> Range<usize> {
3579        let lookahead_glyph_count = self.lookahead_glyph_count();
3580        let start = self.lookahead_glyph_count_byte_range().end;
3581        start..start + (lookahead_glyph_count as usize).saturating_mul(u16::RAW_BYTE_LEN)
3582    }
3583
3584    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3585        let start = self.lookahead_sequence_byte_range().end;
3586        start..start + u16::RAW_BYTE_LEN
3587    }
3588
3589    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3590        let seq_lookup_count = self.seq_lookup_count();
3591        let start = self.seq_lookup_count_byte_range().end;
3592        start
3593            ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3594    }
3595}
3596
3597const _: () = assert!(FontData::default_data_long_enough(
3598    ChainedClassSequenceRule::MIN_SIZE
3599));
3600
3601impl Default for ChainedClassSequenceRule<'_> {
3602    fn default() -> Self {
3603        Self {
3604            data: FontData::default_table_data(),
3605        }
3606    }
3607}
3608
3609#[cfg(feature = "experimental_traverse")]
3610impl<'a> SomeTable<'a> for ChainedClassSequenceRule<'a> {
3611    fn type_name(&self) -> &str {
3612        "ChainedClassSequenceRule"
3613    }
3614    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3615        match idx {
3616            0usize => Some(Field::new(
3617                "backtrack_glyph_count",
3618                self.backtrack_glyph_count(),
3619            )),
3620            1usize => Some(Field::new("backtrack_sequence", self.backtrack_sequence())),
3621            2usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3622            3usize => Some(Field::new("input_sequence", self.input_sequence())),
3623            4usize => Some(Field::new(
3624                "lookahead_glyph_count",
3625                self.lookahead_glyph_count(),
3626            )),
3627            5usize => Some(Field::new("lookahead_sequence", self.lookahead_sequence())),
3628            6usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3629            7usize => Some(Field::new(
3630                "seq_lookup_records",
3631                traversal::FieldType::array_of_records(
3632                    stringify!(SequenceLookupRecord),
3633                    self.seq_lookup_records(),
3634                    self.offset_data(),
3635                ),
3636            )),
3637            _ => None,
3638        }
3639    }
3640}
3641
3642#[cfg(feature = "experimental_traverse")]
3643#[allow(clippy::needless_lifetimes)]
3644impl<'a> std::fmt::Debug for ChainedClassSequenceRule<'a> {
3645    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3646        (self as &dyn SomeTable<'a>).fmt(f)
3647    }
3648}
3649
3650impl Format<u16> for ChainedSequenceContextFormat3<'_> {
3651    const FORMAT: u16 = 3;
3652}
3653
3654impl<'a> MinByteRange<'a> for ChainedSequenceContextFormat3<'a> {
3655    fn min_byte_range(&self) -> Range<usize> {
3656        0..self.seq_lookup_records_byte_range().end
3657    }
3658    fn min_table_bytes(&self) -> &'a [u8] {
3659        let range = self.min_byte_range();
3660        self.data.as_bytes().get(range).unwrap_or_default()
3661    }
3662}
3663
3664impl<'a> FontRead<'a> for ChainedSequenceContextFormat3<'a> {
3665    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3666        #[allow(clippy::absurd_extreme_comparisons)]
3667        if data.len() < Self::MIN_SIZE {
3668            return Err(ReadError::OutOfBounds);
3669        }
3670        Ok(Self { data })
3671    }
3672}
3673
3674/// [Chained Sequence Context Format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#chained-sequence-context-format-3-coverage-based-glyph-contexts)
3675#[derive(Clone)]
3676pub struct ChainedSequenceContextFormat3<'a> {
3677    data: FontData<'a>,
3678}
3679
3680#[allow(clippy::needless_lifetimes)]
3681impl<'a> ChainedSequenceContextFormat3<'a> {
3682    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3683        + u16::RAW_BYTE_LEN
3684        + u16::RAW_BYTE_LEN
3685        + u16::RAW_BYTE_LEN
3686        + u16::RAW_BYTE_LEN);
3687    basic_table_impls!(impl_the_methods);
3688
3689    /// Format identifier: format = 3
3690    pub fn format(&self) -> u16 {
3691        let range = self.format_byte_range();
3692        self.data.read_at(range.start).ok().unwrap()
3693    }
3694
3695    /// Number of glyphs in the backtrack sequence
3696    pub fn backtrack_glyph_count(&self) -> u16 {
3697        let range = self.backtrack_glyph_count_byte_range();
3698        self.data.read_at(range.start).ok().unwrap()
3699    }
3700
3701    /// Array of offsets to coverage tables for the backtrack sequence
3702    pub fn backtrack_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3703        let range = self.backtrack_coverage_offsets_byte_range();
3704        self.data.read_array(range).ok().unwrap_or_default()
3705    }
3706
3707    /// A dynamically resolving wrapper for [`backtrack_coverage_offsets`][Self::backtrack_coverage_offsets].
3708    pub fn backtrack_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3709        let data = self.data;
3710        let offsets = self.backtrack_coverage_offsets();
3711        ArrayOfOffsets::new(offsets, data, ())
3712    }
3713
3714    /// Number of glyphs in the input sequence
3715    pub fn input_glyph_count(&self) -> u16 {
3716        let range = self.input_glyph_count_byte_range();
3717        self.data.read_at(range.start).ok().unwrap_or_default()
3718    }
3719
3720    /// Array of offsets to coverage tables for the input sequence
3721    pub fn input_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3722        let range = self.input_coverage_offsets_byte_range();
3723        self.data.read_array(range).ok().unwrap_or_default()
3724    }
3725
3726    /// A dynamically resolving wrapper for [`input_coverage_offsets`][Self::input_coverage_offsets].
3727    pub fn input_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3728        let data = self.data;
3729        let offsets = self.input_coverage_offsets();
3730        ArrayOfOffsets::new(offsets, data, ())
3731    }
3732
3733    /// Number of glyphs in the lookahead sequence
3734    pub fn lookahead_glyph_count(&self) -> u16 {
3735        let range = self.lookahead_glyph_count_byte_range();
3736        self.data.read_at(range.start).ok().unwrap_or_default()
3737    }
3738
3739    /// Array of offsets to coverage tables for the lookahead sequence
3740    pub fn lookahead_coverage_offsets(&self) -> &'a [BigEndian<Offset16>] {
3741        let range = self.lookahead_coverage_offsets_byte_range();
3742        self.data.read_array(range).ok().unwrap_or_default()
3743    }
3744
3745    /// A dynamically resolving wrapper for [`lookahead_coverage_offsets`][Self::lookahead_coverage_offsets].
3746    pub fn lookahead_coverages(&self) -> ArrayOfOffsets<'a, CoverageTable<'a>, Offset16> {
3747        let data = self.data;
3748        let offsets = self.lookahead_coverage_offsets();
3749        ArrayOfOffsets::new(offsets, data, ())
3750    }
3751
3752    /// Number of SequenceLookupRecords
3753    pub fn seq_lookup_count(&self) -> u16 {
3754        let range = self.seq_lookup_count_byte_range();
3755        self.data.read_at(range.start).ok().unwrap_or_default()
3756    }
3757
3758    /// Array of SequenceLookupRecords
3759    pub fn seq_lookup_records(&self) -> &'a [SequenceLookupRecord] {
3760        let range = self.seq_lookup_records_byte_range();
3761        self.data.read_array(range).ok().unwrap_or_default()
3762    }
3763
3764    pub fn format_byte_range(&self) -> Range<usize> {
3765        let start = 0;
3766        start..start + u16::RAW_BYTE_LEN
3767    }
3768
3769    pub fn backtrack_glyph_count_byte_range(&self) -> Range<usize> {
3770        let start = self.format_byte_range().end;
3771        start..start + u16::RAW_BYTE_LEN
3772    }
3773
3774    pub fn backtrack_coverage_offsets_byte_range(&self) -> Range<usize> {
3775        let backtrack_glyph_count = self.backtrack_glyph_count();
3776        let start = self.backtrack_glyph_count_byte_range().end;
3777        start..start + (backtrack_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3778    }
3779
3780    pub fn input_glyph_count_byte_range(&self) -> Range<usize> {
3781        let start = self.backtrack_coverage_offsets_byte_range().end;
3782        start..start + u16::RAW_BYTE_LEN
3783    }
3784
3785    pub fn input_coverage_offsets_byte_range(&self) -> Range<usize> {
3786        let input_glyph_count = self.input_glyph_count();
3787        let start = self.input_glyph_count_byte_range().end;
3788        start..start + (input_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3789    }
3790
3791    pub fn lookahead_glyph_count_byte_range(&self) -> Range<usize> {
3792        let start = self.input_coverage_offsets_byte_range().end;
3793        start..start + u16::RAW_BYTE_LEN
3794    }
3795
3796    pub fn lookahead_coverage_offsets_byte_range(&self) -> Range<usize> {
3797        let lookahead_glyph_count = self.lookahead_glyph_count();
3798        let start = self.lookahead_glyph_count_byte_range().end;
3799        start..start + (lookahead_glyph_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
3800    }
3801
3802    pub fn seq_lookup_count_byte_range(&self) -> Range<usize> {
3803        let start = self.lookahead_coverage_offsets_byte_range().end;
3804        start..start + u16::RAW_BYTE_LEN
3805    }
3806
3807    pub fn seq_lookup_records_byte_range(&self) -> Range<usize> {
3808        let seq_lookup_count = self.seq_lookup_count();
3809        let start = self.seq_lookup_count_byte_range().end;
3810        start
3811            ..start + (seq_lookup_count as usize).saturating_mul(SequenceLookupRecord::RAW_BYTE_LEN)
3812    }
3813}
3814
3815#[cfg(feature = "experimental_traverse")]
3816impl<'a> SomeTable<'a> for ChainedSequenceContextFormat3<'a> {
3817    fn type_name(&self) -> &str {
3818        "ChainedSequenceContextFormat3"
3819    }
3820    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3821        match idx {
3822            0usize => Some(Field::new("format", self.format())),
3823            1usize => Some(Field::new(
3824                "backtrack_glyph_count",
3825                self.backtrack_glyph_count(),
3826            )),
3827            2usize => Some(Field::new(
3828                "backtrack_coverage_offsets",
3829                FieldType::from(self.backtrack_coverages()),
3830            )),
3831            3usize => Some(Field::new("input_glyph_count", self.input_glyph_count())),
3832            4usize => Some(Field::new(
3833                "input_coverage_offsets",
3834                FieldType::from(self.input_coverages()),
3835            )),
3836            5usize => Some(Field::new(
3837                "lookahead_glyph_count",
3838                self.lookahead_glyph_count(),
3839            )),
3840            6usize => Some(Field::new(
3841                "lookahead_coverage_offsets",
3842                FieldType::from(self.lookahead_coverages()),
3843            )),
3844            7usize => Some(Field::new("seq_lookup_count", self.seq_lookup_count())),
3845            8usize => Some(Field::new(
3846                "seq_lookup_records",
3847                traversal::FieldType::array_of_records(
3848                    stringify!(SequenceLookupRecord),
3849                    self.seq_lookup_records(),
3850                    self.offset_data(),
3851                ),
3852            )),
3853            _ => None,
3854        }
3855    }
3856}
3857
3858#[cfg(feature = "experimental_traverse")]
3859#[allow(clippy::needless_lifetimes)]
3860impl<'a> std::fmt::Debug for ChainedSequenceContextFormat3<'a> {
3861    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3862        (self as &dyn SomeTable<'a>).fmt(f)
3863    }
3864}
3865
3866#[derive(Clone)]
3867pub enum ChainedSequenceContext<'a> {
3868    Format1(ChainedSequenceContextFormat1<'a>),
3869    Format2(ChainedSequenceContextFormat2<'a>),
3870    Format3(ChainedSequenceContextFormat3<'a>),
3871}
3872
3873impl Default for ChainedSequenceContext<'_> {
3874    fn default() -> Self {
3875        Self::Format1(Default::default())
3876    }
3877}
3878
3879impl<'a> ChainedSequenceContext<'a> {
3880    ///Return the `FontData` used to resolve offsets for this table.
3881    pub fn offset_data(&self) -> FontData<'a> {
3882        match self {
3883            Self::Format1(item) => item.offset_data(),
3884            Self::Format2(item) => item.offset_data(),
3885            Self::Format3(item) => item.offset_data(),
3886        }
3887    }
3888
3889    /// Format identifier: format = 1
3890    pub fn format(&self) -> u16 {
3891        match self {
3892            Self::Format1(item) => item.format(),
3893            Self::Format2(item) => item.format(),
3894            Self::Format3(item) => item.format(),
3895        }
3896    }
3897}
3898
3899impl<'a> FontRead<'a> for ChainedSequenceContext<'a> {
3900    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
3901        let format: u16 = data.read_at(0usize)?;
3902        match format {
3903            ChainedSequenceContextFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
3904            ChainedSequenceContextFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
3905            ChainedSequenceContextFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
3906            other => Err(ReadError::InvalidFormat(other.into())),
3907        }
3908    }
3909}
3910
3911impl<'a> MinByteRange<'a> for ChainedSequenceContext<'a> {
3912    fn min_byte_range(&self) -> Range<usize> {
3913        match self {
3914            Self::Format1(item) => item.min_byte_range(),
3915            Self::Format2(item) => item.min_byte_range(),
3916            Self::Format3(item) => item.min_byte_range(),
3917        }
3918    }
3919    fn min_table_bytes(&self) -> &'a [u8] {
3920        match self {
3921            Self::Format1(item) => item.min_table_bytes(),
3922            Self::Format2(item) => item.min_table_bytes(),
3923            Self::Format3(item) => item.min_table_bytes(),
3924        }
3925    }
3926}
3927
3928#[cfg(feature = "experimental_traverse")]
3929impl<'a> ChainedSequenceContext<'a> {
3930    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
3931        match self {
3932            Self::Format1(table) => table,
3933            Self::Format2(table) => table,
3934            Self::Format3(table) => table,
3935        }
3936    }
3937}
3938
3939#[cfg(feature = "experimental_traverse")]
3940impl std::fmt::Debug for ChainedSequenceContext<'_> {
3941    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3942        self.dyn_inner().fmt(f)
3943    }
3944}
3945
3946#[cfg(feature = "experimental_traverse")]
3947impl<'a> SomeTable<'a> for ChainedSequenceContext<'a> {
3948    fn type_name(&self) -> &str {
3949        self.dyn_inner().type_name()
3950    }
3951    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3952        self.dyn_inner().get_field(idx)
3953    }
3954}
3955
3956/// [Device](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
3957/// delta formats
3958#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
3959#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3960#[repr(u16)]
3961#[allow(clippy::manual_non_exhaustive)]
3962pub enum DeltaFormat {
3963    /// Signed 2-bit value, 8 values per uint16
3964    #[default]
3965    Local2BitDeltas = 0x0001,
3966    /// Signed 4-bit value, 4 values per uint16
3967    Local4BitDeltas = 0x0002,
3968    /// Signed 8-bit value, 2 values per uint16
3969    Local8BitDeltas = 0x0003,
3970    /// VariationIndex table, contains a delta-set index pair.
3971    VariationIndex = 0x8000,
3972    #[doc(hidden)]
3973    /// If font data is malformed we will map unknown values to this variant
3974    Unknown,
3975}
3976
3977impl DeltaFormat {
3978    /// Create from a raw scalar.
3979    ///
3980    /// This will never fail; unknown values will be mapped to the `Unknown` variant
3981    pub fn new(raw: u16) -> Self {
3982        match raw {
3983            0x0001 => Self::Local2BitDeltas,
3984            0x0002 => Self::Local4BitDeltas,
3985            0x0003 => Self::Local8BitDeltas,
3986            0x8000 => Self::VariationIndex,
3987            _ => Self::Unknown,
3988        }
3989    }
3990}
3991
3992impl font_types::Scalar for DeltaFormat {
3993    type Raw = <u16 as font_types::Scalar>::Raw;
3994    fn to_raw(self) -> Self::Raw {
3995        (self as u16).to_raw()
3996    }
3997    fn from_raw(raw: Self::Raw) -> Self {
3998        let t = <u16>::from_raw(raw);
3999        Self::new(t)
4000    }
4001}
4002
4003#[cfg(feature = "experimental_traverse")]
4004impl<'a> From<DeltaFormat> for FieldType<'a> {
4005    fn from(src: DeltaFormat) -> FieldType<'a> {
4006        (src as u16).into()
4007    }
4008}
4009
4010impl<'a> MinByteRange<'a> for Device<'a> {
4011    fn min_byte_range(&self) -> Range<usize> {
4012        0..self.delta_value_byte_range().end
4013    }
4014    fn min_table_bytes(&self) -> &'a [u8] {
4015        let range = self.min_byte_range();
4016        self.data.as_bytes().get(range).unwrap_or_default()
4017    }
4018}
4019
4020impl<'a> FontRead<'a> for Device<'a> {
4021    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4022        #[allow(clippy::absurd_extreme_comparisons)]
4023        if data.len() < Self::MIN_SIZE {
4024            return Err(ReadError::OutOfBounds);
4025        }
4026        Ok(Self { data })
4027    }
4028}
4029
4030/// [Device Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#device-and-variationindex-tables)
4031#[derive(Clone)]
4032pub struct Device<'a> {
4033    data: FontData<'a>,
4034}
4035
4036#[allow(clippy::needless_lifetimes)]
4037impl<'a> Device<'a> {
4038    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN);
4039    basic_table_impls!(impl_the_methods);
4040
4041    /// Smallest size to correct, in ppem
4042    pub fn start_size(&self) -> u16 {
4043        let range = self.start_size_byte_range();
4044        self.data.read_at(range.start).ok().unwrap()
4045    }
4046
4047    /// Largest size to correct, in ppem
4048    pub fn end_size(&self) -> u16 {
4049        let range = self.end_size_byte_range();
4050        self.data.read_at(range.start).ok().unwrap()
4051    }
4052
4053    /// Format of deltaValue array data: 0x0001, 0x0002, or 0x0003
4054    pub fn delta_format(&self) -> DeltaFormat {
4055        let range = self.delta_format_byte_range();
4056        self.data.read_at(range.start).ok().unwrap()
4057    }
4058
4059    /// Array of compressed data
4060    pub fn delta_value(&self) -> &'a [BigEndian<u16>] {
4061        let range = self.delta_value_byte_range();
4062        self.data.read_array(range).ok().unwrap_or_default()
4063    }
4064
4065    pub fn start_size_byte_range(&self) -> Range<usize> {
4066        let start = 0;
4067        start..start + u16::RAW_BYTE_LEN
4068    }
4069
4070    pub fn end_size_byte_range(&self) -> Range<usize> {
4071        let start = self.start_size_byte_range().end;
4072        start..start + u16::RAW_BYTE_LEN
4073    }
4074
4075    pub fn delta_format_byte_range(&self) -> Range<usize> {
4076        let start = self.end_size_byte_range().end;
4077        start..start + DeltaFormat::RAW_BYTE_LEN
4078    }
4079
4080    pub fn delta_value_byte_range(&self) -> Range<usize> {
4081        let delta_format = self.delta_format();
4082        let start_size = self.start_size();
4083        let end_size = self.end_size();
4084        let start = self.delta_format_byte_range().end;
4085        start
4086            ..start
4087                + (DeltaFormat::value_count(delta_format, start_size, end_size))
4088                    .saturating_mul(u16::RAW_BYTE_LEN)
4089    }
4090}
4091
4092const _: () = assert!(FontData::default_data_long_enough(Device::MIN_SIZE));
4093
4094impl Default for Device<'_> {
4095    fn default() -> Self {
4096        Self {
4097            data: FontData::default_table_data(),
4098        }
4099    }
4100}
4101
4102#[cfg(feature = "experimental_traverse")]
4103impl<'a> SomeTable<'a> for Device<'a> {
4104    fn type_name(&self) -> &str {
4105        "Device"
4106    }
4107    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4108        match idx {
4109            0usize => Some(Field::new("start_size", self.start_size())),
4110            1usize => Some(Field::new("end_size", self.end_size())),
4111            2usize => Some(Field::new("delta_format", self.delta_format())),
4112            3usize => Some(Field::new("delta_value", self.delta_value())),
4113            _ => None,
4114        }
4115    }
4116}
4117
4118#[cfg(feature = "experimental_traverse")]
4119#[allow(clippy::needless_lifetimes)]
4120impl<'a> std::fmt::Debug for Device<'a> {
4121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4122        (self as &dyn SomeTable<'a>).fmt(f)
4123    }
4124}
4125
4126impl<'a> MinByteRange<'a> for VariationIndex<'a> {
4127    fn min_byte_range(&self) -> Range<usize> {
4128        0..self.delta_format_byte_range().end
4129    }
4130    fn min_table_bytes(&self) -> &'a [u8] {
4131        let range = self.min_byte_range();
4132        self.data.as_bytes().get(range).unwrap_or_default()
4133    }
4134}
4135
4136impl<'a> FontRead<'a> for VariationIndex<'a> {
4137    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4138        #[allow(clippy::absurd_extreme_comparisons)]
4139        if data.len() < Self::MIN_SIZE {
4140            return Err(ReadError::OutOfBounds);
4141        }
4142        Ok(Self { data })
4143    }
4144}
4145
4146/// Variation index table
4147#[derive(Clone)]
4148pub struct VariationIndex<'a> {
4149    data: FontData<'a>,
4150}
4151
4152#[allow(clippy::needless_lifetimes)]
4153impl<'a> VariationIndex<'a> {
4154    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + DeltaFormat::RAW_BYTE_LEN);
4155    basic_table_impls!(impl_the_methods);
4156
4157    /// A delta-set outer index — used to select an item variation
4158    /// data subtable within the item variation store.
4159    pub fn delta_set_outer_index(&self) -> u16 {
4160        let range = self.delta_set_outer_index_byte_range();
4161        self.data.read_at(range.start).ok().unwrap()
4162    }
4163
4164    /// A delta-set inner index — used to select a delta-set row
4165    /// within an item variation data subtable.
4166    pub fn delta_set_inner_index(&self) -> u16 {
4167        let range = self.delta_set_inner_index_byte_range();
4168        self.data.read_at(range.start).ok().unwrap()
4169    }
4170
4171    /// Format, = 0x8000
4172    pub fn delta_format(&self) -> DeltaFormat {
4173        let range = self.delta_format_byte_range();
4174        self.data.read_at(range.start).ok().unwrap()
4175    }
4176
4177    pub fn delta_set_outer_index_byte_range(&self) -> Range<usize> {
4178        let start = 0;
4179        start..start + u16::RAW_BYTE_LEN
4180    }
4181
4182    pub fn delta_set_inner_index_byte_range(&self) -> Range<usize> {
4183        let start = self.delta_set_outer_index_byte_range().end;
4184        start..start + u16::RAW_BYTE_LEN
4185    }
4186
4187    pub fn delta_format_byte_range(&self) -> Range<usize> {
4188        let start = self.delta_set_inner_index_byte_range().end;
4189        start..start + DeltaFormat::RAW_BYTE_LEN
4190    }
4191}
4192
4193const _: () = assert!(FontData::default_data_long_enough(VariationIndex::MIN_SIZE));
4194
4195impl Default for VariationIndex<'_> {
4196    fn default() -> Self {
4197        Self {
4198            data: FontData::default_table_data(),
4199        }
4200    }
4201}
4202
4203#[cfg(feature = "experimental_traverse")]
4204impl<'a> SomeTable<'a> for VariationIndex<'a> {
4205    fn type_name(&self) -> &str {
4206        "VariationIndex"
4207    }
4208    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4209        match idx {
4210            0usize => Some(Field::new(
4211                "delta_set_outer_index",
4212                self.delta_set_outer_index(),
4213            )),
4214            1usize => Some(Field::new(
4215                "delta_set_inner_index",
4216                self.delta_set_inner_index(),
4217            )),
4218            2usize => Some(Field::new("delta_format", self.delta_format())),
4219            _ => None,
4220        }
4221    }
4222}
4223
4224#[cfg(feature = "experimental_traverse")]
4225#[allow(clippy::needless_lifetimes)]
4226impl<'a> std::fmt::Debug for VariationIndex<'a> {
4227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4228        (self as &dyn SomeTable<'a>).fmt(f)
4229    }
4230}
4231
4232/// Either a [Device] table (in a non-variable font) or a [VariationIndex] table (in a variable font)
4233#[derive(Clone)]
4234pub enum DeviceOrVariationIndex<'a> {
4235    Device(Device<'a>),
4236    VariationIndex(VariationIndex<'a>),
4237}
4238
4239impl Default for DeviceOrVariationIndex<'_> {
4240    fn default() -> Self {
4241        Self::Device(Default::default())
4242    }
4243}
4244
4245impl<'a> DeviceOrVariationIndex<'a> {
4246    ///Return the `FontData` used to resolve offsets for this table.
4247    pub fn offset_data(&self) -> FontData<'a> {
4248        match self {
4249            Self::Device(item) => item.offset_data(),
4250            Self::VariationIndex(item) => item.offset_data(),
4251        }
4252    }
4253}
4254
4255impl<'a> FontRead<'a> for DeviceOrVariationIndex<'a> {
4256    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4257        let format: DeltaFormat = data.read_at(4usize)?;
4258
4259        #[allow(clippy::redundant_guards)]
4260        match format {
4261            format if format != DeltaFormat::VariationIndex => {
4262                Ok(Self::Device(FontRead::read(data)?))
4263            }
4264            format if format == DeltaFormat::VariationIndex => {
4265                Ok(Self::VariationIndex(FontRead::read(data)?))
4266            }
4267            other => Err(ReadError::InvalidFormat(other.into())),
4268        }
4269    }
4270}
4271
4272impl<'a> MinByteRange<'a> for DeviceOrVariationIndex<'a> {
4273    fn min_byte_range(&self) -> Range<usize> {
4274        match self {
4275            Self::Device(item) => item.min_byte_range(),
4276            Self::VariationIndex(item) => item.min_byte_range(),
4277        }
4278    }
4279    fn min_table_bytes(&self) -> &'a [u8] {
4280        match self {
4281            Self::Device(item) => item.min_table_bytes(),
4282            Self::VariationIndex(item) => item.min_table_bytes(),
4283        }
4284    }
4285}
4286
4287#[cfg(feature = "experimental_traverse")]
4288impl<'a> DeviceOrVariationIndex<'a> {
4289    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
4290        match self {
4291            Self::Device(table) => table,
4292            Self::VariationIndex(table) => table,
4293        }
4294    }
4295}
4296
4297#[cfg(feature = "experimental_traverse")]
4298impl std::fmt::Debug for DeviceOrVariationIndex<'_> {
4299    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4300        self.dyn_inner().fmt(f)
4301    }
4302}
4303
4304#[cfg(feature = "experimental_traverse")]
4305impl<'a> SomeTable<'a> for DeviceOrVariationIndex<'a> {
4306    fn type_name(&self) -> &str {
4307        self.dyn_inner().type_name()
4308    }
4309    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4310        self.dyn_inner().get_field(idx)
4311    }
4312}
4313
4314impl<'a> MinByteRange<'a> for FeatureVariations<'a> {
4315    fn min_byte_range(&self) -> Range<usize> {
4316        0..self.feature_variation_records_byte_range().end
4317    }
4318    fn min_table_bytes(&self) -> &'a [u8] {
4319        let range = self.min_byte_range();
4320        self.data.as_bytes().get(range).unwrap_or_default()
4321    }
4322}
4323
4324impl<'a> FontRead<'a> for FeatureVariations<'a> {
4325    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4326        #[allow(clippy::absurd_extreme_comparisons)]
4327        if data.len() < Self::MIN_SIZE {
4328            return Err(ReadError::OutOfBounds);
4329        }
4330        Ok(Self { data })
4331    }
4332}
4333
4334/// [FeatureVariations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featurevariations-table)
4335#[derive(Clone)]
4336pub struct FeatureVariations<'a> {
4337    data: FontData<'a>,
4338}
4339
4340#[allow(clippy::needless_lifetimes)]
4341impl<'a> FeatureVariations<'a> {
4342    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
4343    basic_table_impls!(impl_the_methods);
4344
4345    pub fn version(&self) -> MajorMinor {
4346        let range = self.version_byte_range();
4347        self.data.read_at(range.start).ok().unwrap()
4348    }
4349
4350    /// Number of feature variation records.
4351    pub fn feature_variation_record_count(&self) -> u32 {
4352        let range = self.feature_variation_record_count_byte_range();
4353        self.data.read_at(range.start).ok().unwrap()
4354    }
4355
4356    /// Array of feature variation records.
4357    pub fn feature_variation_records(&self) -> &'a [FeatureVariationRecord] {
4358        let range = self.feature_variation_records_byte_range();
4359        self.data.read_array(range).ok().unwrap_or_default()
4360    }
4361
4362    pub fn version_byte_range(&self) -> Range<usize> {
4363        let start = 0;
4364        start..start + MajorMinor::RAW_BYTE_LEN
4365    }
4366
4367    pub fn feature_variation_record_count_byte_range(&self) -> Range<usize> {
4368        let start = self.version_byte_range().end;
4369        start..start + u32::RAW_BYTE_LEN
4370    }
4371
4372    pub fn feature_variation_records_byte_range(&self) -> Range<usize> {
4373        let feature_variation_record_count = self.feature_variation_record_count();
4374        let start = self.feature_variation_record_count_byte_range().end;
4375        start
4376            ..start
4377                + (feature_variation_record_count as usize)
4378                    .saturating_mul(FeatureVariationRecord::RAW_BYTE_LEN)
4379    }
4380}
4381
4382const _: () = assert!(FontData::default_data_long_enough(
4383    FeatureVariations::MIN_SIZE
4384));
4385
4386impl Default for FeatureVariations<'_> {
4387    fn default() -> Self {
4388        Self {
4389            data: FontData::default_table_data(),
4390        }
4391    }
4392}
4393
4394#[cfg(feature = "experimental_traverse")]
4395impl<'a> SomeTable<'a> for FeatureVariations<'a> {
4396    fn type_name(&self) -> &str {
4397        "FeatureVariations"
4398    }
4399    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4400        match idx {
4401            0usize => Some(Field::new("version", self.version())),
4402            1usize => Some(Field::new(
4403                "feature_variation_record_count",
4404                self.feature_variation_record_count(),
4405            )),
4406            2usize => Some(Field::new(
4407                "feature_variation_records",
4408                traversal::FieldType::array_of_records(
4409                    stringify!(FeatureVariationRecord),
4410                    self.feature_variation_records(),
4411                    self.offset_data(),
4412                ),
4413            )),
4414            _ => None,
4415        }
4416    }
4417}
4418
4419#[cfg(feature = "experimental_traverse")]
4420#[allow(clippy::needless_lifetimes)]
4421impl<'a> std::fmt::Debug for FeatureVariations<'a> {
4422    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4423        (self as &dyn SomeTable<'a>).fmt(f)
4424    }
4425}
4426
4427/// Part of [FeatureVariations]
4428#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
4429#[repr(C)]
4430#[repr(packed)]
4431pub struct FeatureVariationRecord {
4432    /// Offset to a condition set table, from beginning of
4433    /// FeatureVariations table.
4434    pub condition_set_offset: BigEndian<Nullable<Offset32>>,
4435    /// Offset to a feature table substitution table, from beginning of
4436    /// the FeatureVariations table.
4437    pub feature_table_substitution_offset: BigEndian<Nullable<Offset32>>,
4438}
4439
4440impl FeatureVariationRecord {
4441    /// Offset to a condition set table, from beginning of
4442    /// FeatureVariations table.
4443    pub fn condition_set_offset(&self) -> Nullable<Offset32> {
4444        self.condition_set_offset.get()
4445    }
4446
4447    /// Offset to a condition set table, from beginning of
4448    /// FeatureVariations table.
4449    ///
4450    /// The `data` argument should be retrieved from the parent table
4451    /// By calling its `offset_data` method.
4452    pub fn condition_set<'a>(
4453        &self,
4454        data: FontData<'a>,
4455    ) -> Option<Result<ConditionSet<'a>, ReadError>> {
4456        self.condition_set_offset().resolve(data)
4457    }
4458
4459    /// Offset to a feature table substitution table, from beginning of
4460    /// the FeatureVariations table.
4461    pub fn feature_table_substitution_offset(&self) -> Nullable<Offset32> {
4462        self.feature_table_substitution_offset.get()
4463    }
4464
4465    /// Offset to a feature table substitution table, from beginning of
4466    /// the FeatureVariations table.
4467    ///
4468    /// The `data` argument should be retrieved from the parent table
4469    /// By calling its `offset_data` method.
4470    pub fn feature_table_substitution<'a>(
4471        &self,
4472        data: FontData<'a>,
4473    ) -> Option<Result<FeatureTableSubstitution<'a>, ReadError>> {
4474        self.feature_table_substitution_offset().resolve(data)
4475    }
4476}
4477
4478impl FixedSize for FeatureVariationRecord {
4479    const RAW_BYTE_LEN: usize = Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
4480}
4481
4482#[cfg(feature = "experimental_traverse")]
4483impl<'a> SomeRecord<'a> for FeatureVariationRecord {
4484    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
4485        RecordResolver {
4486            name: "FeatureVariationRecord",
4487            get_field: Box::new(move |idx, _data| match idx {
4488                0usize => Some(Field::new(
4489                    "condition_set_offset",
4490                    FieldType::offset(self.condition_set_offset(), self.condition_set(_data)),
4491                )),
4492                1usize => Some(Field::new(
4493                    "feature_table_substitution_offset",
4494                    FieldType::offset(
4495                        self.feature_table_substitution_offset(),
4496                        self.feature_table_substitution(_data),
4497                    ),
4498                )),
4499                _ => None,
4500            }),
4501            data,
4502        }
4503    }
4504}
4505
4506impl<'a> MinByteRange<'a> for ConditionSet<'a> {
4507    fn min_byte_range(&self) -> Range<usize> {
4508        0..self.condition_offsets_byte_range().end
4509    }
4510    fn min_table_bytes(&self) -> &'a [u8] {
4511        let range = self.min_byte_range();
4512        self.data.as_bytes().get(range).unwrap_or_default()
4513    }
4514}
4515
4516impl<'a> FontRead<'a> for ConditionSet<'a> {
4517    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4518        #[allow(clippy::absurd_extreme_comparisons)]
4519        if data.len() < Self::MIN_SIZE {
4520            return Err(ReadError::OutOfBounds);
4521        }
4522        Ok(Self { data })
4523    }
4524}
4525
4526/// [ConditionSet Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#conditionset-table)
4527#[derive(Clone)]
4528pub struct ConditionSet<'a> {
4529    data: FontData<'a>,
4530}
4531
4532#[allow(clippy::needless_lifetimes)]
4533impl<'a> ConditionSet<'a> {
4534    pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
4535    basic_table_impls!(impl_the_methods);
4536
4537    /// Number of conditions for this condition set.
4538    pub fn condition_count(&self) -> u16 {
4539        let range = self.condition_count_byte_range();
4540        self.data.read_at(range.start).ok().unwrap()
4541    }
4542
4543    /// Array of offsets to condition tables, from beginning of the
4544    /// ConditionSet table.
4545    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset32>] {
4546        let range = self.condition_offsets_byte_range();
4547        self.data.read_array(range).ok().unwrap_or_default()
4548    }
4549
4550    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
4551    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset32> {
4552        let data = self.data;
4553        let offsets = self.condition_offsets();
4554        ArrayOfOffsets::new(offsets, data, ())
4555    }
4556
4557    pub fn condition_count_byte_range(&self) -> Range<usize> {
4558        let start = 0;
4559        start..start + u16::RAW_BYTE_LEN
4560    }
4561
4562    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
4563        let condition_count = self.condition_count();
4564        let start = self.condition_count_byte_range().end;
4565        start..start + (condition_count as usize).saturating_mul(Offset32::RAW_BYTE_LEN)
4566    }
4567}
4568
4569const _: () = assert!(FontData::default_data_long_enough(ConditionSet::MIN_SIZE));
4570
4571impl Default for ConditionSet<'_> {
4572    fn default() -> Self {
4573        Self {
4574            data: FontData::default_table_data(),
4575        }
4576    }
4577}
4578
4579#[cfg(feature = "experimental_traverse")]
4580impl<'a> SomeTable<'a> for ConditionSet<'a> {
4581    fn type_name(&self) -> &str {
4582        "ConditionSet"
4583    }
4584    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4585        match idx {
4586            0usize => Some(Field::new("condition_count", self.condition_count())),
4587            1usize => Some(Field::new(
4588                "condition_offsets",
4589                FieldType::from(self.conditions()),
4590            )),
4591            _ => None,
4592        }
4593    }
4594}
4595
4596#[cfg(feature = "experimental_traverse")]
4597#[allow(clippy::needless_lifetimes)]
4598impl<'a> std::fmt::Debug for ConditionSet<'a> {
4599    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4600        (self as &dyn SomeTable<'a>).fmt(f)
4601    }
4602}
4603
4604/// [Condition Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table)
4605///
4606/// Formats 2..5 are implementations of specification changes currently under debate at ISO for an OFF
4607/// update. For the time being the specification is <https://github.com/harfbuzz/boring-expansion-spec/blob/main/ConditionTree.md>.
4608#[derive(Clone)]
4609pub enum Condition<'a> {
4610    Format1AxisRange(ConditionFormat1<'a>),
4611    Format2VariableValue(ConditionFormat2<'a>),
4612    Format3And(ConditionFormat3<'a>),
4613    Format4Or(ConditionFormat4<'a>),
4614    Format5Negate(ConditionFormat5<'a>),
4615}
4616
4617impl Default for Condition<'_> {
4618    fn default() -> Self {
4619        Self::Format1AxisRange(Default::default())
4620    }
4621}
4622
4623impl<'a> Condition<'a> {
4624    ///Return the `FontData` used to resolve offsets for this table.
4625    pub fn offset_data(&self) -> FontData<'a> {
4626        match self {
4627            Self::Format1AxisRange(item) => item.offset_data(),
4628            Self::Format2VariableValue(item) => item.offset_data(),
4629            Self::Format3And(item) => item.offset_data(),
4630            Self::Format4Or(item) => item.offset_data(),
4631            Self::Format5Negate(item) => item.offset_data(),
4632        }
4633    }
4634
4635    /// Format, = 1
4636    pub fn format(&self) -> u16 {
4637        match self {
4638            Self::Format1AxisRange(item) => item.format(),
4639            Self::Format2VariableValue(item) => item.format(),
4640            Self::Format3And(item) => item.format(),
4641            Self::Format4Or(item) => item.format(),
4642            Self::Format5Negate(item) => item.format(),
4643        }
4644    }
4645}
4646
4647impl<'a> FontRead<'a> for Condition<'a> {
4648    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4649        let format: u16 = data.read_at(0usize)?;
4650        match format {
4651            ConditionFormat1::FORMAT => Ok(Self::Format1AxisRange(FontRead::read(data)?)),
4652            ConditionFormat2::FORMAT => Ok(Self::Format2VariableValue(FontRead::read(data)?)),
4653            ConditionFormat3::FORMAT => Ok(Self::Format3And(FontRead::read(data)?)),
4654            ConditionFormat4::FORMAT => Ok(Self::Format4Or(FontRead::read(data)?)),
4655            ConditionFormat5::FORMAT => Ok(Self::Format5Negate(FontRead::read(data)?)),
4656            other => Err(ReadError::InvalidFormat(other.into())),
4657        }
4658    }
4659}
4660
4661impl<'a> MinByteRange<'a> for Condition<'a> {
4662    fn min_byte_range(&self) -> Range<usize> {
4663        match self {
4664            Self::Format1AxisRange(item) => item.min_byte_range(),
4665            Self::Format2VariableValue(item) => item.min_byte_range(),
4666            Self::Format3And(item) => item.min_byte_range(),
4667            Self::Format4Or(item) => item.min_byte_range(),
4668            Self::Format5Negate(item) => item.min_byte_range(),
4669        }
4670    }
4671    fn min_table_bytes(&self) -> &'a [u8] {
4672        match self {
4673            Self::Format1AxisRange(item) => item.min_table_bytes(),
4674            Self::Format2VariableValue(item) => item.min_table_bytes(),
4675            Self::Format3And(item) => item.min_table_bytes(),
4676            Self::Format4Or(item) => item.min_table_bytes(),
4677            Self::Format5Negate(item) => item.min_table_bytes(),
4678        }
4679    }
4680}
4681
4682#[cfg(feature = "experimental_traverse")]
4683impl<'a> Condition<'a> {
4684    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
4685        match self {
4686            Self::Format1AxisRange(table) => table,
4687            Self::Format2VariableValue(table) => table,
4688            Self::Format3And(table) => table,
4689            Self::Format4Or(table) => table,
4690            Self::Format5Negate(table) => table,
4691        }
4692    }
4693}
4694
4695#[cfg(feature = "experimental_traverse")]
4696impl std::fmt::Debug for Condition<'_> {
4697    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4698        self.dyn_inner().fmt(f)
4699    }
4700}
4701
4702#[cfg(feature = "experimental_traverse")]
4703impl<'a> SomeTable<'a> for Condition<'a> {
4704    fn type_name(&self) -> &str {
4705        self.dyn_inner().type_name()
4706    }
4707    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4708        self.dyn_inner().get_field(idx)
4709    }
4710}
4711
4712impl Format<u16> for ConditionFormat1<'_> {
4713    const FORMAT: u16 = 1;
4714}
4715
4716impl<'a> MinByteRange<'a> for ConditionFormat1<'a> {
4717    fn min_byte_range(&self) -> Range<usize> {
4718        0..self.filter_range_max_value_byte_range().end
4719    }
4720    fn min_table_bytes(&self) -> &'a [u8] {
4721        let range = self.min_byte_range();
4722        self.data.as_bytes().get(range).unwrap_or_default()
4723    }
4724}
4725
4726impl<'a> FontRead<'a> for ConditionFormat1<'a> {
4727    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4728        #[allow(clippy::absurd_extreme_comparisons)]
4729        if data.len() < Self::MIN_SIZE {
4730            return Err(ReadError::OutOfBounds);
4731        }
4732        Ok(Self { data })
4733    }
4734}
4735
4736/// [Condition Table Format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#condition-table-format-1-font-variation-axis-range): Font Variation Axis Range
4737#[derive(Clone)]
4738pub struct ConditionFormat1<'a> {
4739    data: FontData<'a>,
4740}
4741
4742#[allow(clippy::needless_lifetimes)]
4743impl<'a> ConditionFormat1<'a> {
4744    pub const MIN_SIZE: usize =
4745        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN + F2Dot14::RAW_BYTE_LEN);
4746    basic_table_impls!(impl_the_methods);
4747
4748    /// Format, = 1
4749    pub fn format(&self) -> u16 {
4750        let range = self.format_byte_range();
4751        self.data.read_at(range.start).ok().unwrap()
4752    }
4753
4754    /// Index (zero-based) for the variation axis within the 'fvar'
4755    /// table.
4756    pub fn axis_index(&self) -> u16 {
4757        let range = self.axis_index_byte_range();
4758        self.data.read_at(range.start).ok().unwrap()
4759    }
4760
4761    /// Minimum value of the font variation instances that satisfy this
4762    /// condition.
4763    pub fn filter_range_min_value(&self) -> F2Dot14 {
4764        let range = self.filter_range_min_value_byte_range();
4765        self.data.read_at(range.start).ok().unwrap()
4766    }
4767
4768    /// Maximum value of the font variation instances that satisfy this
4769    /// condition.
4770    pub fn filter_range_max_value(&self) -> F2Dot14 {
4771        let range = self.filter_range_max_value_byte_range();
4772        self.data.read_at(range.start).ok().unwrap()
4773    }
4774
4775    pub fn format_byte_range(&self) -> Range<usize> {
4776        let start = 0;
4777        start..start + u16::RAW_BYTE_LEN
4778    }
4779
4780    pub fn axis_index_byte_range(&self) -> Range<usize> {
4781        let start = self.format_byte_range().end;
4782        start..start + u16::RAW_BYTE_LEN
4783    }
4784
4785    pub fn filter_range_min_value_byte_range(&self) -> Range<usize> {
4786        let start = self.axis_index_byte_range().end;
4787        start..start + F2Dot14::RAW_BYTE_LEN
4788    }
4789
4790    pub fn filter_range_max_value_byte_range(&self) -> Range<usize> {
4791        let start = self.filter_range_min_value_byte_range().end;
4792        start..start + F2Dot14::RAW_BYTE_LEN
4793    }
4794}
4795
4796const _: () = assert!(FontData::default_data_long_enough(
4797    ConditionFormat1::MIN_SIZE
4798));
4799
4800impl Default for ConditionFormat1<'_> {
4801    fn default() -> Self {
4802        Self {
4803            data: FontData::default_format_1_u16_table_data(),
4804        }
4805    }
4806}
4807
4808#[cfg(feature = "experimental_traverse")]
4809impl<'a> SomeTable<'a> for ConditionFormat1<'a> {
4810    fn type_name(&self) -> &str {
4811        "ConditionFormat1"
4812    }
4813    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4814        match idx {
4815            0usize => Some(Field::new("format", self.format())),
4816            1usize => Some(Field::new("axis_index", self.axis_index())),
4817            2usize => Some(Field::new(
4818                "filter_range_min_value",
4819                self.filter_range_min_value(),
4820            )),
4821            3usize => Some(Field::new(
4822                "filter_range_max_value",
4823                self.filter_range_max_value(),
4824            )),
4825            _ => None,
4826        }
4827    }
4828}
4829
4830#[cfg(feature = "experimental_traverse")]
4831#[allow(clippy::needless_lifetimes)]
4832impl<'a> std::fmt::Debug for ConditionFormat1<'a> {
4833    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4834        (self as &dyn SomeTable<'a>).fmt(f)
4835    }
4836}
4837
4838impl Format<u16> for ConditionFormat2<'_> {
4839    const FORMAT: u16 = 2;
4840}
4841
4842impl<'a> MinByteRange<'a> for ConditionFormat2<'a> {
4843    fn min_byte_range(&self) -> Range<usize> {
4844        0..self.var_index_byte_range().end
4845    }
4846    fn min_table_bytes(&self) -> &'a [u8] {
4847        let range = self.min_byte_range();
4848        self.data.as_bytes().get(range).unwrap_or_default()
4849    }
4850}
4851
4852impl<'a> FontRead<'a> for ConditionFormat2<'a> {
4853    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4854        #[allow(clippy::absurd_extreme_comparisons)]
4855        if data.len() < Self::MIN_SIZE {
4856            return Err(ReadError::OutOfBounds);
4857        }
4858        Ok(Self { data })
4859    }
4860}
4861
4862/// [Condition Table Format 2](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3237-L3255): Variation index
4863#[derive(Clone)]
4864pub struct ConditionFormat2<'a> {
4865    data: FontData<'a>,
4866}
4867
4868#[allow(clippy::needless_lifetimes)]
4869impl<'a> ConditionFormat2<'a> {
4870    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
4871    basic_table_impls!(impl_the_methods);
4872
4873    /// Format, = 2
4874    pub fn format(&self) -> u16 {
4875        let range = self.format_byte_range();
4876        self.data.read_at(range.start).ok().unwrap()
4877    }
4878
4879    /// Value at default instance.
4880    pub fn default_value(&self) -> i16 {
4881        let range = self.default_value_byte_range();
4882        self.data.read_at(range.start).ok().unwrap()
4883    }
4884
4885    /// Variation index to vary the value based on current designspace location.
4886    pub fn var_index(&self) -> u32 {
4887        let range = self.var_index_byte_range();
4888        self.data.read_at(range.start).ok().unwrap()
4889    }
4890
4891    pub fn format_byte_range(&self) -> Range<usize> {
4892        let start = 0;
4893        start..start + u16::RAW_BYTE_LEN
4894    }
4895
4896    pub fn default_value_byte_range(&self) -> Range<usize> {
4897        let start = self.format_byte_range().end;
4898        start..start + i16::RAW_BYTE_LEN
4899    }
4900
4901    pub fn var_index_byte_range(&self) -> Range<usize> {
4902        let start = self.default_value_byte_range().end;
4903        start..start + u32::RAW_BYTE_LEN
4904    }
4905}
4906
4907#[cfg(feature = "experimental_traverse")]
4908impl<'a> SomeTable<'a> for ConditionFormat2<'a> {
4909    fn type_name(&self) -> &str {
4910        "ConditionFormat2"
4911    }
4912    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4913        match idx {
4914            0usize => Some(Field::new("format", self.format())),
4915            1usize => Some(Field::new("default_value", self.default_value())),
4916            2usize => Some(Field::new("var_index", self.var_index())),
4917            _ => None,
4918        }
4919    }
4920}
4921
4922#[cfg(feature = "experimental_traverse")]
4923#[allow(clippy::needless_lifetimes)]
4924impl<'a> std::fmt::Debug for ConditionFormat2<'a> {
4925    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4926        (self as &dyn SomeTable<'a>).fmt(f)
4927    }
4928}
4929
4930impl Format<u16> for ConditionFormat3<'_> {
4931    const FORMAT: u16 = 3;
4932}
4933
4934impl<'a> MinByteRange<'a> for ConditionFormat3<'a> {
4935    fn min_byte_range(&self) -> Range<usize> {
4936        0..self.condition_offsets_byte_range().end
4937    }
4938    fn min_table_bytes(&self) -> &'a [u8] {
4939        let range = self.min_byte_range();
4940        self.data.as_bytes().get(range).unwrap_or_default()
4941    }
4942}
4943
4944impl<'a> FontRead<'a> for ConditionFormat3<'a> {
4945    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
4946        #[allow(clippy::absurd_extreme_comparisons)]
4947        if data.len() < Self::MIN_SIZE {
4948            return Err(ReadError::OutOfBounds);
4949        }
4950        Ok(Self { data })
4951    }
4952}
4953
4954/// [Condition Table Format 3](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3257-L3275): AND
4955#[derive(Clone)]
4956pub struct ConditionFormat3<'a> {
4957    data: FontData<'a>,
4958}
4959
4960#[allow(clippy::needless_lifetimes)]
4961impl<'a> ConditionFormat3<'a> {
4962    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
4963    basic_table_impls!(impl_the_methods);
4964
4965    /// Format, = 3
4966    pub fn format(&self) -> u16 {
4967        let range = self.format_byte_range();
4968        self.data.read_at(range.start).ok().unwrap()
4969    }
4970
4971    /// Number of conditions.
4972    pub fn condition_count(&self) -> u8 {
4973        let range = self.condition_count_byte_range();
4974        self.data.read_at(range.start).ok().unwrap()
4975    }
4976
4977    /// Array of condition tables for this conjunction (AND) expression.
4978    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
4979        let range = self.condition_offsets_byte_range();
4980        self.data.read_array(range).ok().unwrap_or_default()
4981    }
4982
4983    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
4984    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
4985        let data = self.data;
4986        let offsets = self.condition_offsets();
4987        ArrayOfOffsets::new(offsets, data, ())
4988    }
4989
4990    pub fn format_byte_range(&self) -> Range<usize> {
4991        let start = 0;
4992        start..start + u16::RAW_BYTE_LEN
4993    }
4994
4995    pub fn condition_count_byte_range(&self) -> Range<usize> {
4996        let start = self.format_byte_range().end;
4997        start..start + u8::RAW_BYTE_LEN
4998    }
4999
5000    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
5001        let condition_count = self.condition_count();
5002        let start = self.condition_count_byte_range().end;
5003        start..start + (condition_count as usize).saturating_mul(Offset24::RAW_BYTE_LEN)
5004    }
5005}
5006
5007#[cfg(feature = "experimental_traverse")]
5008impl<'a> SomeTable<'a> for ConditionFormat3<'a> {
5009    fn type_name(&self) -> &str {
5010        "ConditionFormat3"
5011    }
5012    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5013        match idx {
5014            0usize => Some(Field::new("format", self.format())),
5015            1usize => Some(Field::new("condition_count", self.condition_count())),
5016            2usize => Some(Field::new(
5017                "condition_offsets",
5018                FieldType::from(self.conditions()),
5019            )),
5020            _ => None,
5021        }
5022    }
5023}
5024
5025#[cfg(feature = "experimental_traverse")]
5026#[allow(clippy::needless_lifetimes)]
5027impl<'a> std::fmt::Debug for ConditionFormat3<'a> {
5028    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5029        (self as &dyn SomeTable<'a>).fmt(f)
5030    }
5031}
5032
5033impl Format<u16> for ConditionFormat4<'_> {
5034    const FORMAT: u16 = 4;
5035}
5036
5037impl<'a> MinByteRange<'a> for ConditionFormat4<'a> {
5038    fn min_byte_range(&self) -> Range<usize> {
5039        0..self.condition_offsets_byte_range().end
5040    }
5041    fn min_table_bytes(&self) -> &'a [u8] {
5042        let range = self.min_byte_range();
5043        self.data.as_bytes().get(range).unwrap_or_default()
5044    }
5045}
5046
5047impl<'a> FontRead<'a> for ConditionFormat4<'a> {
5048    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5049        #[allow(clippy::absurd_extreme_comparisons)]
5050        if data.len() < Self::MIN_SIZE {
5051            return Err(ReadError::OutOfBounds);
5052        }
5053        Ok(Self { data })
5054    }
5055}
5056
5057/// [Condition Table Format 4](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3276-L3295): OR
5058#[derive(Clone)]
5059pub struct ConditionFormat4<'a> {
5060    data: FontData<'a>,
5061}
5062
5063#[allow(clippy::needless_lifetimes)]
5064impl<'a> ConditionFormat4<'a> {
5065    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
5066    basic_table_impls!(impl_the_methods);
5067
5068    /// Format, = 4
5069    pub fn format(&self) -> u16 {
5070        let range = self.format_byte_range();
5071        self.data.read_at(range.start).ok().unwrap()
5072    }
5073
5074    /// Number of conditions.
5075    pub fn condition_count(&self) -> u8 {
5076        let range = self.condition_count_byte_range();
5077        self.data.read_at(range.start).ok().unwrap()
5078    }
5079
5080    /// Array of condition tables for this disjunction (OR) expression.
5081    pub fn condition_offsets(&self) -> &'a [BigEndian<Offset24>] {
5082        let range = self.condition_offsets_byte_range();
5083        self.data.read_array(range).ok().unwrap_or_default()
5084    }
5085
5086    /// A dynamically resolving wrapper for [`condition_offsets`][Self::condition_offsets].
5087    pub fn conditions(&self) -> ArrayOfOffsets<'a, Condition<'a>, Offset24> {
5088        let data = self.data;
5089        let offsets = self.condition_offsets();
5090        ArrayOfOffsets::new(offsets, data, ())
5091    }
5092
5093    pub fn format_byte_range(&self) -> Range<usize> {
5094        let start = 0;
5095        start..start + u16::RAW_BYTE_LEN
5096    }
5097
5098    pub fn condition_count_byte_range(&self) -> Range<usize> {
5099        let start = self.format_byte_range().end;
5100        start..start + u8::RAW_BYTE_LEN
5101    }
5102
5103    pub fn condition_offsets_byte_range(&self) -> Range<usize> {
5104        let condition_count = self.condition_count();
5105        let start = self.condition_count_byte_range().end;
5106        start..start + (condition_count as usize).saturating_mul(Offset24::RAW_BYTE_LEN)
5107    }
5108}
5109
5110#[cfg(feature = "experimental_traverse")]
5111impl<'a> SomeTable<'a> for ConditionFormat4<'a> {
5112    fn type_name(&self) -> &str {
5113        "ConditionFormat4"
5114    }
5115    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5116        match idx {
5117            0usize => Some(Field::new("format", self.format())),
5118            1usize => Some(Field::new("condition_count", self.condition_count())),
5119            2usize => Some(Field::new(
5120                "condition_offsets",
5121                FieldType::from(self.conditions()),
5122            )),
5123            _ => None,
5124        }
5125    }
5126}
5127
5128#[cfg(feature = "experimental_traverse")]
5129#[allow(clippy::needless_lifetimes)]
5130impl<'a> std::fmt::Debug for ConditionFormat4<'a> {
5131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5132        (self as &dyn SomeTable<'a>).fmt(f)
5133    }
5134}
5135
5136impl Format<u16> for ConditionFormat5<'_> {
5137    const FORMAT: u16 = 5;
5138}
5139
5140impl<'a> MinByteRange<'a> for ConditionFormat5<'a> {
5141    fn min_byte_range(&self) -> Range<usize> {
5142        0..self.condition_offset_byte_range().end
5143    }
5144    fn min_table_bytes(&self) -> &'a [u8] {
5145        let range = self.min_byte_range();
5146        self.data.as_bytes().get(range).unwrap_or_default()
5147    }
5148}
5149
5150impl<'a> FontRead<'a> for ConditionFormat5<'a> {
5151    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5152        #[allow(clippy::absurd_extreme_comparisons)]
5153        if data.len() < Self::MIN_SIZE {
5154            return Err(ReadError::OutOfBounds);
5155        }
5156        Ok(Self { data })
5157    }
5158}
5159
5160/// [Condition Table Format 5](https://github.com/fonttools/fonttools/blob/5e6b12d12fa08abafbeb7570f47707fbedf69a45/Lib/fontTools/ttLib/tables/otData.py#L3296-L3308): NOT
5161#[derive(Clone)]
5162pub struct ConditionFormat5<'a> {
5163    data: FontData<'a>,
5164}
5165
5166#[allow(clippy::needless_lifetimes)]
5167impl<'a> ConditionFormat5<'a> {
5168    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset24::RAW_BYTE_LEN);
5169    basic_table_impls!(impl_the_methods);
5170
5171    /// Format, = 5
5172    pub fn format(&self) -> u16 {
5173        let range = self.format_byte_range();
5174        self.data.read_at(range.start).ok().unwrap()
5175    }
5176
5177    /// Condition to negate.
5178    pub fn condition_offset(&self) -> Offset24 {
5179        let range = self.condition_offset_byte_range();
5180        self.data.read_at(range.start).ok().unwrap()
5181    }
5182
5183    /// Attempt to resolve [`condition_offset`][Self::condition_offset].
5184    pub fn condition(&self) -> Result<Condition<'a>, ReadError> {
5185        let data = self.data;
5186        self.condition_offset().resolve(data)
5187    }
5188
5189    pub fn format_byte_range(&self) -> Range<usize> {
5190        let start = 0;
5191        start..start + u16::RAW_BYTE_LEN
5192    }
5193
5194    pub fn condition_offset_byte_range(&self) -> Range<usize> {
5195        let start = self.format_byte_range().end;
5196        start..start + Offset24::RAW_BYTE_LEN
5197    }
5198}
5199
5200#[cfg(feature = "experimental_traverse")]
5201impl<'a> SomeTable<'a> for ConditionFormat5<'a> {
5202    fn type_name(&self) -> &str {
5203        "ConditionFormat5"
5204    }
5205    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5206        match idx {
5207            0usize => Some(Field::new("format", self.format())),
5208            1usize => Some(Field::new(
5209                "condition_offset",
5210                FieldType::offset(self.condition_offset(), self.condition()),
5211            )),
5212            _ => None,
5213        }
5214    }
5215}
5216
5217#[cfg(feature = "experimental_traverse")]
5218#[allow(clippy::needless_lifetimes)]
5219impl<'a> std::fmt::Debug for ConditionFormat5<'a> {
5220    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5221        (self as &dyn SomeTable<'a>).fmt(f)
5222    }
5223}
5224
5225impl<'a> MinByteRange<'a> for FeatureTableSubstitution<'a> {
5226    fn min_byte_range(&self) -> Range<usize> {
5227        0..self.substitutions_byte_range().end
5228    }
5229    fn min_table_bytes(&self) -> &'a [u8] {
5230        let range = self.min_byte_range();
5231        self.data.as_bytes().get(range).unwrap_or_default()
5232    }
5233}
5234
5235impl<'a> FontRead<'a> for FeatureTableSubstitution<'a> {
5236    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5237        #[allow(clippy::absurd_extreme_comparisons)]
5238        if data.len() < Self::MIN_SIZE {
5239            return Err(ReadError::OutOfBounds);
5240        }
5241        Ok(Self { data })
5242    }
5243}
5244
5245/// [FeatureTableSubstitution Table](https://docs.microsoft.com/en-us/typography/opentype/spec/chapter2#featuretablesubstitution-table)
5246#[derive(Clone)]
5247pub struct FeatureTableSubstitution<'a> {
5248    data: FontData<'a>,
5249}
5250
5251#[allow(clippy::needless_lifetimes)]
5252impl<'a> FeatureTableSubstitution<'a> {
5253    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
5254    basic_table_impls!(impl_the_methods);
5255
5256    /// Major & minor version of the table: (1, 0)
5257    pub fn version(&self) -> MajorMinor {
5258        let range = self.version_byte_range();
5259        self.data.read_at(range.start).ok().unwrap()
5260    }
5261
5262    /// Number of feature table substitution records.
5263    pub fn substitution_count(&self) -> u16 {
5264        let range = self.substitution_count_byte_range();
5265        self.data.read_at(range.start).ok().unwrap()
5266    }
5267
5268    /// Array of feature table substitution records.
5269    pub fn substitutions(&self) -> &'a [FeatureTableSubstitutionRecord] {
5270        let range = self.substitutions_byte_range();
5271        self.data.read_array(range).ok().unwrap_or_default()
5272    }
5273
5274    pub fn version_byte_range(&self) -> Range<usize> {
5275        let start = 0;
5276        start..start + MajorMinor::RAW_BYTE_LEN
5277    }
5278
5279    pub fn substitution_count_byte_range(&self) -> Range<usize> {
5280        let start = self.version_byte_range().end;
5281        start..start + u16::RAW_BYTE_LEN
5282    }
5283
5284    pub fn substitutions_byte_range(&self) -> Range<usize> {
5285        let substitution_count = self.substitution_count();
5286        let start = self.substitution_count_byte_range().end;
5287        start
5288            ..start
5289                + (substitution_count as usize)
5290                    .saturating_mul(FeatureTableSubstitutionRecord::RAW_BYTE_LEN)
5291    }
5292}
5293
5294const _: () = assert!(FontData::default_data_long_enough(
5295    FeatureTableSubstitution::MIN_SIZE
5296));
5297
5298impl Default for FeatureTableSubstitution<'_> {
5299    fn default() -> Self {
5300        Self {
5301            data: FontData::default_table_data(),
5302        }
5303    }
5304}
5305
5306#[cfg(feature = "experimental_traverse")]
5307impl<'a> SomeTable<'a> for FeatureTableSubstitution<'a> {
5308    fn type_name(&self) -> &str {
5309        "FeatureTableSubstitution"
5310    }
5311    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5312        match idx {
5313            0usize => Some(Field::new("version", self.version())),
5314            1usize => Some(Field::new("substitution_count", self.substitution_count())),
5315            2usize => Some(Field::new(
5316                "substitutions",
5317                traversal::FieldType::array_of_records(
5318                    stringify!(FeatureTableSubstitutionRecord),
5319                    self.substitutions(),
5320                    self.offset_data(),
5321                ),
5322            )),
5323            _ => None,
5324        }
5325    }
5326}
5327
5328#[cfg(feature = "experimental_traverse")]
5329#[allow(clippy::needless_lifetimes)]
5330impl<'a> std::fmt::Debug for FeatureTableSubstitution<'a> {
5331    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5332        (self as &dyn SomeTable<'a>).fmt(f)
5333    }
5334}
5335
5336/// Used in [FeatureTableSubstitution]
5337#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
5338#[repr(C)]
5339#[repr(packed)]
5340pub struct FeatureTableSubstitutionRecord {
5341    /// The feature table index to match.
5342    pub feature_index: BigEndian<u16>,
5343    /// Offset to an alternate feature table, from start of the
5344    /// FeatureTableSubstitution table.
5345    pub alternate_feature_offset: BigEndian<Offset32>,
5346}
5347
5348impl FeatureTableSubstitutionRecord {
5349    /// The feature table index to match.
5350    pub fn feature_index(&self) -> u16 {
5351        self.feature_index.get()
5352    }
5353
5354    /// Offset to an alternate feature table, from start of the
5355    /// FeatureTableSubstitution table.
5356    pub fn alternate_feature_offset(&self) -> Offset32 {
5357        self.alternate_feature_offset.get()
5358    }
5359}
5360
5361impl FixedSize for FeatureTableSubstitutionRecord {
5362    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
5363}
5364
5365#[cfg(feature = "experimental_traverse")]
5366impl<'a> SomeRecord<'a> for FeatureTableSubstitutionRecord {
5367    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
5368        RecordResolver {
5369            name: "FeatureTableSubstitutionRecord",
5370            get_field: Box::new(move |idx, _data| match idx {
5371                0usize => Some(Field::new("feature_index", self.feature_index())),
5372                1usize => Some(Field::new(
5373                    "alternate_feature_offset",
5374                    FieldType::offset(
5375                        self.alternate_feature_offset(),
5376                        self.alternate_feature(_data),
5377                    ),
5378                )),
5379                _ => None,
5380            }),
5381            data,
5382        }
5383    }
5384}
5385
5386impl<'a> MinByteRange<'a> for SizeParams<'a> {
5387    fn min_byte_range(&self) -> Range<usize> {
5388        0..self.range_end_byte_range().end
5389    }
5390    fn min_table_bytes(&self) -> &'a [u8] {
5391        let range = self.min_byte_range();
5392        self.data.as_bytes().get(range).unwrap_or_default()
5393    }
5394}
5395
5396impl<'a> FontRead<'a> for SizeParams<'a> {
5397    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5398        #[allow(clippy::absurd_extreme_comparisons)]
5399        if data.len() < Self::MIN_SIZE {
5400            return Err(ReadError::OutOfBounds);
5401        }
5402        Ok(Self { data })
5403    }
5404}
5405
5406#[derive(Clone)]
5407pub struct SizeParams<'a> {
5408    data: FontData<'a>,
5409}
5410
5411#[allow(clippy::needless_lifetimes)]
5412impl<'a> SizeParams<'a> {
5413    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5414        + u16::RAW_BYTE_LEN
5415        + u16::RAW_BYTE_LEN
5416        + u16::RAW_BYTE_LEN
5417        + u16::RAW_BYTE_LEN);
5418    basic_table_impls!(impl_the_methods);
5419
5420    /// The first value represents the design size in 720/inch units (decipoints).
5421    ///
5422    /// The design size entry must be non-zero. When there is a design size but
5423    /// no recommended size range, the rest of the array will consist of zeros.
5424    pub fn design_size(&self) -> u16 {
5425        let range = self.design_size_byte_range();
5426        self.data.read_at(range.start).ok().unwrap()
5427    }
5428
5429    /// The second value has no independent meaning, but serves as an identifier that associates fonts in a subfamily.
5430    ///
5431    /// All fonts which share a Typographic or Font Family name and which differ
5432    /// only by size range shall have the same subfamily value, and no fonts
5433    /// which differ in weight or style shall have the same subfamily value.
5434    /// If this value is zero, the remaining fields in the array will be ignored.
5435    pub fn identifier(&self) -> u16 {
5436        let range = self.identifier_byte_range();
5437        self.data.read_at(range.start).ok().unwrap()
5438    }
5439
5440    /// The third value enables applications to use a single name for the subfamily identified by the second value.
5441    ///
5442    /// If the preceding value is non-zero, this value must be set in the range
5443    /// 256 – 32767 (inclusive). It records the value of a field in the 'name'
5444    /// table, which must contain English-language strings encoded in Windows
5445    /// Unicode and Macintosh Roman, and may contain additional strings localized
5446    /// to other scripts and languages. Each of these strings is the name
5447    /// an application should use, in combination with the family name, to
5448    /// represent the subfamily in a menu. Applications will choose the
5449    /// appropriate version based on their selection criteria.
5450    pub fn name_entry(&self) -> u16 {
5451        let range = self.name_entry_byte_range();
5452        self.data.read_at(range.start).ok().unwrap()
5453    }
5454
5455    /// The fourth and fifth values represent the small end of the recommended
5456    /// usage range (exclusive) and the large end of the recommended usage range
5457    /// (inclusive), stored in 720/inch units (decipoints).
5458    ///
5459    /// Ranges must not overlap, and should generally be contiguous.
5460    pub fn range_start(&self) -> u16 {
5461        let range = self.range_start_byte_range();
5462        self.data.read_at(range.start).ok().unwrap()
5463    }
5464
5465    pub fn range_end(&self) -> u16 {
5466        let range = self.range_end_byte_range();
5467        self.data.read_at(range.start).ok().unwrap()
5468    }
5469
5470    pub fn design_size_byte_range(&self) -> Range<usize> {
5471        let start = 0;
5472        start..start + u16::RAW_BYTE_LEN
5473    }
5474
5475    pub fn identifier_byte_range(&self) -> Range<usize> {
5476        let start = self.design_size_byte_range().end;
5477        start..start + u16::RAW_BYTE_LEN
5478    }
5479
5480    pub fn name_entry_byte_range(&self) -> Range<usize> {
5481        let start = self.identifier_byte_range().end;
5482        start..start + u16::RAW_BYTE_LEN
5483    }
5484
5485    pub fn range_start_byte_range(&self) -> Range<usize> {
5486        let start = self.name_entry_byte_range().end;
5487        start..start + u16::RAW_BYTE_LEN
5488    }
5489
5490    pub fn range_end_byte_range(&self) -> Range<usize> {
5491        let start = self.range_start_byte_range().end;
5492        start..start + u16::RAW_BYTE_LEN
5493    }
5494}
5495
5496const _: () = assert!(FontData::default_data_long_enough(SizeParams::MIN_SIZE));
5497
5498impl Default for SizeParams<'_> {
5499    fn default() -> Self {
5500        Self {
5501            data: FontData::default_table_data(),
5502        }
5503    }
5504}
5505
5506#[cfg(feature = "experimental_traverse")]
5507impl<'a> SomeTable<'a> for SizeParams<'a> {
5508    fn type_name(&self) -> &str {
5509        "SizeParams"
5510    }
5511    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5512        match idx {
5513            0usize => Some(Field::new("design_size", self.design_size())),
5514            1usize => Some(Field::new("identifier", self.identifier())),
5515            2usize => Some(Field::new("name_entry", self.name_entry())),
5516            3usize => Some(Field::new("range_start", self.range_start())),
5517            4usize => Some(Field::new("range_end", self.range_end())),
5518            _ => None,
5519        }
5520    }
5521}
5522
5523#[cfg(feature = "experimental_traverse")]
5524#[allow(clippy::needless_lifetimes)]
5525impl<'a> std::fmt::Debug for SizeParams<'a> {
5526    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5527        (self as &dyn SomeTable<'a>).fmt(f)
5528    }
5529}
5530
5531impl<'a> MinByteRange<'a> for StylisticSetParams<'a> {
5532    fn min_byte_range(&self) -> Range<usize> {
5533        0..self.ui_name_id_byte_range().end
5534    }
5535    fn min_table_bytes(&self) -> &'a [u8] {
5536        let range = self.min_byte_range();
5537        self.data.as_bytes().get(range).unwrap_or_default()
5538    }
5539}
5540
5541impl<'a> FontRead<'a> for StylisticSetParams<'a> {
5542    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5543        #[allow(clippy::absurd_extreme_comparisons)]
5544        if data.len() < Self::MIN_SIZE {
5545            return Err(ReadError::OutOfBounds);
5546        }
5547        Ok(Self { data })
5548    }
5549}
5550
5551#[derive(Clone)]
5552pub struct StylisticSetParams<'a> {
5553    data: FontData<'a>,
5554}
5555
5556#[allow(clippy::needless_lifetimes)]
5557impl<'a> StylisticSetParams<'a> {
5558    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN);
5559    basic_table_impls!(impl_the_methods);
5560
5561    pub fn version(&self) -> u16 {
5562        let range = self.version_byte_range();
5563        self.data.read_at(range.start).ok().unwrap()
5564    }
5565
5566    /// The 'name' table name ID that specifies a string (or strings, for
5567    /// multiple languages) for a user-interface label for this feature.
5568    ///
5569    /// The value of uiLabelNameId is expected to be in the font-specific name
5570    /// ID range (256-32767), though that is not a requirement in this Feature
5571    /// Parameters specification. The user-interface label for the feature can
5572    /// be provided in multiple languages. An English string should be included
5573    /// as a fallback. The string should be kept to a minimal length to fit
5574    /// comfortably with different application interfaces.
5575    pub fn ui_name_id(&self) -> NameId {
5576        let range = self.ui_name_id_byte_range();
5577        self.data.read_at(range.start).ok().unwrap()
5578    }
5579
5580    pub fn version_byte_range(&self) -> Range<usize> {
5581        let start = 0;
5582        start..start + u16::RAW_BYTE_LEN
5583    }
5584
5585    pub fn ui_name_id_byte_range(&self) -> Range<usize> {
5586        let start = self.version_byte_range().end;
5587        start..start + NameId::RAW_BYTE_LEN
5588    }
5589}
5590
5591const _: () = assert!(FontData::default_data_long_enough(
5592    StylisticSetParams::MIN_SIZE
5593));
5594
5595impl Default for StylisticSetParams<'_> {
5596    fn default() -> Self {
5597        Self {
5598            data: FontData::default_table_data(),
5599        }
5600    }
5601}
5602
5603#[cfg(feature = "experimental_traverse")]
5604impl<'a> SomeTable<'a> for StylisticSetParams<'a> {
5605    fn type_name(&self) -> &str {
5606        "StylisticSetParams"
5607    }
5608    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5609        match idx {
5610            0usize => Some(Field::new("version", self.version())),
5611            1usize => Some(Field::new("ui_name_id", self.ui_name_id())),
5612            _ => None,
5613        }
5614    }
5615}
5616
5617#[cfg(feature = "experimental_traverse")]
5618#[allow(clippy::needless_lifetimes)]
5619impl<'a> std::fmt::Debug for StylisticSetParams<'a> {
5620    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5621        (self as &dyn SomeTable<'a>).fmt(f)
5622    }
5623}
5624
5625impl Format<u16> for CharacterVariantParams<'_> {
5626    const FORMAT: u16 = 0;
5627}
5628
5629impl<'a> MinByteRange<'a> for CharacterVariantParams<'a> {
5630    fn min_byte_range(&self) -> Range<usize> {
5631        0..self.character_byte_range().end
5632    }
5633    fn min_table_bytes(&self) -> &'a [u8] {
5634        let range = self.min_byte_range();
5635        self.data.as_bytes().get(range).unwrap_or_default()
5636    }
5637}
5638
5639impl<'a> FontRead<'a> for CharacterVariantParams<'a> {
5640    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
5641        #[allow(clippy::absurd_extreme_comparisons)]
5642        if data.len() < Self::MIN_SIZE {
5643            return Err(ReadError::OutOfBounds);
5644        }
5645        Ok(Self { data })
5646    }
5647}
5648
5649/// featureParams for ['cv01'-'cv99'](https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99)
5650#[derive(Clone)]
5651pub struct CharacterVariantParams<'a> {
5652    data: FontData<'a>,
5653}
5654
5655#[allow(clippy::needless_lifetimes)]
5656impl<'a> CharacterVariantParams<'a> {
5657    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
5658        + NameId::RAW_BYTE_LEN
5659        + NameId::RAW_BYTE_LEN
5660        + NameId::RAW_BYTE_LEN
5661        + u16::RAW_BYTE_LEN
5662        + NameId::RAW_BYTE_LEN
5663        + u16::RAW_BYTE_LEN);
5664    basic_table_impls!(impl_the_methods);
5665
5666    /// Format number is set to 0.
5667    pub fn format(&self) -> u16 {
5668        let range = self.format_byte_range();
5669        self.data.read_at(range.start).ok().unwrap()
5670    }
5671
5672    /// The 'name' table name ID that specifies a string (or strings,
5673    /// for multiple languages) for a user-interface label for this
5674    /// feature. (May be NULL.)
5675    pub fn feat_ui_label_name_id(&self) -> NameId {
5676        let range = self.feat_ui_label_name_id_byte_range();
5677        self.data.read_at(range.start).ok().unwrap()
5678    }
5679
5680    /// The 'name' table name ID that specifies a string (or strings,
5681    /// for multiple languages) that an application can use for tooltip
5682    /// text for this feature. (May be NULL.)
5683    pub fn feat_ui_tooltip_text_name_id(&self) -> NameId {
5684        let range = self.feat_ui_tooltip_text_name_id_byte_range();
5685        self.data.read_at(range.start).ok().unwrap()
5686    }
5687
5688    /// The 'name' table name ID that specifies sample text that
5689    /// illustrates the effect of this feature. (May be NULL.)
5690    pub fn sample_text_name_id(&self) -> NameId {
5691        let range = self.sample_text_name_id_byte_range();
5692        self.data.read_at(range.start).ok().unwrap()
5693    }
5694
5695    /// Number of named parameters. (May be zero.)
5696    pub fn num_named_parameters(&self) -> u16 {
5697        let range = self.num_named_parameters_byte_range();
5698        self.data.read_at(range.start).ok().unwrap()
5699    }
5700
5701    /// The first 'name' table name ID used to specify strings for
5702    /// user-interface labels for the feature parameters. (Must be zero
5703    /// if numParameters is zero.)
5704    pub fn first_param_ui_label_name_id(&self) -> NameId {
5705        let range = self.first_param_ui_label_name_id_byte_range();
5706        self.data.read_at(range.start).ok().unwrap()
5707    }
5708
5709    /// The count of characters for which this feature provides glyph
5710    /// variants. (May be zero.)
5711    pub fn char_count(&self) -> u16 {
5712        let range = self.char_count_byte_range();
5713        self.data.read_at(range.start).ok().unwrap()
5714    }
5715
5716    /// The Unicode Scalar Value of the characters for which this
5717    /// feature provides glyph variants.
5718    pub fn character(&self) -> &'a [BigEndian<Uint24>] {
5719        let range = self.character_byte_range();
5720        self.data.read_array(range).ok().unwrap_or_default()
5721    }
5722
5723    pub fn format_byte_range(&self) -> Range<usize> {
5724        let start = 0;
5725        start..start + u16::RAW_BYTE_LEN
5726    }
5727
5728    pub fn feat_ui_label_name_id_byte_range(&self) -> Range<usize> {
5729        let start = self.format_byte_range().end;
5730        start..start + NameId::RAW_BYTE_LEN
5731    }
5732
5733    pub fn feat_ui_tooltip_text_name_id_byte_range(&self) -> Range<usize> {
5734        let start = self.feat_ui_label_name_id_byte_range().end;
5735        start..start + NameId::RAW_BYTE_LEN
5736    }
5737
5738    pub fn sample_text_name_id_byte_range(&self) -> Range<usize> {
5739        let start = self.feat_ui_tooltip_text_name_id_byte_range().end;
5740        start..start + NameId::RAW_BYTE_LEN
5741    }
5742
5743    pub fn num_named_parameters_byte_range(&self) -> Range<usize> {
5744        let start = self.sample_text_name_id_byte_range().end;
5745        start..start + u16::RAW_BYTE_LEN
5746    }
5747
5748    pub fn first_param_ui_label_name_id_byte_range(&self) -> Range<usize> {
5749        let start = self.num_named_parameters_byte_range().end;
5750        start..start + NameId::RAW_BYTE_LEN
5751    }
5752
5753    pub fn char_count_byte_range(&self) -> Range<usize> {
5754        let start = self.first_param_ui_label_name_id_byte_range().end;
5755        start..start + u16::RAW_BYTE_LEN
5756    }
5757
5758    pub fn character_byte_range(&self) -> Range<usize> {
5759        let char_count = self.char_count();
5760        let start = self.char_count_byte_range().end;
5761        start..start + (char_count as usize).saturating_mul(Uint24::RAW_BYTE_LEN)
5762    }
5763}
5764
5765const _: () = assert!(FontData::default_data_long_enough(
5766    CharacterVariantParams::MIN_SIZE
5767));
5768
5769impl Default for CharacterVariantParams<'_> {
5770    fn default() -> Self {
5771        Self {
5772            data: FontData::default_table_data(),
5773        }
5774    }
5775}
5776
5777#[cfg(feature = "experimental_traverse")]
5778impl<'a> SomeTable<'a> for CharacterVariantParams<'a> {
5779    fn type_name(&self) -> &str {
5780        "CharacterVariantParams"
5781    }
5782    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
5783        match idx {
5784            0usize => Some(Field::new("format", self.format())),
5785            1usize => Some(Field::new(
5786                "feat_ui_label_name_id",
5787                self.feat_ui_label_name_id(),
5788            )),
5789            2usize => Some(Field::new(
5790                "feat_ui_tooltip_text_name_id",
5791                self.feat_ui_tooltip_text_name_id(),
5792            )),
5793            3usize => Some(Field::new(
5794                "sample_text_name_id",
5795                self.sample_text_name_id(),
5796            )),
5797            4usize => Some(Field::new(
5798                "num_named_parameters",
5799                self.num_named_parameters(),
5800            )),
5801            5usize => Some(Field::new(
5802                "first_param_ui_label_name_id",
5803                self.first_param_ui_label_name_id(),
5804            )),
5805            6usize => Some(Field::new("char_count", self.char_count())),
5806            7usize => Some(Field::new("character", self.character())),
5807            _ => None,
5808        }
5809    }
5810}
5811
5812#[cfg(feature = "experimental_traverse")]
5813#[allow(clippy::needless_lifetimes)]
5814impl<'a> std::fmt::Debug for CharacterVariantParams<'a> {
5815    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5816        (self as &dyn SomeTable<'a>).fmt(f)
5817    }
5818}