Skip to main content

read_fonts/generated/
generated_layout.rs

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