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