Skip to main content

read_fonts/generated/
generated_layout.rs

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