Skip to main content

write_fonts/generated/
generated_gsub.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
8/// [GSUB](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#gsub-header)
9#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct Gsub {
12    /// Offset to ScriptList table, from beginning of GSUB table
13    pub script_list: NullableOffsetMarker<ScriptList>,
14    /// Offset to FeatureList table, from beginning of GSUB table
15    pub feature_list: NullableOffsetMarker<FeatureList>,
16    /// Offset to LookupList table, from beginning of GSUB table
17    pub lookup_list: NullableOffsetMarker<OriginalSubstitutionLookupList>,
18    /// Offset to FeatureVariations table, from beginning of the GSUB
19    /// table (may be NULL)
20    pub feature_variations: NullableOffsetMarker<FeatureVariations, WIDTH_32>,
21    /// 32-bit offset to ScriptList, taking precedence when nonzero.
22    pub script_list2: NullableOffsetMarker<ScriptList, WIDTH_32>,
23    /// 32-bit offset to FeatureList, taking precedence when nonzero.
24    pub feature_list2: NullableOffsetMarker<FeatureList, WIDTH_32>,
25    /// 32-bit offset to LookupList2, taking precedence when nonzero.
26    pub lookup_list2: NullableOffsetMarker<SubstitutionLookupList2, WIDTH_32>,
27}
28
29impl Default for Gsub {
30    fn default() -> Self {
31        Self {
32            script_list: Some(Default::default()).into(),
33            feature_list: Some(Default::default()).into(),
34            lookup_list: Some(Default::default()).into(),
35            feature_variations: Default::default(),
36            script_list2: Default::default(),
37            feature_list2: Default::default(),
38            lookup_list2: Default::default(),
39        }
40    }
41}
42
43impl FontWrite for Gsub {
44    #[allow(clippy::unnecessary_cast)]
45    fn write_into(&self, writer: &mut TableWriter) {
46        let version = self.compute_version() as MajorMinor;
47        version.write_into(writer);
48        self.script_list.write_into(writer);
49        self.feature_list.write_into(writer);
50        self.lookup_list.write_into(writer);
51        version
52            .compatible((1u16, 1u16))
53            .then(|| self.feature_variations.write_into(writer));
54        version
55            .compatible((1u16, 2u16))
56            .then(|| self.script_list2.write_into(writer));
57        version
58            .compatible((1u16, 2u16))
59            .then(|| self.feature_list2.write_into(writer));
60        version
61            .compatible((1u16, 2u16))
62            .then(|| self.lookup_list2.write_into(writer));
63    }
64    fn table_type(&self) -> TableType {
65        TableType::TopLevel(Gsub::TAG)
66    }
67}
68
69impl Validate for Gsub {
70    fn validate_impl(&self, ctx: &mut ValidationCtx) {
71        ctx.in_table("Gsub", |ctx| {
72            ctx.in_field("script_list", |ctx| {
73                self.script_list.validate_impl(ctx);
74            });
75            ctx.in_field("feature_list", |ctx| {
76                self.feature_list.validate_impl(ctx);
77            });
78            ctx.in_field("lookup_list", |ctx| {
79                self.lookup_list.validate_impl(ctx);
80            });
81            ctx.in_field("feature_variations", |ctx| {
82                self.feature_variations.validate_impl(ctx);
83            });
84            ctx.in_field("script_list2", |ctx| {
85                self.script_list2.validate_impl(ctx);
86            });
87            ctx.in_field("feature_list2", |ctx| {
88                self.feature_list2.validate_impl(ctx);
89            });
90            ctx.in_field("lookup_list2", |ctx| {
91                self.lookup_list2.validate_impl(ctx);
92            });
93        })
94    }
95}
96
97impl TopLevelTable for Gsub {
98    const TAG: Tag = Tag::new(b"GSUB");
99}
100
101impl<'a> FromObjRef<read_fonts::tables::gsub::Gsub<'a>> for Gsub {
102    fn from_obj_ref(obj: &read_fonts::tables::gsub::Gsub<'a>, _: FontData) -> Self {
103        Gsub {
104            script_list: obj.original_script_list().to_owned_table(),
105            feature_list: obj.original_feature_list().to_owned_table(),
106            lookup_list: obj.original_lookup_list().to_owned_table(),
107            feature_variations: obj.feature_variations().to_owned_table(),
108            script_list2: obj.script_list2().to_owned_table(),
109            feature_list2: obj.feature_list2().to_owned_table(),
110            lookup_list2: obj.lookup_list2().to_owned_table(),
111        }
112    }
113}
114
115#[allow(clippy::needless_lifetimes)]
116impl<'a> FromTableRef<read_fonts::tables::gsub::Gsub<'a>> for Gsub {}
117
118impl ReadArgs for Gsub {
119    type Args = ();
120}
121
122impl<'a> FontRead<'a> for Gsub {
123    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
124        <read_fonts::tables::gsub::Gsub as FontRead>::read(data).map(|x| x.to_owned_table())
125    }
126}
127
128/// A [GSUB Lookup](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#gsubLookupTypeEnum) subtable.
129#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
131pub enum SubstitutionLookup {
132    Single(Lookup<SingleSubst>),
133    Multiple(Lookup<MultipleSubst>),
134    Alternate(Lookup<AlternateSubst>),
135    Ligature(Lookup<LigatureSubst>),
136    Contextual(Lookup<SubstitutionSequenceContext>),
137    ChainContextual(Lookup<SubstitutionChainContext>),
138    Extension(Lookup<ExtensionSubtable>),
139    Reverse(Lookup<ReverseChainSingleSubst>),
140}
141
142impl Default for SubstitutionLookup {
143    fn default() -> Self {
144        Self::Single(Default::default())
145    }
146}
147
148impl FontWrite for SubstitutionLookup {
149    fn write_into(&self, writer: &mut TableWriter) {
150        match self {
151            Self::Single(table) => table.write_into(writer),
152            Self::Multiple(table) => table.write_into(writer),
153            Self::Alternate(table) => table.write_into(writer),
154            Self::Ligature(table) => table.write_into(writer),
155            Self::Contextual(table) => table.write_into(writer),
156            Self::ChainContextual(table) => table.write_into(writer),
157            Self::Extension(table) => table.write_into(writer),
158            Self::Reverse(table) => table.write_into(writer),
159        }
160    }
161    fn table_type(&self) -> TableType {
162        match self {
163            Self::Single(table) => table.table_type(),
164            Self::Multiple(table) => table.table_type(),
165            Self::Alternate(table) => table.table_type(),
166            Self::Ligature(table) => table.table_type(),
167            Self::Contextual(table) => table.table_type(),
168            Self::ChainContextual(table) => table.table_type(),
169            Self::Extension(table) => table.table_type(),
170            Self::Reverse(table) => table.table_type(),
171        }
172    }
173}
174
175impl Validate for SubstitutionLookup {
176    fn validate_impl(&self, ctx: &mut ValidationCtx) {
177        match self {
178            Self::Single(table) => table.validate_impl(ctx),
179            Self::Multiple(table) => table.validate_impl(ctx),
180            Self::Alternate(table) => table.validate_impl(ctx),
181            Self::Ligature(table) => table.validate_impl(ctx),
182            Self::Contextual(table) => table.validate_impl(ctx),
183            Self::ChainContextual(table) => table.validate_impl(ctx),
184            Self::Extension(table) => table.validate_impl(ctx),
185            Self::Reverse(table) => table.validate_impl(ctx),
186        }
187    }
188}
189
190impl FromObjRef<read_fonts::tables::gsub::SubstitutionLookup<'_>> for SubstitutionLookup {
191    fn from_obj_ref(
192        from: &read_fonts::tables::gsub::SubstitutionLookup<'_>,
193        data: FontData,
194    ) -> Self {
195        match from {
196            read_fonts::tables::gsub::SubstitutionLookup::Single(table) => {
197                Self::Single(table.to_owned_obj(data))
198            }
199            read_fonts::tables::gsub::SubstitutionLookup::Multiple(table) => {
200                Self::Multiple(table.to_owned_obj(data))
201            }
202            read_fonts::tables::gsub::SubstitutionLookup::Alternate(table) => {
203                Self::Alternate(table.to_owned_obj(data))
204            }
205            read_fonts::tables::gsub::SubstitutionLookup::Ligature(table) => {
206                Self::Ligature(table.to_owned_obj(data))
207            }
208            read_fonts::tables::gsub::SubstitutionLookup::Contextual(table) => {
209                Self::Contextual(table.to_owned_obj(data))
210            }
211            read_fonts::tables::gsub::SubstitutionLookup::ChainContextual(table) => {
212                Self::ChainContextual(table.to_owned_obj(data))
213            }
214            read_fonts::tables::gsub::SubstitutionLookup::Extension(table) => {
215                Self::Extension(table.to_owned_obj(data))
216            }
217            read_fonts::tables::gsub::SubstitutionLookup::Reverse(table) => {
218                Self::Reverse(table.to_owned_obj(data))
219            }
220        }
221    }
222}
223
224impl FromTableRef<read_fonts::tables::gsub::SubstitutionLookup<'_>> for SubstitutionLookup {}
225
226impl From<Lookup<SingleSubst>> for SubstitutionLookup {
227    fn from(src: Lookup<SingleSubst>) -> SubstitutionLookup {
228        SubstitutionLookup::Single(src)
229    }
230}
231
232impl From<Lookup<MultipleSubst>> for SubstitutionLookup {
233    fn from(src: Lookup<MultipleSubst>) -> SubstitutionLookup {
234        SubstitutionLookup::Multiple(src)
235    }
236}
237
238impl From<Lookup<AlternateSubst>> for SubstitutionLookup {
239    fn from(src: Lookup<AlternateSubst>) -> SubstitutionLookup {
240        SubstitutionLookup::Alternate(src)
241    }
242}
243
244impl From<Lookup<LigatureSubst>> for SubstitutionLookup {
245    fn from(src: Lookup<LigatureSubst>) -> SubstitutionLookup {
246        SubstitutionLookup::Ligature(src)
247    }
248}
249
250impl From<Lookup<SubstitutionSequenceContext>> for SubstitutionLookup {
251    fn from(src: Lookup<SubstitutionSequenceContext>) -> SubstitutionLookup {
252        SubstitutionLookup::Contextual(src)
253    }
254}
255
256impl From<Lookup<SubstitutionChainContext>> for SubstitutionLookup {
257    fn from(src: Lookup<SubstitutionChainContext>) -> SubstitutionLookup {
258        SubstitutionLookup::ChainContextual(src)
259    }
260}
261
262impl From<Lookup<ExtensionSubtable>> for SubstitutionLookup {
263    fn from(src: Lookup<ExtensionSubtable>) -> SubstitutionLookup {
264        SubstitutionLookup::Extension(src)
265    }
266}
267
268impl From<Lookup<ReverseChainSingleSubst>> for SubstitutionLookup {
269    fn from(src: Lookup<ReverseChainSingleSubst>) -> SubstitutionLookup {
270        SubstitutionLookup::Reverse(src)
271    }
272}
273
274/// LookupType 1: [Single Substitution](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#lookuptype-1-single-substitution-subtable) Subtable
275#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
276#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
277pub enum SingleSubst {
278    Format1(SingleSubstFormat1),
279    Format2(SingleSubstFormat2),
280    Format3(SingleSubstFormat3),
281    Format4(SingleSubstFormat4),
282}
283
284impl SingleSubst {
285    /// Construct a new `SingleSubstFormat1` subtable
286    pub fn format_1(coverage: CoverageTable, delta_glyph_id: i16) -> Self {
287        Self::Format1(SingleSubstFormat1::new(coverage, delta_glyph_id))
288    }
289
290    /// Construct a new `SingleSubstFormat2` subtable
291    pub fn format_2(coverage: CoverageTable, substitute_glyph_ids: Vec<GlyphId16>) -> Self {
292        Self::Format2(SingleSubstFormat2::new(coverage, substitute_glyph_ids))
293    }
294
295    /// Construct a new `SingleSubstFormat3` subtable
296    pub fn format_3(coverage: CoverageTable, delta_glyph_id: Int24) -> Self {
297        Self::Format3(SingleSubstFormat3::new(coverage, delta_glyph_id))
298    }
299
300    /// Construct a new `SingleSubstFormat4` subtable
301    pub fn format_4(coverage: CoverageTable, substitute_glyph_ids: Vec<GlyphId24>) -> Self {
302        Self::Format4(SingleSubstFormat4::new(coverage, substitute_glyph_ids))
303    }
304}
305
306impl Default for SingleSubst {
307    fn default() -> Self {
308        Self::Format1(Default::default())
309    }
310}
311
312impl FontWrite for SingleSubst {
313    fn write_into(&self, writer: &mut TableWriter) {
314        match self {
315            Self::Format1(item) => item.write_into(writer),
316            Self::Format2(item) => item.write_into(writer),
317            Self::Format3(item) => item.write_into(writer),
318            Self::Format4(item) => item.write_into(writer),
319        }
320    }
321    fn table_type(&self) -> TableType {
322        match self {
323            Self::Format1(item) => item.table_type(),
324            Self::Format2(item) => item.table_type(),
325            Self::Format3(item) => item.table_type(),
326            Self::Format4(item) => item.table_type(),
327        }
328    }
329}
330
331impl Validate for SingleSubst {
332    fn validate_impl(&self, ctx: &mut ValidationCtx) {
333        match self {
334            Self::Format1(item) => item.validate_impl(ctx),
335            Self::Format2(item) => item.validate_impl(ctx),
336            Self::Format3(item) => item.validate_impl(ctx),
337            Self::Format4(item) => item.validate_impl(ctx),
338        }
339    }
340}
341
342impl FromObjRef<read_fonts::tables::gsub::SingleSubst<'_>> for SingleSubst {
343    fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubst, _: FontData) -> Self {
344        use read_fonts::tables::gsub::SingleSubst as ObjRefType;
345        match obj {
346            ObjRefType::Format1(item) => SingleSubst::Format1(item.to_owned_table()),
347            ObjRefType::Format2(item) => SingleSubst::Format2(item.to_owned_table()),
348            ObjRefType::Format3(item) => SingleSubst::Format3(item.to_owned_table()),
349            ObjRefType::Format4(item) => SingleSubst::Format4(item.to_owned_table()),
350        }
351    }
352}
353
354impl FromTableRef<read_fonts::tables::gsub::SingleSubst<'_>> for SingleSubst {}
355
356impl ReadArgs for SingleSubst {
357    type Args = ();
358}
359
360impl<'a> FontRead<'a> for SingleSubst {
361    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
362        <read_fonts::tables::gsub::SingleSubst as FontRead>::read(data).map(|x| x.to_owned_table())
363    }
364}
365
366impl From<SingleSubstFormat1> for SingleSubst {
367    fn from(src: SingleSubstFormat1) -> SingleSubst {
368        SingleSubst::Format1(src)
369    }
370}
371
372impl From<SingleSubstFormat2> for SingleSubst {
373    fn from(src: SingleSubstFormat2) -> SingleSubst {
374        SingleSubst::Format2(src)
375    }
376}
377
378impl From<SingleSubstFormat3> for SingleSubst {
379    fn from(src: SingleSubstFormat3) -> SingleSubst {
380        SingleSubst::Format3(src)
381    }
382}
383
384impl From<SingleSubstFormat4> for SingleSubst {
385    fn from(src: SingleSubstFormat4) -> SingleSubst {
386        SingleSubst::Format4(src)
387    }
388}
389
390/// [Single Substitution Format 1](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#11-single-substitution-format-1)
391#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
392#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
393pub struct SingleSubstFormat1 {
394    /// Offset to Coverage table, from beginning of substitution
395    /// subtable
396    pub coverage: OffsetMarker<CoverageTable>,
397    /// Add to original glyph ID to get substitute glyph ID
398    pub delta_glyph_id: i16,
399}
400
401impl SingleSubstFormat1 {
402    /// Construct a new `SingleSubstFormat1`
403    pub fn new(coverage: CoverageTable, delta_glyph_id: i16) -> Self {
404        Self {
405            coverage: coverage.into(),
406            delta_glyph_id,
407        }
408    }
409}
410
411impl FontWrite for SingleSubstFormat1 {
412    #[allow(clippy::unnecessary_cast)]
413    fn write_into(&self, writer: &mut TableWriter) {
414        (1 as u16).write_into(writer);
415        self.coverage.write_into(writer);
416        self.delta_glyph_id.write_into(writer);
417    }
418    fn table_type(&self) -> TableType {
419        TableType::Named("SingleSubstFormat1")
420    }
421}
422
423impl Validate for SingleSubstFormat1 {
424    fn validate_impl(&self, ctx: &mut ValidationCtx) {
425        ctx.in_table("SingleSubstFormat1", |ctx| {
426            ctx.in_field("coverage", |ctx| {
427                self.coverage.validate_impl(ctx);
428            });
429        })
430    }
431}
432
433impl<'a> FromObjRef<read_fonts::tables::gsub::SingleSubstFormat1<'a>> for SingleSubstFormat1 {
434    fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubstFormat1<'a>, _: FontData) -> Self {
435        SingleSubstFormat1 {
436            coverage: obj.coverage().to_owned_table(),
437            delta_glyph_id: obj.delta_glyph_id(),
438        }
439    }
440}
441
442#[allow(clippy::needless_lifetimes)]
443impl<'a> FromTableRef<read_fonts::tables::gsub::SingleSubstFormat1<'a>> for SingleSubstFormat1 {}
444
445impl ReadArgs for SingleSubstFormat1 {
446    type Args = ();
447}
448
449impl<'a> FontRead<'a> for SingleSubstFormat1 {
450    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
451        <read_fonts::tables::gsub::SingleSubstFormat1 as FontRead>::read(data)
452            .map(|x| x.to_owned_table())
453    }
454}
455
456/// [Single Substitution Format 2](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#12-single-substitution-format-2)
457#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
458#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
459pub struct SingleSubstFormat2 {
460    /// Offset to Coverage table, from beginning of substitution
461    /// subtable
462    pub coverage: OffsetMarker<CoverageTable>,
463    /// Array of substitute glyph IDs — ordered by Coverage index
464    pub substitute_glyph_ids: Vec<GlyphId16>,
465}
466
467impl SingleSubstFormat2 {
468    /// Construct a new `SingleSubstFormat2`
469    pub fn new(coverage: CoverageTable, substitute_glyph_ids: Vec<GlyphId16>) -> Self {
470        Self {
471            coverage: coverage.into(),
472            substitute_glyph_ids,
473        }
474    }
475}
476
477impl FontWrite for SingleSubstFormat2 {
478    #[allow(clippy::unnecessary_cast)]
479    fn write_into(&self, writer: &mut TableWriter) {
480        (2 as u16).write_into(writer);
481        self.coverage.write_into(writer);
482        (u16::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
483        self.substitute_glyph_ids.write_into(writer);
484    }
485    fn table_type(&self) -> TableType {
486        TableType::Named("SingleSubstFormat2")
487    }
488}
489
490impl Validate for SingleSubstFormat2 {
491    fn validate_impl(&self, ctx: &mut ValidationCtx) {
492        ctx.in_table("SingleSubstFormat2", |ctx| {
493            ctx.in_field("coverage", |ctx| {
494                self.coverage.validate_impl(ctx);
495            });
496            ctx.in_field("substitute_glyph_ids", |ctx| {
497                if self.substitute_glyph_ids.len() > to_usize(u16::MAX) {
498                    ctx.report("array exceeds max length");
499                }
500            });
501        })
502    }
503}
504
505impl<'a> FromObjRef<read_fonts::tables::gsub::SingleSubstFormat2<'a>> for SingleSubstFormat2 {
506    fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubstFormat2<'a>, _: FontData) -> Self {
507        let offset_data = obj.offset_data();
508        SingleSubstFormat2 {
509            coverage: obj.coverage().to_owned_table(),
510            substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
511        }
512    }
513}
514
515#[allow(clippy::needless_lifetimes)]
516impl<'a> FromTableRef<read_fonts::tables::gsub::SingleSubstFormat2<'a>> for SingleSubstFormat2 {}
517
518impl ReadArgs for SingleSubstFormat2 {
519    type Args = ();
520}
521
522impl<'a> FontRead<'a> for SingleSubstFormat2 {
523    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
524        <read_fonts::tables::gsub::SingleSubstFormat2 as FontRead>::read(data)
525            .map(|x| x.to_owned_table())
526    }
527}
528
529/// [Multiple Substitution Format 1](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#21-multiple-substitution-format-1)
530#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
531#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
532pub struct MultipleSubstFormat1 {
533    /// Offset to Coverage table, from beginning of substitution
534    /// subtable
535    pub coverage: OffsetMarker<CoverageTable>,
536    /// Array of offsets to Sequence tables. Offsets are from beginning
537    /// of substitution subtable, ordered by Coverage index
538    pub sequences: Vec<OffsetMarker<Sequence>>,
539}
540
541impl MultipleSubstFormat1 {
542    /// Construct a new `MultipleSubstFormat1`
543    pub fn new(coverage: CoverageTable, sequences: Vec<Sequence>) -> Self {
544        Self {
545            coverage: coverage.into(),
546            sequences: sequences.into_iter().map(Into::into).collect(),
547        }
548    }
549}
550
551impl FontWrite for MultipleSubstFormat1 {
552    #[allow(clippy::unnecessary_cast)]
553    fn write_into(&self, writer: &mut TableWriter) {
554        (1 as u16).write_into(writer);
555        self.coverage.write_into(writer);
556        (u16::try_from(array_len(&self.sequences)).unwrap()).write_into(writer);
557        self.sequences.write_into(writer);
558    }
559    fn table_type(&self) -> TableType {
560        TableType::Named("MultipleSubstFormat1")
561    }
562}
563
564impl Validate for MultipleSubstFormat1 {
565    fn validate_impl(&self, ctx: &mut ValidationCtx) {
566        ctx.in_table("MultipleSubstFormat1", |ctx| {
567            ctx.in_field("coverage", |ctx| {
568                self.coverage.validate_impl(ctx);
569            });
570            ctx.in_field("sequences", |ctx| {
571                if self.sequences.len() > to_usize(u16::MAX) {
572                    ctx.report("array exceeds max length");
573                }
574                self.sequences.validate_impl(ctx);
575            });
576        })
577    }
578}
579
580impl<'a> FromObjRef<read_fonts::tables::gsub::MultipleSubstFormat1<'a>> for MultipleSubstFormat1 {
581    fn from_obj_ref(obj: &read_fonts::tables::gsub::MultipleSubstFormat1<'a>, _: FontData) -> Self {
582        MultipleSubstFormat1 {
583            coverage: obj.coverage().to_owned_table(),
584            sequences: obj.sequences().to_owned_table(),
585        }
586    }
587}
588
589#[allow(clippy::needless_lifetimes)]
590impl<'a> FromTableRef<read_fonts::tables::gsub::MultipleSubstFormat1<'a>> for MultipleSubstFormat1 {}
591
592impl ReadArgs for MultipleSubstFormat1 {
593    type Args = ();
594}
595
596impl<'a> FontRead<'a> for MultipleSubstFormat1 {
597    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
598        <read_fonts::tables::gsub::MultipleSubstFormat1 as FontRead>::read(data)
599            .map(|x| x.to_owned_table())
600    }
601}
602
603/// Part of [MultipleSubstFormat1]
604#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
605#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
606pub struct Sequence {
607    /// String of glyph IDs to substitute
608    pub substitute_glyph_ids: Vec<GlyphId16>,
609}
610
611impl Sequence {
612    /// Construct a new `Sequence`
613    pub fn new(substitute_glyph_ids: Vec<GlyphId16>) -> Self {
614        Self {
615            substitute_glyph_ids,
616        }
617    }
618}
619
620impl FontWrite for Sequence {
621    #[allow(clippy::unnecessary_cast)]
622    fn write_into(&self, writer: &mut TableWriter) {
623        (u16::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
624        self.substitute_glyph_ids.write_into(writer);
625    }
626    fn table_type(&self) -> TableType {
627        TableType::Named("Sequence")
628    }
629}
630
631impl Validate for Sequence {
632    fn validate_impl(&self, ctx: &mut ValidationCtx) {
633        ctx.in_table("Sequence", |ctx| {
634            ctx.in_field("substitute_glyph_ids", |ctx| {
635                if self.substitute_glyph_ids.len() > to_usize(u16::MAX) {
636                    ctx.report("array exceeds max length");
637                }
638            });
639        })
640    }
641}
642
643impl<'a> FromObjRef<read_fonts::tables::gsub::Sequence<'a>> for Sequence {
644    fn from_obj_ref(obj: &read_fonts::tables::gsub::Sequence<'a>, _: FontData) -> Self {
645        let offset_data = obj.offset_data();
646        Sequence {
647            substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
648        }
649    }
650}
651
652#[allow(clippy::needless_lifetimes)]
653impl<'a> FromTableRef<read_fonts::tables::gsub::Sequence<'a>> for Sequence {}
654
655impl ReadArgs for Sequence {
656    type Args = ();
657}
658
659impl<'a> FontRead<'a> for Sequence {
660    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
661        <read_fonts::tables::gsub::Sequence as FontRead>::read(data).map(|x| x.to_owned_table())
662    }
663}
664
665/// [Alternate Substitution Format 1](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#31-alternate-substitution-format-1)
666#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
667#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
668pub struct AlternateSubstFormat1 {
669    /// Offset to Coverage table, from beginning of substitution
670    /// subtable
671    pub coverage: OffsetMarker<CoverageTable>,
672    /// Array of offsets to AlternateSet tables. Offsets are from
673    /// beginning of substitution subtable, ordered by Coverage index
674    pub alternate_sets: Vec<OffsetMarker<AlternateSet>>,
675}
676
677impl AlternateSubstFormat1 {
678    /// Construct a new `AlternateSubstFormat1`
679    pub fn new(coverage: CoverageTable, alternate_sets: Vec<AlternateSet>) -> Self {
680        Self {
681            coverage: coverage.into(),
682            alternate_sets: alternate_sets.into_iter().map(Into::into).collect(),
683        }
684    }
685}
686
687impl FontWrite for AlternateSubstFormat1 {
688    #[allow(clippy::unnecessary_cast)]
689    fn write_into(&self, writer: &mut TableWriter) {
690        (1 as u16).write_into(writer);
691        self.coverage.write_into(writer);
692        (u16::try_from(array_len(&self.alternate_sets)).unwrap()).write_into(writer);
693        self.alternate_sets.write_into(writer);
694    }
695    fn table_type(&self) -> TableType {
696        TableType::Named("AlternateSubstFormat1")
697    }
698}
699
700impl Validate for AlternateSubstFormat1 {
701    fn validate_impl(&self, ctx: &mut ValidationCtx) {
702        ctx.in_table("AlternateSubstFormat1", |ctx| {
703            ctx.in_field("coverage", |ctx| {
704                self.coverage.validate_impl(ctx);
705            });
706            ctx.in_field("alternate_sets", |ctx| {
707                if self.alternate_sets.len() > to_usize(u16::MAX) {
708                    ctx.report("array exceeds max length");
709                }
710                self.alternate_sets.validate_impl(ctx);
711            });
712        })
713    }
714}
715
716impl<'a> FromObjRef<read_fonts::tables::gsub::AlternateSubstFormat1<'a>> for AlternateSubstFormat1 {
717    fn from_obj_ref(
718        obj: &read_fonts::tables::gsub::AlternateSubstFormat1<'a>,
719        _: FontData,
720    ) -> Self {
721        AlternateSubstFormat1 {
722            coverage: obj.coverage().to_owned_table(),
723            alternate_sets: obj.alternate_sets().to_owned_table(),
724        }
725    }
726}
727
728#[allow(clippy::needless_lifetimes)]
729impl<'a> FromTableRef<read_fonts::tables::gsub::AlternateSubstFormat1<'a>>
730    for AlternateSubstFormat1
731{
732}
733
734impl ReadArgs for AlternateSubstFormat1 {
735    type Args = ();
736}
737
738impl<'a> FontRead<'a> for AlternateSubstFormat1 {
739    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
740        <read_fonts::tables::gsub::AlternateSubstFormat1 as FontRead>::read(data)
741            .map(|x| x.to_owned_table())
742    }
743}
744
745/// Part of [AlternateSubstFormat1]
746#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
747#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
748pub struct AlternateSet {
749    /// Array of alternate glyph IDs, in arbitrary order
750    pub alternate_glyph_ids: Vec<GlyphId16>,
751}
752
753impl AlternateSet {
754    /// Construct a new `AlternateSet`
755    pub fn new(alternate_glyph_ids: Vec<GlyphId16>) -> Self {
756        Self {
757            alternate_glyph_ids,
758        }
759    }
760}
761
762impl FontWrite for AlternateSet {
763    #[allow(clippy::unnecessary_cast)]
764    fn write_into(&self, writer: &mut TableWriter) {
765        (u16::try_from(array_len(&self.alternate_glyph_ids)).unwrap()).write_into(writer);
766        self.alternate_glyph_ids.write_into(writer);
767    }
768    fn table_type(&self) -> TableType {
769        TableType::Named("AlternateSet")
770    }
771}
772
773impl Validate for AlternateSet {
774    fn validate_impl(&self, ctx: &mut ValidationCtx) {
775        ctx.in_table("AlternateSet", |ctx| {
776            ctx.in_field("alternate_glyph_ids", |ctx| {
777                if self.alternate_glyph_ids.len() > to_usize(u16::MAX) {
778                    ctx.report("array exceeds max length");
779                }
780            });
781        })
782    }
783}
784
785impl<'a> FromObjRef<read_fonts::tables::gsub::AlternateSet<'a>> for AlternateSet {
786    fn from_obj_ref(obj: &read_fonts::tables::gsub::AlternateSet<'a>, _: FontData) -> Self {
787        let offset_data = obj.offset_data();
788        AlternateSet {
789            alternate_glyph_ids: obj.alternate_glyph_ids().to_owned_obj(offset_data),
790        }
791    }
792}
793
794#[allow(clippy::needless_lifetimes)]
795impl<'a> FromTableRef<read_fonts::tables::gsub::AlternateSet<'a>> for AlternateSet {}
796
797impl ReadArgs for AlternateSet {
798    type Args = ();
799}
800
801impl<'a> FontRead<'a> for AlternateSet {
802    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
803        <read_fonts::tables::gsub::AlternateSet as FontRead>::read(data).map(|x| x.to_owned_table())
804    }
805}
806
807/// [Ligature Substitution Format 1](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#41-ligature-substitution-format-1)
808#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
809#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
810pub struct LigatureSubstFormat1 {
811    /// Offset to Coverage table, from beginning of substitution
812    /// subtable
813    pub coverage: OffsetMarker<CoverageTable>,
814    /// Array of offsets to LigatureSet tables. Offsets are from
815    /// beginning of substitution subtable, ordered by Coverage index
816    pub ligature_sets: Vec<OffsetMarker<LigatureSet>>,
817}
818
819impl LigatureSubstFormat1 {
820    /// Construct a new `LigatureSubstFormat1`
821    pub fn new(coverage: CoverageTable, ligature_sets: Vec<LigatureSet>) -> Self {
822        Self {
823            coverage: coverage.into(),
824            ligature_sets: ligature_sets.into_iter().map(Into::into).collect(),
825        }
826    }
827}
828
829impl FontWrite for LigatureSubstFormat1 {
830    #[allow(clippy::unnecessary_cast)]
831    fn write_into(&self, writer: &mut TableWriter) {
832        (1 as u16).write_into(writer);
833        self.coverage.write_into(writer);
834        (u16::try_from(array_len(&self.ligature_sets)).unwrap()).write_into(writer);
835        self.ligature_sets.write_into(writer);
836    }
837    fn table_type(&self) -> TableType {
838        TableType::Named("LigatureSubstFormat1")
839    }
840}
841
842impl Validate for LigatureSubstFormat1 {
843    fn validate_impl(&self, ctx: &mut ValidationCtx) {
844        ctx.in_table("LigatureSubstFormat1", |ctx| {
845            ctx.in_field("coverage", |ctx| {
846                self.coverage.validate_impl(ctx);
847            });
848            ctx.in_field("ligature_sets", |ctx| {
849                if self.ligature_sets.len() > to_usize(u16::MAX) {
850                    ctx.report("array exceeds max length");
851                }
852                self.ligature_sets.validate_impl(ctx);
853            });
854        })
855    }
856}
857
858impl<'a> FromObjRef<read_fonts::tables::gsub::LigatureSubstFormat1<'a>> for LigatureSubstFormat1 {
859    fn from_obj_ref(obj: &read_fonts::tables::gsub::LigatureSubstFormat1<'a>, _: FontData) -> Self {
860        LigatureSubstFormat1 {
861            coverage: obj.coverage().to_owned_table(),
862            ligature_sets: obj.ligature_sets().to_owned_table(),
863        }
864    }
865}
866
867#[allow(clippy::needless_lifetimes)]
868impl<'a> FromTableRef<read_fonts::tables::gsub::LigatureSubstFormat1<'a>> for LigatureSubstFormat1 {}
869
870impl ReadArgs for LigatureSubstFormat1 {
871    type Args = ();
872}
873
874impl<'a> FontRead<'a> for LigatureSubstFormat1 {
875    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
876        <read_fonts::tables::gsub::LigatureSubstFormat1 as FontRead>::read(data)
877            .map(|x| x.to_owned_table())
878    }
879}
880
881/// Part of [LigatureSubstFormat1]
882#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
883#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
884pub struct LigatureSet {
885    /// Array of offsets to Ligature tables. Offsets are from beginning
886    /// of LigatureSet table, ordered by preference.
887    pub ligatures: Vec<OffsetMarker<Ligature>>,
888}
889
890impl LigatureSet {
891    /// Construct a new `LigatureSet`
892    pub fn new(ligatures: Vec<Ligature>) -> Self {
893        Self {
894            ligatures: ligatures.into_iter().map(Into::into).collect(),
895        }
896    }
897}
898
899impl FontWrite for LigatureSet {
900    #[allow(clippy::unnecessary_cast)]
901    fn write_into(&self, writer: &mut TableWriter) {
902        (u16::try_from(array_len(&self.ligatures)).unwrap()).write_into(writer);
903        self.ligatures.write_into(writer);
904    }
905    fn table_type(&self) -> TableType {
906        TableType::Named("LigatureSet")
907    }
908}
909
910impl Validate for LigatureSet {
911    fn validate_impl(&self, ctx: &mut ValidationCtx) {
912        ctx.in_table("LigatureSet", |ctx| {
913            ctx.in_field("ligatures", |ctx| {
914                if self.ligatures.len() > to_usize(u16::MAX) {
915                    ctx.report("array exceeds max length");
916                }
917                self.ligatures.validate_impl(ctx);
918            });
919        })
920    }
921}
922
923impl<'a> FromObjRef<read_fonts::tables::gsub::LigatureSet<'a>> for LigatureSet {
924    fn from_obj_ref(obj: &read_fonts::tables::gsub::LigatureSet<'a>, _: FontData) -> Self {
925        LigatureSet {
926            ligatures: obj.ligatures().to_owned_table(),
927        }
928    }
929}
930
931#[allow(clippy::needless_lifetimes)]
932impl<'a> FromTableRef<read_fonts::tables::gsub::LigatureSet<'a>> for LigatureSet {}
933
934impl ReadArgs for LigatureSet {
935    type Args = ();
936}
937
938impl<'a> FontRead<'a> for LigatureSet {
939    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
940        <read_fonts::tables::gsub::LigatureSet as FontRead>::read(data).map(|x| x.to_owned_table())
941    }
942}
943
944/// Part of [LigatureSubstFormat1]
945#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
946#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
947pub struct Ligature {
948    /// glyph ID of ligature to substitute
949    pub ligature_glyph: GlyphId16,
950    /// Array of component glyph IDs — start with the second
951    /// component, ordered in writing direction
952    pub component_glyph_ids: Vec<GlyphId16>,
953}
954
955impl Ligature {
956    /// Construct a new `Ligature`
957    pub fn new(ligature_glyph: GlyphId16, component_glyph_ids: Vec<GlyphId16>) -> Self {
958        Self {
959            ligature_glyph,
960            component_glyph_ids,
961        }
962    }
963}
964
965impl FontWrite for Ligature {
966    #[allow(clippy::unnecessary_cast)]
967    fn write_into(&self, writer: &mut TableWriter) {
968        self.ligature_glyph.write_into(writer);
969        (u16::try_from(plus_one(&self.component_glyph_ids.len())).unwrap()).write_into(writer);
970        self.component_glyph_ids.write_into(writer);
971    }
972    fn table_type(&self) -> TableType {
973        TableType::Named("Ligature")
974    }
975}
976
977impl Validate for Ligature {
978    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
979}
980
981impl<'a> FromObjRef<read_fonts::tables::gsub::Ligature<'a>> for Ligature {
982    fn from_obj_ref(obj: &read_fonts::tables::gsub::Ligature<'a>, _: FontData) -> Self {
983        let offset_data = obj.offset_data();
984        Ligature {
985            ligature_glyph: obj.ligature_glyph(),
986            component_glyph_ids: obj.component_glyph_ids().to_owned_obj(offset_data),
987        }
988    }
989}
990
991#[allow(clippy::needless_lifetimes)]
992impl<'a> FromTableRef<read_fonts::tables::gsub::Ligature<'a>> for Ligature {}
993
994impl ReadArgs for Ligature {
995    type Args = ();
996}
997
998impl<'a> FontRead<'a> for Ligature {
999    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1000        <read_fonts::tables::gsub::Ligature as FontRead>::read(data).map(|x| x.to_owned_table())
1001    }
1002}
1003
1004/// [Extension Substitution Subtable Format 1](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#71-extension-substitution-subtable-format-1)
1005#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1006#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1007pub struct ExtensionSubstFormat1<T> {
1008    /// Lookup type of subtable referenced by extensionOffset (that is,
1009    /// the extension subtable).
1010    pub extension_lookup_type: u16,
1011    /// Offset to the extension subtable, of lookup type
1012    /// extensionLookupType, relative to the start of the
1013    /// ExtensionSubstFormat1 subtable.
1014    pub extension: OffsetMarker<T, WIDTH_32>,
1015}
1016
1017impl<T: Default> ExtensionSubstFormat1<T> {
1018    /// Construct a new `ExtensionSubstFormat1`
1019    pub fn new(extension_lookup_type: u16, extension: T) -> Self {
1020        Self {
1021            extension_lookup_type,
1022            extension: extension.into(),
1023        }
1024    }
1025}
1026
1027impl<T: Validate> Validate for ExtensionSubstFormat1<T> {
1028    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1029        ctx.in_table("ExtensionSubstFormat1", |ctx| {
1030            ctx.in_field("extension", |ctx| {
1031                self.extension.validate_impl(ctx);
1032            });
1033        })
1034    }
1035}
1036
1037impl<'a, T, U> FromObjRef<read_fonts::tables::gsub::ExtensionSubstFormat1<'a, U>>
1038    for ExtensionSubstFormat1<T>
1039where
1040    U: FontRead<'a, Args = ()>,
1041    T: FromTableRef<U> + Default + 'static,
1042{
1043    fn from_obj_ref(
1044        obj: &read_fonts::tables::gsub::ExtensionSubstFormat1<'a, U>,
1045        _: FontData,
1046    ) -> Self {
1047        ExtensionSubstFormat1 {
1048            extension_lookup_type: obj.extension_lookup_type(),
1049            extension: obj.extension().to_owned_table(),
1050        }
1051    }
1052}
1053
1054#[allow(clippy::needless_lifetimes)]
1055impl<'a, T, U> FromTableRef<read_fonts::tables::gsub::ExtensionSubstFormat1<'a, U>>
1056    for ExtensionSubstFormat1<T>
1057where
1058    U: FontRead<'a, Args = ()>,
1059    T: FromTableRef<U> + Default + 'static,
1060{
1061}
1062
1063/// A [GSUB Extension Substitution](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#ES) subtable
1064#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1065#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1066pub enum ExtensionSubtable {
1067    Single(ExtensionSubstFormat1<SingleSubst>),
1068    Multiple(ExtensionSubstFormat1<MultipleSubst>),
1069    Alternate(ExtensionSubstFormat1<AlternateSubst>),
1070    Ligature(ExtensionSubstFormat1<LigatureSubst>),
1071    Contextual(ExtensionSubstFormat1<SubstitutionSequenceContext>),
1072    ChainContextual(ExtensionSubstFormat1<SubstitutionChainContext>),
1073    Reverse(ExtensionSubstFormat1<ReverseChainSingleSubst>),
1074}
1075
1076impl Default for ExtensionSubtable {
1077    fn default() -> Self {
1078        Self::Single(Default::default())
1079    }
1080}
1081
1082impl FontWrite for ExtensionSubtable {
1083    fn write_into(&self, writer: &mut TableWriter) {
1084        match self {
1085            Self::Single(table) => table.write_into(writer),
1086            Self::Multiple(table) => table.write_into(writer),
1087            Self::Alternate(table) => table.write_into(writer),
1088            Self::Ligature(table) => table.write_into(writer),
1089            Self::Contextual(table) => table.write_into(writer),
1090            Self::ChainContextual(table) => table.write_into(writer),
1091            Self::Reverse(table) => table.write_into(writer),
1092        }
1093    }
1094    fn table_type(&self) -> TableType {
1095        match self {
1096            Self::Single(table) => table.table_type(),
1097            Self::Multiple(table) => table.table_type(),
1098            Self::Alternate(table) => table.table_type(),
1099            Self::Ligature(table) => table.table_type(),
1100            Self::Contextual(table) => table.table_type(),
1101            Self::ChainContextual(table) => table.table_type(),
1102            Self::Reverse(table) => table.table_type(),
1103        }
1104    }
1105}
1106
1107impl Validate for ExtensionSubtable {
1108    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1109        match self {
1110            Self::Single(table) => table.validate_impl(ctx),
1111            Self::Multiple(table) => table.validate_impl(ctx),
1112            Self::Alternate(table) => table.validate_impl(ctx),
1113            Self::Ligature(table) => table.validate_impl(ctx),
1114            Self::Contextual(table) => table.validate_impl(ctx),
1115            Self::ChainContextual(table) => table.validate_impl(ctx),
1116            Self::Reverse(table) => table.validate_impl(ctx),
1117        }
1118    }
1119}
1120
1121impl FromObjRef<read_fonts::tables::gsub::ExtensionSubtable<'_>> for ExtensionSubtable {
1122    fn from_obj_ref(
1123        from: &read_fonts::tables::gsub::ExtensionSubtable<'_>,
1124        data: FontData,
1125    ) -> Self {
1126        match from {
1127            read_fonts::tables::gsub::ExtensionSubtable::Single(table) => {
1128                Self::Single(table.to_owned_obj(data))
1129            }
1130            read_fonts::tables::gsub::ExtensionSubtable::Multiple(table) => {
1131                Self::Multiple(table.to_owned_obj(data))
1132            }
1133            read_fonts::tables::gsub::ExtensionSubtable::Alternate(table) => {
1134                Self::Alternate(table.to_owned_obj(data))
1135            }
1136            read_fonts::tables::gsub::ExtensionSubtable::Ligature(table) => {
1137                Self::Ligature(table.to_owned_obj(data))
1138            }
1139            read_fonts::tables::gsub::ExtensionSubtable::Contextual(table) => {
1140                Self::Contextual(table.to_owned_obj(data))
1141            }
1142            read_fonts::tables::gsub::ExtensionSubtable::ChainContextual(table) => {
1143                Self::ChainContextual(table.to_owned_obj(data))
1144            }
1145            read_fonts::tables::gsub::ExtensionSubtable::Reverse(table) => {
1146                Self::Reverse(table.to_owned_obj(data))
1147            }
1148        }
1149    }
1150}
1151
1152impl FromTableRef<read_fonts::tables::gsub::ExtensionSubtable<'_>> for ExtensionSubtable {}
1153
1154impl From<ExtensionSubstFormat1<SingleSubst>> for ExtensionSubtable {
1155    fn from(src: ExtensionSubstFormat1<SingleSubst>) -> ExtensionSubtable {
1156        ExtensionSubtable::Single(src)
1157    }
1158}
1159
1160impl From<ExtensionSubstFormat1<MultipleSubst>> for ExtensionSubtable {
1161    fn from(src: ExtensionSubstFormat1<MultipleSubst>) -> ExtensionSubtable {
1162        ExtensionSubtable::Multiple(src)
1163    }
1164}
1165
1166impl From<ExtensionSubstFormat1<AlternateSubst>> for ExtensionSubtable {
1167    fn from(src: ExtensionSubstFormat1<AlternateSubst>) -> ExtensionSubtable {
1168        ExtensionSubtable::Alternate(src)
1169    }
1170}
1171
1172impl From<ExtensionSubstFormat1<LigatureSubst>> for ExtensionSubtable {
1173    fn from(src: ExtensionSubstFormat1<LigatureSubst>) -> ExtensionSubtable {
1174        ExtensionSubtable::Ligature(src)
1175    }
1176}
1177
1178impl From<ExtensionSubstFormat1<SubstitutionSequenceContext>> for ExtensionSubtable {
1179    fn from(src: ExtensionSubstFormat1<SubstitutionSequenceContext>) -> ExtensionSubtable {
1180        ExtensionSubtable::Contextual(src)
1181    }
1182}
1183
1184impl From<ExtensionSubstFormat1<SubstitutionChainContext>> for ExtensionSubtable {
1185    fn from(src: ExtensionSubstFormat1<SubstitutionChainContext>) -> ExtensionSubtable {
1186        ExtensionSubtable::ChainContextual(src)
1187    }
1188}
1189
1190impl From<ExtensionSubstFormat1<ReverseChainSingleSubst>> for ExtensionSubtable {
1191    fn from(src: ExtensionSubstFormat1<ReverseChainSingleSubst>) -> ExtensionSubtable {
1192        ExtensionSubtable::Reverse(src)
1193    }
1194}
1195
1196/// [Reverse Chaining Contextual Single Substitution Format 1](https://learn.microsoft.com/en-us/typography/opentype/spec/gsub#81-reverse-chaining-contextual-single-substitution-format-1-coverage-based-glyph-contexts)
1197#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1198#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1199pub struct ReverseChainSingleSubstFormat1 {
1200    /// Offset to Coverage table, from beginning of substitution
1201    /// subtable.
1202    pub coverage: OffsetMarker<CoverageTable>,
1203    /// Array of offsets to coverage tables in backtrack sequence, in
1204    /// glyph sequence order.
1205    pub backtrack_coverages: Vec<OffsetMarker<CoverageTable>>,
1206    /// Array of offsets to coverage tables in lookahead sequence, in
1207    /// glyph sequence order.
1208    pub lookahead_coverages: Vec<OffsetMarker<CoverageTable>>,
1209    /// Array of substitute glyph IDs — ordered by Coverage index.
1210    pub substitute_glyph_ids: Vec<GlyphId16>,
1211}
1212
1213impl ReverseChainSingleSubstFormat1 {
1214    /// Construct a new `ReverseChainSingleSubstFormat1`
1215    pub fn new(
1216        coverage: CoverageTable,
1217        backtrack_coverages: Vec<CoverageTable>,
1218        lookahead_coverages: Vec<CoverageTable>,
1219        substitute_glyph_ids: Vec<GlyphId16>,
1220    ) -> Self {
1221        Self {
1222            coverage: coverage.into(),
1223            backtrack_coverages: backtrack_coverages.into_iter().map(Into::into).collect(),
1224            lookahead_coverages: lookahead_coverages.into_iter().map(Into::into).collect(),
1225            substitute_glyph_ids,
1226        }
1227    }
1228}
1229
1230impl FontWrite for ReverseChainSingleSubstFormat1 {
1231    #[allow(clippy::unnecessary_cast)]
1232    fn write_into(&self, writer: &mut TableWriter) {
1233        (1 as u16).write_into(writer);
1234        self.coverage.write_into(writer);
1235        (u16::try_from(array_len(&self.backtrack_coverages)).unwrap()).write_into(writer);
1236        self.backtrack_coverages.write_into(writer);
1237        (u16::try_from(array_len(&self.lookahead_coverages)).unwrap()).write_into(writer);
1238        self.lookahead_coverages.write_into(writer);
1239        (u16::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
1240        self.substitute_glyph_ids.write_into(writer);
1241    }
1242    fn table_type(&self) -> TableType {
1243        TableType::Named("ReverseChainSingleSubstFormat1")
1244    }
1245}
1246
1247impl Validate for ReverseChainSingleSubstFormat1 {
1248    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1249        ctx.in_table("ReverseChainSingleSubstFormat1", |ctx| {
1250            ctx.in_field("coverage", |ctx| {
1251                self.coverage.validate_impl(ctx);
1252            });
1253            ctx.in_field("backtrack_coverages", |ctx| {
1254                if self.backtrack_coverages.len() > to_usize(u16::MAX) {
1255                    ctx.report("array exceeds max length");
1256                }
1257                self.backtrack_coverages.validate_impl(ctx);
1258            });
1259            ctx.in_field("lookahead_coverages", |ctx| {
1260                if self.lookahead_coverages.len() > to_usize(u16::MAX) {
1261                    ctx.report("array exceeds max length");
1262                }
1263                self.lookahead_coverages.validate_impl(ctx);
1264            });
1265            ctx.in_field("substitute_glyph_ids", |ctx| {
1266                if self.substitute_glyph_ids.len() > to_usize(u16::MAX) {
1267                    ctx.report("array exceeds max length");
1268                }
1269            });
1270        })
1271    }
1272}
1273
1274impl<'a> FromObjRef<read_fonts::tables::gsub::ReverseChainSingleSubstFormat1<'a>>
1275    for ReverseChainSingleSubstFormat1
1276{
1277    fn from_obj_ref(
1278        obj: &read_fonts::tables::gsub::ReverseChainSingleSubstFormat1<'a>,
1279        _: FontData,
1280    ) -> Self {
1281        let offset_data = obj.offset_data();
1282        ReverseChainSingleSubstFormat1 {
1283            coverage: obj.coverage().to_owned_table(),
1284            backtrack_coverages: obj.backtrack_coverages().to_owned_table(),
1285            lookahead_coverages: obj.lookahead_coverages().to_owned_table(),
1286            substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
1287        }
1288    }
1289}
1290
1291#[allow(clippy::needless_lifetimes)]
1292impl<'a> FromTableRef<read_fonts::tables::gsub::ReverseChainSingleSubstFormat1<'a>>
1293    for ReverseChainSingleSubstFormat1
1294{
1295}
1296
1297impl ReadArgs for ReverseChainSingleSubstFormat1 {
1298    type Args = ();
1299}
1300
1301impl<'a> FontRead<'a> for ReverseChainSingleSubstFormat1 {
1302    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1303        <read_fonts::tables::gsub::ReverseChainSingleSubstFormat1 as FontRead>::read(data)
1304            .map(|x| x.to_owned_table())
1305    }
1306}
1307
1308/// SingleSubstFormat3 (ISO/IEC 14496-22:2026).
1309#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1310#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1311pub struct SingleSubstFormat3 {
1312    /// Offset to Coverage table, from beginning of substitution
1313    /// subtable
1314    pub coverage: OffsetMarker<CoverageTable, WIDTH_32>,
1315    /// Add to original glyph ID to get substitute glyph ID
1316    pub delta_glyph_id: Int24,
1317}
1318
1319impl SingleSubstFormat3 {
1320    /// Construct a new `SingleSubstFormat3`
1321    pub fn new(coverage: CoverageTable, delta_glyph_id: Int24) -> Self {
1322        Self {
1323            coverage: coverage.into(),
1324            delta_glyph_id,
1325        }
1326    }
1327}
1328
1329impl FontWrite for SingleSubstFormat3 {
1330    #[allow(clippy::unnecessary_cast)]
1331    fn write_into(&self, writer: &mut TableWriter) {
1332        (3 as u16).write_into(writer);
1333        self.coverage.write_into(writer);
1334        self.delta_glyph_id.write_into(writer);
1335    }
1336    fn table_type(&self) -> TableType {
1337        TableType::Named("SingleSubstFormat3")
1338    }
1339}
1340
1341impl Validate for SingleSubstFormat3 {
1342    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1343        ctx.in_table("SingleSubstFormat3", |ctx| {
1344            ctx.in_field("coverage", |ctx| {
1345                self.coverage.validate_impl(ctx);
1346            });
1347        })
1348    }
1349}
1350
1351impl<'a> FromObjRef<read_fonts::tables::gsub::SingleSubstFormat3<'a>> for SingleSubstFormat3 {
1352    fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubstFormat3<'a>, _: FontData) -> Self {
1353        SingleSubstFormat3 {
1354            coverage: obj.coverage().to_owned_table(),
1355            delta_glyph_id: obj.delta_glyph_id(),
1356        }
1357    }
1358}
1359
1360#[allow(clippy::needless_lifetimes)]
1361impl<'a> FromTableRef<read_fonts::tables::gsub::SingleSubstFormat3<'a>> for SingleSubstFormat3 {}
1362
1363impl ReadArgs for SingleSubstFormat3 {
1364    type Args = ();
1365}
1366
1367impl<'a> FontRead<'a> for SingleSubstFormat3 {
1368    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1369        <read_fonts::tables::gsub::SingleSubstFormat3 as FontRead>::read(data)
1370            .map(|x| x.to_owned_table())
1371    }
1372}
1373
1374/// SingleSubstFormat4 (ISO/IEC 14496-22:2026).
1375#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1376#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1377pub struct SingleSubstFormat4 {
1378    /// Offset to Coverage table, from beginning of substitution
1379    /// subtable
1380    pub coverage: OffsetMarker<CoverageTable, WIDTH_32>,
1381    /// Array of substitute glyph IDs — ordered by Coverage index
1382    pub substitute_glyph_ids: Vec<GlyphId24>,
1383}
1384
1385impl SingleSubstFormat4 {
1386    /// Construct a new `SingleSubstFormat4`
1387    pub fn new(coverage: CoverageTable, substitute_glyph_ids: Vec<GlyphId24>) -> Self {
1388        Self {
1389            coverage: coverage.into(),
1390            substitute_glyph_ids,
1391        }
1392    }
1393}
1394
1395impl FontWrite for SingleSubstFormat4 {
1396    #[allow(clippy::unnecessary_cast)]
1397    fn write_into(&self, writer: &mut TableWriter) {
1398        (4 as u16).write_into(writer);
1399        self.coverage.write_into(writer);
1400        (Uint24::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
1401        self.substitute_glyph_ids.write_into(writer);
1402    }
1403    fn table_type(&self) -> TableType {
1404        TableType::Named("SingleSubstFormat4")
1405    }
1406}
1407
1408impl Validate for SingleSubstFormat4 {
1409    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1410        ctx.in_table("SingleSubstFormat4", |ctx| {
1411            ctx.in_field("coverage", |ctx| {
1412                self.coverage.validate_impl(ctx);
1413            });
1414            ctx.in_field("substitute_glyph_ids", |ctx| {
1415                if self.substitute_glyph_ids.len() > to_usize(Uint24::MAX) {
1416                    ctx.report("array exceeds max length");
1417                }
1418            });
1419        })
1420    }
1421}
1422
1423impl<'a> FromObjRef<read_fonts::tables::gsub::SingleSubstFormat4<'a>> for SingleSubstFormat4 {
1424    fn from_obj_ref(obj: &read_fonts::tables::gsub::SingleSubstFormat4<'a>, _: FontData) -> Self {
1425        let offset_data = obj.offset_data();
1426        SingleSubstFormat4 {
1427            coverage: obj.coverage().to_owned_table(),
1428            substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
1429        }
1430    }
1431}
1432
1433#[allow(clippy::needless_lifetimes)]
1434impl<'a> FromTableRef<read_fonts::tables::gsub::SingleSubstFormat4<'a>> for SingleSubstFormat4 {}
1435
1436impl ReadArgs for SingleSubstFormat4 {
1437    type Args = ();
1438}
1439
1440impl<'a> FontRead<'a> for SingleSubstFormat4 {
1441    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1442        <read_fonts::tables::gsub::SingleSubstFormat4 as FontRead>::read(data)
1443            .map(|x| x.to_owned_table())
1444    }
1445}
1446
1447/// MultipleSubstFormat2 (ISO/IEC 14496-22:2026).
1448#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1449#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1450pub struct MultipleSubstFormat2 {
1451    /// Offset to Coverage table, from beginning of substitution
1452    /// subtable
1453    pub coverage: OffsetMarker<CoverageTable, WIDTH_32>,
1454    /// Array of offsets to Sequence tables. Offsets are from beginning
1455    /// of substitution subtable, ordered by Coverage index
1456    pub sequences: Vec<OffsetMarker<Sequence2, WIDTH_24>>,
1457}
1458
1459impl MultipleSubstFormat2 {
1460    /// Construct a new `MultipleSubstFormat2`
1461    pub fn new(coverage: CoverageTable, sequences: Vec<Sequence2>) -> Self {
1462        Self {
1463            coverage: coverage.into(),
1464            sequences: sequences.into_iter().map(Into::into).collect(),
1465        }
1466    }
1467}
1468
1469impl FontWrite for MultipleSubstFormat2 {
1470    #[allow(clippy::unnecessary_cast)]
1471    fn write_into(&self, writer: &mut TableWriter) {
1472        (2 as u16).write_into(writer);
1473        self.coverage.write_into(writer);
1474        (Uint24::try_from(array_len(&self.sequences)).unwrap()).write_into(writer);
1475        self.sequences.write_into(writer);
1476    }
1477    fn table_type(&self) -> TableType {
1478        TableType::Named("MultipleSubstFormat2")
1479    }
1480}
1481
1482impl Validate for MultipleSubstFormat2 {
1483    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1484        ctx.in_table("MultipleSubstFormat2", |ctx| {
1485            ctx.in_field("coverage", |ctx| {
1486                self.coverage.validate_impl(ctx);
1487            });
1488            ctx.in_field("sequences", |ctx| {
1489                if self.sequences.len() > to_usize(Uint24::MAX) {
1490                    ctx.report("array exceeds max length");
1491                }
1492                self.sequences.validate_impl(ctx);
1493            });
1494        })
1495    }
1496}
1497
1498impl<'a> FromObjRef<read_fonts::tables::gsub::MultipleSubstFormat2<'a>> for MultipleSubstFormat2 {
1499    fn from_obj_ref(obj: &read_fonts::tables::gsub::MultipleSubstFormat2<'a>, _: FontData) -> Self {
1500        MultipleSubstFormat2 {
1501            coverage: obj.coverage().to_owned_table(),
1502            sequences: obj.sequences().to_owned_table(),
1503        }
1504    }
1505}
1506
1507#[allow(clippy::needless_lifetimes)]
1508impl<'a> FromTableRef<read_fonts::tables::gsub::MultipleSubstFormat2<'a>> for MultipleSubstFormat2 {}
1509
1510impl ReadArgs for MultipleSubstFormat2 {
1511    type Args = ();
1512}
1513
1514impl<'a> FontRead<'a> for MultipleSubstFormat2 {
1515    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1516        <read_fonts::tables::gsub::MultipleSubstFormat2 as FontRead>::read(data)
1517            .map(|x| x.to_owned_table())
1518    }
1519}
1520
1521/// AlternateSubstFormat2 (ISO/IEC 14496-22:2026).
1522#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1523#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1524pub struct AlternateSubstFormat2 {
1525    /// Offset to Coverage table, from beginning of substitution
1526    /// subtable
1527    pub coverage: OffsetMarker<CoverageTable, WIDTH_32>,
1528    /// Array of offsets to AlternateSet tables. Offsets are from
1529    /// beginning of substitution subtable, ordered by Coverage index
1530    pub alternate_sets: Vec<OffsetMarker<AlternateSet2, WIDTH_24>>,
1531}
1532
1533impl AlternateSubstFormat2 {
1534    /// Construct a new `AlternateSubstFormat2`
1535    pub fn new(coverage: CoverageTable, alternate_sets: Vec<AlternateSet2>) -> Self {
1536        Self {
1537            coverage: coverage.into(),
1538            alternate_sets: alternate_sets.into_iter().map(Into::into).collect(),
1539        }
1540    }
1541}
1542
1543impl FontWrite for AlternateSubstFormat2 {
1544    #[allow(clippy::unnecessary_cast)]
1545    fn write_into(&self, writer: &mut TableWriter) {
1546        (2 as u16).write_into(writer);
1547        self.coverage.write_into(writer);
1548        (Uint24::try_from(array_len(&self.alternate_sets)).unwrap()).write_into(writer);
1549        self.alternate_sets.write_into(writer);
1550    }
1551    fn table_type(&self) -> TableType {
1552        TableType::Named("AlternateSubstFormat2")
1553    }
1554}
1555
1556impl Validate for AlternateSubstFormat2 {
1557    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1558        ctx.in_table("AlternateSubstFormat2", |ctx| {
1559            ctx.in_field("coverage", |ctx| {
1560                self.coverage.validate_impl(ctx);
1561            });
1562            ctx.in_field("alternate_sets", |ctx| {
1563                if self.alternate_sets.len() > to_usize(Uint24::MAX) {
1564                    ctx.report("array exceeds max length");
1565                }
1566                self.alternate_sets.validate_impl(ctx);
1567            });
1568        })
1569    }
1570}
1571
1572impl<'a> FromObjRef<read_fonts::tables::gsub::AlternateSubstFormat2<'a>> for AlternateSubstFormat2 {
1573    fn from_obj_ref(
1574        obj: &read_fonts::tables::gsub::AlternateSubstFormat2<'a>,
1575        _: FontData,
1576    ) -> Self {
1577        AlternateSubstFormat2 {
1578            coverage: obj.coverage().to_owned_table(),
1579            alternate_sets: obj.alternate_sets().to_owned_table(),
1580        }
1581    }
1582}
1583
1584#[allow(clippy::needless_lifetimes)]
1585impl<'a> FromTableRef<read_fonts::tables::gsub::AlternateSubstFormat2<'a>>
1586    for AlternateSubstFormat2
1587{
1588}
1589
1590impl ReadArgs for AlternateSubstFormat2 {
1591    type Args = ();
1592}
1593
1594impl<'a> FontRead<'a> for AlternateSubstFormat2 {
1595    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1596        <read_fonts::tables::gsub::AlternateSubstFormat2 as FontRead>::read(data)
1597            .map(|x| x.to_owned_table())
1598    }
1599}
1600
1601/// LigatureSubstFormat2 (ISO/IEC 14496-22:2026).
1602#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1603#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1604pub struct LigatureSubstFormat2 {
1605    /// Offset to Coverage table, from beginning of substitution
1606    /// subtable
1607    pub coverage: OffsetMarker<CoverageTable, WIDTH_32>,
1608    /// Array of offsets to LigatureSet tables. Offsets are from
1609    /// beginning of substitution subtable, ordered by Coverage index
1610    pub ligature_sets: Vec<OffsetMarker<LigatureSet2, WIDTH_24>>,
1611}
1612
1613impl LigatureSubstFormat2 {
1614    /// Construct a new `LigatureSubstFormat2`
1615    pub fn new(coverage: CoverageTable, ligature_sets: Vec<LigatureSet2>) -> Self {
1616        Self {
1617            coverage: coverage.into(),
1618            ligature_sets: ligature_sets.into_iter().map(Into::into).collect(),
1619        }
1620    }
1621}
1622
1623impl FontWrite for LigatureSubstFormat2 {
1624    #[allow(clippy::unnecessary_cast)]
1625    fn write_into(&self, writer: &mut TableWriter) {
1626        (2 as u16).write_into(writer);
1627        self.coverage.write_into(writer);
1628        (Uint24::try_from(array_len(&self.ligature_sets)).unwrap()).write_into(writer);
1629        self.ligature_sets.write_into(writer);
1630    }
1631    fn table_type(&self) -> TableType {
1632        TableType::Named("LigatureSubstFormat2")
1633    }
1634}
1635
1636impl Validate for LigatureSubstFormat2 {
1637    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1638        ctx.in_table("LigatureSubstFormat2", |ctx| {
1639            ctx.in_field("coverage", |ctx| {
1640                self.coverage.validate_impl(ctx);
1641            });
1642            ctx.in_field("ligature_sets", |ctx| {
1643                if self.ligature_sets.len() > to_usize(Uint24::MAX) {
1644                    ctx.report("array exceeds max length");
1645                }
1646                self.ligature_sets.validate_impl(ctx);
1647            });
1648        })
1649    }
1650}
1651
1652impl<'a> FromObjRef<read_fonts::tables::gsub::LigatureSubstFormat2<'a>> for LigatureSubstFormat2 {
1653    fn from_obj_ref(obj: &read_fonts::tables::gsub::LigatureSubstFormat2<'a>, _: FontData) -> Self {
1654        LigatureSubstFormat2 {
1655            coverage: obj.coverage().to_owned_table(),
1656            ligature_sets: obj.ligature_sets().to_owned_table(),
1657        }
1658    }
1659}
1660
1661#[allow(clippy::needless_lifetimes)]
1662impl<'a> FromTableRef<read_fonts::tables::gsub::LigatureSubstFormat2<'a>> for LigatureSubstFormat2 {}
1663
1664impl ReadArgs for LigatureSubstFormat2 {
1665    type Args = ();
1666}
1667
1668impl<'a> FontRead<'a> for LigatureSubstFormat2 {
1669    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1670        <read_fonts::tables::gsub::LigatureSubstFormat2 as FontRead>::read(data)
1671            .map(|x| x.to_owned_table())
1672    }
1673}
1674
1675/// ReverseChainSingleSubstFormat2 (ISO/IEC 14496-22:2026).
1676#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1677#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1678pub struct ReverseChainSingleSubstFormat2 {
1679    /// Offset to Coverage table, from beginning of substitution
1680    /// subtable.
1681    pub coverage: OffsetMarker<CoverageTable, WIDTH_32>,
1682    /// Array of offsets to coverage tables in backtrack sequence, in
1683    /// glyph sequence order.
1684    pub backtrack_coverages: Vec<OffsetMarker<CoverageTable, WIDTH_24>>,
1685    /// Array of offsets to coverage tables in lookahead sequence, in
1686    /// glyph sequence order.
1687    pub lookahead_coverages: Vec<OffsetMarker<CoverageTable, WIDTH_24>>,
1688    /// Array of substitute glyph IDs — ordered by Coverage index.
1689    pub substitute_glyph_ids: Vec<GlyphId24>,
1690}
1691
1692impl ReverseChainSingleSubstFormat2 {
1693    /// Construct a new `ReverseChainSingleSubstFormat2`
1694    pub fn new(
1695        coverage: CoverageTable,
1696        backtrack_coverages: Vec<CoverageTable>,
1697        lookahead_coverages: Vec<CoverageTable>,
1698        substitute_glyph_ids: Vec<GlyphId24>,
1699    ) -> Self {
1700        Self {
1701            coverage: coverage.into(),
1702            backtrack_coverages: backtrack_coverages.into_iter().map(Into::into).collect(),
1703            lookahead_coverages: lookahead_coverages.into_iter().map(Into::into).collect(),
1704            substitute_glyph_ids,
1705        }
1706    }
1707}
1708
1709impl FontWrite for ReverseChainSingleSubstFormat2 {
1710    #[allow(clippy::unnecessary_cast)]
1711    fn write_into(&self, writer: &mut TableWriter) {
1712        (2 as u16).write_into(writer);
1713        self.coverage.write_into(writer);
1714        (u16::try_from(array_len(&self.backtrack_coverages)).unwrap()).write_into(writer);
1715        self.backtrack_coverages.write_into(writer);
1716        (u16::try_from(array_len(&self.lookahead_coverages)).unwrap()).write_into(writer);
1717        self.lookahead_coverages.write_into(writer);
1718        (Uint24::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
1719        self.substitute_glyph_ids.write_into(writer);
1720    }
1721    fn table_type(&self) -> TableType {
1722        TableType::Named("ReverseChainSingleSubstFormat2")
1723    }
1724}
1725
1726impl Validate for ReverseChainSingleSubstFormat2 {
1727    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1728        ctx.in_table("ReverseChainSingleSubstFormat2", |ctx| {
1729            ctx.in_field("coverage", |ctx| {
1730                self.coverage.validate_impl(ctx);
1731            });
1732            ctx.in_field("backtrack_coverages", |ctx| {
1733                if self.backtrack_coverages.len() > to_usize(u16::MAX) {
1734                    ctx.report("array exceeds max length");
1735                }
1736                self.backtrack_coverages.validate_impl(ctx);
1737            });
1738            ctx.in_field("lookahead_coverages", |ctx| {
1739                if self.lookahead_coverages.len() > to_usize(u16::MAX) {
1740                    ctx.report("array exceeds max length");
1741                }
1742                self.lookahead_coverages.validate_impl(ctx);
1743            });
1744            ctx.in_field("substitute_glyph_ids", |ctx| {
1745                if self.substitute_glyph_ids.len() > to_usize(Uint24::MAX) {
1746                    ctx.report("array exceeds max length");
1747                }
1748            });
1749        })
1750    }
1751}
1752
1753impl<'a> FromObjRef<read_fonts::tables::gsub::ReverseChainSingleSubstFormat2<'a>>
1754    for ReverseChainSingleSubstFormat2
1755{
1756    fn from_obj_ref(
1757        obj: &read_fonts::tables::gsub::ReverseChainSingleSubstFormat2<'a>,
1758        _: FontData,
1759    ) -> Self {
1760        let offset_data = obj.offset_data();
1761        ReverseChainSingleSubstFormat2 {
1762            coverage: obj.coverage().to_owned_table(),
1763            backtrack_coverages: obj.backtrack_coverages().to_owned_table(),
1764            lookahead_coverages: obj.lookahead_coverages().to_owned_table(),
1765            substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
1766        }
1767    }
1768}
1769
1770#[allow(clippy::needless_lifetimes)]
1771impl<'a> FromTableRef<read_fonts::tables::gsub::ReverseChainSingleSubstFormat2<'a>>
1772    for ReverseChainSingleSubstFormat2
1773{
1774}
1775
1776impl ReadArgs for ReverseChainSingleSubstFormat2 {
1777    type Args = ();
1778}
1779
1780impl<'a> FontRead<'a> for ReverseChainSingleSubstFormat2 {
1781    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1782        <read_fonts::tables::gsub::ReverseChainSingleSubstFormat2 as FontRead>::read(data)
1783            .map(|x| x.to_owned_table())
1784    }
1785}
1786
1787/// Sequence2 (ISO/IEC 14496-22:2026).
1788#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1789#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1790pub struct Sequence2 {
1791    /// String of glyph IDs to substitute
1792    pub substitute_glyph_ids: Vec<GlyphId24>,
1793}
1794
1795impl Sequence2 {
1796    /// Construct a new `Sequence2`
1797    pub fn new(substitute_glyph_ids: Vec<GlyphId24>) -> Self {
1798        Self {
1799            substitute_glyph_ids,
1800        }
1801    }
1802}
1803
1804impl FontWrite for Sequence2 {
1805    #[allow(clippy::unnecessary_cast)]
1806    fn write_into(&self, writer: &mut TableWriter) {
1807        (u16::try_from(array_len(&self.substitute_glyph_ids)).unwrap()).write_into(writer);
1808        self.substitute_glyph_ids.write_into(writer);
1809    }
1810    fn table_type(&self) -> TableType {
1811        TableType::Named("Sequence2")
1812    }
1813}
1814
1815impl Validate for Sequence2 {
1816    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1817        ctx.in_table("Sequence2", |ctx| {
1818            ctx.in_field("substitute_glyph_ids", |ctx| {
1819                if self.substitute_glyph_ids.len() > to_usize(u16::MAX) {
1820                    ctx.report("array exceeds max length");
1821                }
1822            });
1823        })
1824    }
1825}
1826
1827impl<'a> FromObjRef<read_fonts::tables::gsub::Sequence2<'a>> for Sequence2 {
1828    fn from_obj_ref(obj: &read_fonts::tables::gsub::Sequence2<'a>, _: FontData) -> Self {
1829        let offset_data = obj.offset_data();
1830        Sequence2 {
1831            substitute_glyph_ids: obj.substitute_glyph_ids().to_owned_obj(offset_data),
1832        }
1833    }
1834}
1835
1836#[allow(clippy::needless_lifetimes)]
1837impl<'a> FromTableRef<read_fonts::tables::gsub::Sequence2<'a>> for Sequence2 {}
1838
1839impl ReadArgs for Sequence2 {
1840    type Args = ();
1841}
1842
1843impl<'a> FontRead<'a> for Sequence2 {
1844    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1845        <read_fonts::tables::gsub::Sequence2 as FontRead>::read(data).map(|x| x.to_owned_table())
1846    }
1847}
1848
1849/// AlternateSet2 (ISO/IEC 14496-22:2026).
1850#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1851#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1852pub struct AlternateSet2 {
1853    /// Array of alternate glyph IDs, in arbitrary order
1854    pub alternate_glyph_ids: Vec<GlyphId24>,
1855}
1856
1857impl AlternateSet2 {
1858    /// Construct a new `AlternateSet2`
1859    pub fn new(alternate_glyph_ids: Vec<GlyphId24>) -> Self {
1860        Self {
1861            alternate_glyph_ids,
1862        }
1863    }
1864}
1865
1866impl FontWrite for AlternateSet2 {
1867    #[allow(clippy::unnecessary_cast)]
1868    fn write_into(&self, writer: &mut TableWriter) {
1869        (u16::try_from(array_len(&self.alternate_glyph_ids)).unwrap()).write_into(writer);
1870        self.alternate_glyph_ids.write_into(writer);
1871    }
1872    fn table_type(&self) -> TableType {
1873        TableType::Named("AlternateSet2")
1874    }
1875}
1876
1877impl Validate for AlternateSet2 {
1878    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1879        ctx.in_table("AlternateSet2", |ctx| {
1880            ctx.in_field("alternate_glyph_ids", |ctx| {
1881                if self.alternate_glyph_ids.len() > to_usize(u16::MAX) {
1882                    ctx.report("array exceeds max length");
1883                }
1884            });
1885        })
1886    }
1887}
1888
1889impl<'a> FromObjRef<read_fonts::tables::gsub::AlternateSet2<'a>> for AlternateSet2 {
1890    fn from_obj_ref(obj: &read_fonts::tables::gsub::AlternateSet2<'a>, _: FontData) -> Self {
1891        let offset_data = obj.offset_data();
1892        AlternateSet2 {
1893            alternate_glyph_ids: obj.alternate_glyph_ids().to_owned_obj(offset_data),
1894        }
1895    }
1896}
1897
1898#[allow(clippy::needless_lifetimes)]
1899impl<'a> FromTableRef<read_fonts::tables::gsub::AlternateSet2<'a>> for AlternateSet2 {}
1900
1901impl ReadArgs for AlternateSet2 {
1902    type Args = ();
1903}
1904
1905impl<'a> FontRead<'a> for AlternateSet2 {
1906    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1907        <read_fonts::tables::gsub::AlternateSet2 as FontRead>::read(data)
1908            .map(|x| x.to_owned_table())
1909    }
1910}
1911
1912/// LigatureSet2 (ISO/IEC 14496-22:2026).
1913#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1914#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1915pub struct LigatureSet2 {
1916    /// Array of offsets to Ligature tables. Offsets are from beginning
1917    /// of LigatureSet2 table, ordered by preference.
1918    pub ligatures: Vec<OffsetMarker<Ligature2, WIDTH_24>>,
1919}
1920
1921impl LigatureSet2 {
1922    /// Construct a new `LigatureSet2`
1923    pub fn new(ligatures: Vec<Ligature2>) -> Self {
1924        Self {
1925            ligatures: ligatures.into_iter().map(Into::into).collect(),
1926        }
1927    }
1928}
1929
1930impl FontWrite for LigatureSet2 {
1931    #[allow(clippy::unnecessary_cast)]
1932    fn write_into(&self, writer: &mut TableWriter) {
1933        (u16::try_from(array_len(&self.ligatures)).unwrap()).write_into(writer);
1934        self.ligatures.write_into(writer);
1935    }
1936    fn table_type(&self) -> TableType {
1937        TableType::Named("LigatureSet2")
1938    }
1939}
1940
1941impl Validate for LigatureSet2 {
1942    fn validate_impl(&self, ctx: &mut ValidationCtx) {
1943        ctx.in_table("LigatureSet2", |ctx| {
1944            ctx.in_field("ligatures", |ctx| {
1945                if self.ligatures.len() > to_usize(u16::MAX) {
1946                    ctx.report("array exceeds max length");
1947                }
1948                self.ligatures.validate_impl(ctx);
1949            });
1950        })
1951    }
1952}
1953
1954impl<'a> FromObjRef<read_fonts::tables::gsub::LigatureSet2<'a>> for LigatureSet2 {
1955    fn from_obj_ref(obj: &read_fonts::tables::gsub::LigatureSet2<'a>, _: FontData) -> Self {
1956        LigatureSet2 {
1957            ligatures: obj.ligatures().to_owned_table(),
1958        }
1959    }
1960}
1961
1962#[allow(clippy::needless_lifetimes)]
1963impl<'a> FromTableRef<read_fonts::tables::gsub::LigatureSet2<'a>> for LigatureSet2 {}
1964
1965impl ReadArgs for LigatureSet2 {
1966    type Args = ();
1967}
1968
1969impl<'a> FontRead<'a> for LigatureSet2 {
1970    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1971        <read_fonts::tables::gsub::LigatureSet2 as FontRead>::read(data).map(|x| x.to_owned_table())
1972    }
1973}
1974
1975/// Ligature2 (ISO/IEC 14496-22:2026).
1976#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
1977#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1978pub struct Ligature2 {
1979    /// glyph ID of ligature to substitute
1980    pub ligature_glyph: GlyphId24,
1981    /// Array of component glyph IDs — start with the second
1982    /// component, ordered in writing direction
1983    pub component_glyph_ids: Vec<GlyphId24>,
1984}
1985
1986impl Ligature2 {
1987    /// Construct a new `Ligature2`
1988    pub fn new(ligature_glyph: GlyphId24, component_glyph_ids: Vec<GlyphId24>) -> Self {
1989        Self {
1990            ligature_glyph,
1991            component_glyph_ids,
1992        }
1993    }
1994}
1995
1996impl FontWrite for Ligature2 {
1997    #[allow(clippy::unnecessary_cast)]
1998    fn write_into(&self, writer: &mut TableWriter) {
1999        self.ligature_glyph.write_into(writer);
2000        (u16::try_from(plus_one(&self.component_glyph_ids.len())).unwrap()).write_into(writer);
2001        self.component_glyph_ids.write_into(writer);
2002    }
2003    fn table_type(&self) -> TableType {
2004        TableType::Named("Ligature2")
2005    }
2006}
2007
2008impl Validate for Ligature2 {
2009    fn validate_impl(&self, _ctx: &mut ValidationCtx) {}
2010}
2011
2012impl<'a> FromObjRef<read_fonts::tables::gsub::Ligature2<'a>> for Ligature2 {
2013    fn from_obj_ref(obj: &read_fonts::tables::gsub::Ligature2<'a>, _: FontData) -> Self {
2014        let offset_data = obj.offset_data();
2015        Ligature2 {
2016            ligature_glyph: obj.ligature_glyph(),
2017            component_glyph_ids: obj.component_glyph_ids().to_owned_obj(offset_data),
2018        }
2019    }
2020}
2021
2022#[allow(clippy::needless_lifetimes)]
2023impl<'a> FromTableRef<read_fonts::tables::gsub::Ligature2<'a>> for Ligature2 {}
2024
2025impl ReadArgs for Ligature2 {
2026    type Args = ();
2027}
2028
2029impl<'a> FontRead<'a> for Ligature2 {
2030    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2031        <read_fonts::tables::gsub::Ligature2 as FontRead>::read(data).map(|x| x.to_owned_table())
2032    }
2033}
2034
2035/// MultipleSubst (ISO/IEC 14496-22:2026).
2036#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2037#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2038pub enum MultipleSubst {
2039    Format1(MultipleSubstFormat1),
2040    Format2(MultipleSubstFormat2),
2041}
2042
2043impl MultipleSubst {
2044    /// Construct a new `MultipleSubstFormat1` subtable
2045    pub fn format_1(coverage: CoverageTable, sequences: Vec<Sequence>) -> Self {
2046        Self::Format1(MultipleSubstFormat1::new(coverage, sequences))
2047    }
2048
2049    /// Construct a new `MultipleSubstFormat2` subtable
2050    pub fn format_2(coverage: CoverageTable, sequences: Vec<Sequence2>) -> Self {
2051        Self::Format2(MultipleSubstFormat2::new(coverage, sequences))
2052    }
2053}
2054
2055impl Default for MultipleSubst {
2056    fn default() -> Self {
2057        Self::Format1(Default::default())
2058    }
2059}
2060
2061impl FontWrite for MultipleSubst {
2062    fn write_into(&self, writer: &mut TableWriter) {
2063        match self {
2064            Self::Format1(item) => item.write_into(writer),
2065            Self::Format2(item) => item.write_into(writer),
2066        }
2067    }
2068    fn table_type(&self) -> TableType {
2069        match self {
2070            Self::Format1(item) => item.table_type(),
2071            Self::Format2(item) => item.table_type(),
2072        }
2073    }
2074}
2075
2076impl Validate for MultipleSubst {
2077    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2078        match self {
2079            Self::Format1(item) => item.validate_impl(ctx),
2080            Self::Format2(item) => item.validate_impl(ctx),
2081        }
2082    }
2083}
2084
2085impl FromObjRef<read_fonts::tables::gsub::MultipleSubst<'_>> for MultipleSubst {
2086    fn from_obj_ref(obj: &read_fonts::tables::gsub::MultipleSubst, _: FontData) -> Self {
2087        use read_fonts::tables::gsub::MultipleSubst as ObjRefType;
2088        match obj {
2089            ObjRefType::Format1(item) => MultipleSubst::Format1(item.to_owned_table()),
2090            ObjRefType::Format2(item) => MultipleSubst::Format2(item.to_owned_table()),
2091        }
2092    }
2093}
2094
2095impl FromTableRef<read_fonts::tables::gsub::MultipleSubst<'_>> for MultipleSubst {}
2096
2097impl ReadArgs for MultipleSubst {
2098    type Args = ();
2099}
2100
2101impl<'a> FontRead<'a> for MultipleSubst {
2102    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2103        <read_fonts::tables::gsub::MultipleSubst as FontRead>::read(data)
2104            .map(|x| x.to_owned_table())
2105    }
2106}
2107
2108impl From<MultipleSubstFormat1> for MultipleSubst {
2109    fn from(src: MultipleSubstFormat1) -> MultipleSubst {
2110        MultipleSubst::Format1(src)
2111    }
2112}
2113
2114impl From<MultipleSubstFormat2> for MultipleSubst {
2115    fn from(src: MultipleSubstFormat2) -> MultipleSubst {
2116        MultipleSubst::Format2(src)
2117    }
2118}
2119
2120/// AlternateSubst (ISO/IEC 14496-22:2026).
2121#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2123pub enum AlternateSubst {
2124    Format1(AlternateSubstFormat1),
2125    Format2(AlternateSubstFormat2),
2126}
2127
2128impl AlternateSubst {
2129    /// Construct a new `AlternateSubstFormat1` subtable
2130    pub fn format_1(coverage: CoverageTable, alternate_sets: Vec<AlternateSet>) -> Self {
2131        Self::Format1(AlternateSubstFormat1::new(coverage, alternate_sets))
2132    }
2133
2134    /// Construct a new `AlternateSubstFormat2` subtable
2135    pub fn format_2(coverage: CoverageTable, alternate_sets: Vec<AlternateSet2>) -> Self {
2136        Self::Format2(AlternateSubstFormat2::new(coverage, alternate_sets))
2137    }
2138}
2139
2140impl Default for AlternateSubst {
2141    fn default() -> Self {
2142        Self::Format1(Default::default())
2143    }
2144}
2145
2146impl FontWrite for AlternateSubst {
2147    fn write_into(&self, writer: &mut TableWriter) {
2148        match self {
2149            Self::Format1(item) => item.write_into(writer),
2150            Self::Format2(item) => item.write_into(writer),
2151        }
2152    }
2153    fn table_type(&self) -> TableType {
2154        match self {
2155            Self::Format1(item) => item.table_type(),
2156            Self::Format2(item) => item.table_type(),
2157        }
2158    }
2159}
2160
2161impl Validate for AlternateSubst {
2162    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2163        match self {
2164            Self::Format1(item) => item.validate_impl(ctx),
2165            Self::Format2(item) => item.validate_impl(ctx),
2166        }
2167    }
2168}
2169
2170impl FromObjRef<read_fonts::tables::gsub::AlternateSubst<'_>> for AlternateSubst {
2171    fn from_obj_ref(obj: &read_fonts::tables::gsub::AlternateSubst, _: FontData) -> Self {
2172        use read_fonts::tables::gsub::AlternateSubst as ObjRefType;
2173        match obj {
2174            ObjRefType::Format1(item) => AlternateSubst::Format1(item.to_owned_table()),
2175            ObjRefType::Format2(item) => AlternateSubst::Format2(item.to_owned_table()),
2176        }
2177    }
2178}
2179
2180impl FromTableRef<read_fonts::tables::gsub::AlternateSubst<'_>> for AlternateSubst {}
2181
2182impl ReadArgs for AlternateSubst {
2183    type Args = ();
2184}
2185
2186impl<'a> FontRead<'a> for AlternateSubst {
2187    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2188        <read_fonts::tables::gsub::AlternateSubst as FontRead>::read(data)
2189            .map(|x| x.to_owned_table())
2190    }
2191}
2192
2193impl From<AlternateSubstFormat1> for AlternateSubst {
2194    fn from(src: AlternateSubstFormat1) -> AlternateSubst {
2195        AlternateSubst::Format1(src)
2196    }
2197}
2198
2199impl From<AlternateSubstFormat2> for AlternateSubst {
2200    fn from(src: AlternateSubstFormat2) -> AlternateSubst {
2201        AlternateSubst::Format2(src)
2202    }
2203}
2204
2205/// LigatureSubst (ISO/IEC 14496-22:2026).
2206#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2207#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2208pub enum LigatureSubst {
2209    Format1(LigatureSubstFormat1),
2210    Format2(LigatureSubstFormat2),
2211}
2212
2213impl LigatureSubst {
2214    /// Construct a new `LigatureSubstFormat1` subtable
2215    pub fn format_1(coverage: CoverageTable, ligature_sets: Vec<LigatureSet>) -> Self {
2216        Self::Format1(LigatureSubstFormat1::new(coverage, ligature_sets))
2217    }
2218
2219    /// Construct a new `LigatureSubstFormat2` subtable
2220    pub fn format_2(coverage: CoverageTable, ligature_sets: Vec<LigatureSet2>) -> Self {
2221        Self::Format2(LigatureSubstFormat2::new(coverage, ligature_sets))
2222    }
2223}
2224
2225impl Default for LigatureSubst {
2226    fn default() -> Self {
2227        Self::Format1(Default::default())
2228    }
2229}
2230
2231impl FontWrite for LigatureSubst {
2232    fn write_into(&self, writer: &mut TableWriter) {
2233        match self {
2234            Self::Format1(item) => item.write_into(writer),
2235            Self::Format2(item) => item.write_into(writer),
2236        }
2237    }
2238    fn table_type(&self) -> TableType {
2239        match self {
2240            Self::Format1(item) => item.table_type(),
2241            Self::Format2(item) => item.table_type(),
2242        }
2243    }
2244}
2245
2246impl Validate for LigatureSubst {
2247    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2248        match self {
2249            Self::Format1(item) => item.validate_impl(ctx),
2250            Self::Format2(item) => item.validate_impl(ctx),
2251        }
2252    }
2253}
2254
2255impl FromObjRef<read_fonts::tables::gsub::LigatureSubst<'_>> for LigatureSubst {
2256    fn from_obj_ref(obj: &read_fonts::tables::gsub::LigatureSubst, _: FontData) -> Self {
2257        use read_fonts::tables::gsub::LigatureSubst as ObjRefType;
2258        match obj {
2259            ObjRefType::Format1(item) => LigatureSubst::Format1(item.to_owned_table()),
2260            ObjRefType::Format2(item) => LigatureSubst::Format2(item.to_owned_table()),
2261        }
2262    }
2263}
2264
2265impl FromTableRef<read_fonts::tables::gsub::LigatureSubst<'_>> for LigatureSubst {}
2266
2267impl ReadArgs for LigatureSubst {
2268    type Args = ();
2269}
2270
2271impl<'a> FontRead<'a> for LigatureSubst {
2272    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2273        <read_fonts::tables::gsub::LigatureSubst as FontRead>::read(data)
2274            .map(|x| x.to_owned_table())
2275    }
2276}
2277
2278impl From<LigatureSubstFormat1> for LigatureSubst {
2279    fn from(src: LigatureSubstFormat1) -> LigatureSubst {
2280        LigatureSubst::Format1(src)
2281    }
2282}
2283
2284impl From<LigatureSubstFormat2> for LigatureSubst {
2285    fn from(src: LigatureSubstFormat2) -> LigatureSubst {
2286        LigatureSubst::Format2(src)
2287    }
2288}
2289
2290/// ReverseChainSingleSubst (ISO/IEC 14496-22:2026).
2291#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
2292#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2293pub enum ReverseChainSingleSubst {
2294    Format1(ReverseChainSingleSubstFormat1),
2295    Format2(ReverseChainSingleSubstFormat2),
2296}
2297
2298impl ReverseChainSingleSubst {
2299    /// Construct a new `ReverseChainSingleSubstFormat1` subtable
2300    pub fn format_1(
2301        coverage: CoverageTable,
2302        backtrack_coverages: Vec<CoverageTable>,
2303        lookahead_coverages: Vec<CoverageTable>,
2304        substitute_glyph_ids: Vec<GlyphId16>,
2305    ) -> Self {
2306        Self::Format1(ReverseChainSingleSubstFormat1::new(
2307            coverage,
2308            backtrack_coverages,
2309            lookahead_coverages,
2310            substitute_glyph_ids,
2311        ))
2312    }
2313
2314    /// Construct a new `ReverseChainSingleSubstFormat2` subtable
2315    pub fn format_2(
2316        coverage: CoverageTable,
2317        backtrack_coverages: Vec<CoverageTable>,
2318        lookahead_coverages: Vec<CoverageTable>,
2319        substitute_glyph_ids: Vec<GlyphId24>,
2320    ) -> Self {
2321        Self::Format2(ReverseChainSingleSubstFormat2::new(
2322            coverage,
2323            backtrack_coverages,
2324            lookahead_coverages,
2325            substitute_glyph_ids,
2326        ))
2327    }
2328}
2329
2330impl Default for ReverseChainSingleSubst {
2331    fn default() -> Self {
2332        Self::Format1(Default::default())
2333    }
2334}
2335
2336impl FontWrite for ReverseChainSingleSubst {
2337    fn write_into(&self, writer: &mut TableWriter) {
2338        match self {
2339            Self::Format1(item) => item.write_into(writer),
2340            Self::Format2(item) => item.write_into(writer),
2341        }
2342    }
2343    fn table_type(&self) -> TableType {
2344        match self {
2345            Self::Format1(item) => item.table_type(),
2346            Self::Format2(item) => item.table_type(),
2347        }
2348    }
2349}
2350
2351impl Validate for ReverseChainSingleSubst {
2352    fn validate_impl(&self, ctx: &mut ValidationCtx) {
2353        match self {
2354            Self::Format1(item) => item.validate_impl(ctx),
2355            Self::Format2(item) => item.validate_impl(ctx),
2356        }
2357    }
2358}
2359
2360impl FromObjRef<read_fonts::tables::gsub::ReverseChainSingleSubst<'_>> for ReverseChainSingleSubst {
2361    fn from_obj_ref(obj: &read_fonts::tables::gsub::ReverseChainSingleSubst, _: FontData) -> Self {
2362        use read_fonts::tables::gsub::ReverseChainSingleSubst as ObjRefType;
2363        match obj {
2364            ObjRefType::Format1(item) => ReverseChainSingleSubst::Format1(item.to_owned_table()),
2365            ObjRefType::Format2(item) => ReverseChainSingleSubst::Format2(item.to_owned_table()),
2366        }
2367    }
2368}
2369
2370impl FromTableRef<read_fonts::tables::gsub::ReverseChainSingleSubst<'_>>
2371    for ReverseChainSingleSubst
2372{
2373}
2374
2375impl ReadArgs for ReverseChainSingleSubst {
2376    type Args = ();
2377}
2378
2379impl<'a> FontRead<'a> for ReverseChainSingleSubst {
2380    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2381        <read_fonts::tables::gsub::ReverseChainSingleSubst as FontRead>::read(data)
2382            .map(|x| x.to_owned_table())
2383    }
2384}
2385
2386impl From<ReverseChainSingleSubstFormat1> for ReverseChainSingleSubst {
2387    fn from(src: ReverseChainSingleSubstFormat1) -> ReverseChainSingleSubst {
2388        ReverseChainSingleSubst::Format1(src)
2389    }
2390}
2391
2392impl From<ReverseChainSingleSubstFormat2> for ReverseChainSingleSubst {
2393    fn from(src: ReverseChainSingleSubstFormat2) -> ReverseChainSingleSubst {
2394        ReverseChainSingleSubst::Format2(src)
2395    }
2396}