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