Skip to main content

read_fonts/generated/
generated_layout.rs

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