Skip to main content

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