Skip to main content

read_fonts/generated/
generated_stat.rs

1// THIS FILE IS AUTOGENERATED.
2// Any changes to this file will be overwritten.
3// For more information about how codegen works, see font-codegen/README.md
4
5#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Stat<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.offset_to_axis_value_offsets_byte_range().end
11    }
12    fn min_table_bytes(&self) -> &'a [u8] {
13        let range = self.min_byte_range();
14        self.data.as_bytes().get(range).unwrap_or_default()
15    }
16}
17
18impl TopLevelTable for Stat<'_> {
19    /// `STAT`
20    const TAG: Tag = Tag::new(b"STAT");
21}
22
23impl<'a> FontRead<'a> for Stat<'a> {
24    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
25        #[allow(clippy::absurd_extreme_comparisons)]
26        if data.len() < Self::MIN_SIZE {
27            return Err(ReadError::OutOfBounds);
28        }
29        Ok(Self { data })
30    }
31}
32
33/// [STAT](https://docs.microsoft.com/en-us/typography/opentype/spec/stat) (Style Attributes Table)
34#[derive(Clone)]
35pub struct Stat<'a> {
36    data: FontData<'a>,
37}
38
39#[allow(clippy::needless_lifetimes)]
40impl<'a> Stat<'a> {
41    pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
42        + u16::RAW_BYTE_LEN
43        + u16::RAW_BYTE_LEN
44        + Offset32::RAW_BYTE_LEN
45        + u16::RAW_BYTE_LEN
46        + Offset32::RAW_BYTE_LEN);
47    basic_table_impls!(impl_the_methods);
48
49    /// Major/minor version number. Set to 1.2 for new fonts.
50    pub fn version(&self) -> MajorMinor {
51        let range = self.version_byte_range();
52        self.data.read_at(range.start).ok().unwrap()
53    }
54
55    /// The size in bytes of each axis record.
56    pub fn design_axis_size(&self) -> u16 {
57        let range = self.design_axis_size_byte_range();
58        self.data.read_at(range.start).ok().unwrap()
59    }
60
61    /// The number of axis records. In a font with an 'fvar' table,
62    /// this value must be greater than or equal to the axisCount value
63    /// in the 'fvar' table. In all fonts, must be greater than zero if
64    /// axisValueCount is greater than zero.
65    pub fn design_axis_count(&self) -> u16 {
66        let range = self.design_axis_count_byte_range();
67        self.data.read_at(range.start).ok().unwrap()
68    }
69
70    /// Offset in bytes from the beginning of the STAT table to the
71    /// start of the design axes array. If designAxisCount is zero, set
72    /// to zero; if designAxisCount is greater than zero, must be
73    /// greater than zero.
74    pub fn design_axes_offset(&self) -> Offset32 {
75        let range = self.design_axes_offset_byte_range();
76        self.data.read_at(range.start).ok().unwrap()
77    }
78
79    /// Attempt to resolve [`design_axes_offset`][Self::design_axes_offset].
80    pub fn design_axes(&self) -> Result<&'a [AxisRecord], ReadError> {
81        let data = self.data;
82        let args = self.design_axis_count();
83        self.design_axes_offset().resolve_with_args(data, &args)
84    }
85
86    /// The number of axis value tables.
87    pub fn axis_value_count(&self) -> u16 {
88        let range = self.axis_value_count_byte_range();
89        self.data.read_at(range.start).ok().unwrap()
90    }
91
92    /// Offset in bytes from the beginning of the STAT table to the
93    /// start of the design axes value offsets array. If axisValueCount
94    /// is zero, set to zero; if axisValueCount is greater than zero,
95    /// must be greater than zero.
96    pub fn offset_to_axis_value_offsets(&self) -> Nullable<Offset32> {
97        let range = self.offset_to_axis_value_offsets_byte_range();
98        self.data.read_at(range.start).ok().unwrap()
99    }
100
101    /// Attempt to resolve [`offset_to_axis_value_offsets`][Self::offset_to_axis_value_offsets].
102    pub fn offset_to_axis_values(&self) -> Option<Result<AxisValueArray<'a>, ReadError>> {
103        let data = self.data;
104        let args = self.axis_value_count();
105        self.offset_to_axis_value_offsets()
106            .resolve_with_args(data, &args)
107    }
108
109    /// Name ID used as fallback when projection of names into a
110    /// particular font model produces a subfamily name containing only
111    /// elidable elements.
112    pub fn elided_fallback_name_id(&self) -> Option<NameId> {
113        let range = self.elided_fallback_name_id_byte_range();
114        (!range.is_empty())
115            .then(|| self.data.read_at(range.start).ok())
116            .flatten()
117    }
118
119    pub fn version_byte_range(&self) -> Range<usize> {
120        let start = 0;
121        start..start + MajorMinor::RAW_BYTE_LEN
122    }
123
124    pub fn design_axis_size_byte_range(&self) -> Range<usize> {
125        let start = self.version_byte_range().end;
126        start..start + u16::RAW_BYTE_LEN
127    }
128
129    pub fn design_axis_count_byte_range(&self) -> Range<usize> {
130        let start = self.design_axis_size_byte_range().end;
131        start..start + u16::RAW_BYTE_LEN
132    }
133
134    pub fn design_axes_offset_byte_range(&self) -> Range<usize> {
135        let start = self.design_axis_count_byte_range().end;
136        start..start + Offset32::RAW_BYTE_LEN
137    }
138
139    pub fn axis_value_count_byte_range(&self) -> Range<usize> {
140        let start = self.design_axes_offset_byte_range().end;
141        start..start + u16::RAW_BYTE_LEN
142    }
143
144    pub fn offset_to_axis_value_offsets_byte_range(&self) -> Range<usize> {
145        let start = self.axis_value_count_byte_range().end;
146        start..start + Offset32::RAW_BYTE_LEN
147    }
148
149    pub fn elided_fallback_name_id_byte_range(&self) -> Range<usize> {
150        let start = self.offset_to_axis_value_offsets_byte_range().end;
151        start
152            ..(self.version().compatible((1u16, 1u16)))
153                .then(|| start + NameId::RAW_BYTE_LEN)
154                .unwrap_or(start)
155    }
156}
157
158#[cfg(feature = "experimental_traverse")]
159impl<'a> SomeTable<'a> for Stat<'a> {
160    fn type_name(&self) -> &str {
161        "Stat"
162    }
163    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
164        match idx {
165            0usize => Some(Field::new("version", self.version())),
166            1usize => Some(Field::new("design_axis_size", self.design_axis_size())),
167            2usize => Some(Field::new("design_axis_count", self.design_axis_count())),
168            3usize => Some(Field::new(
169                "design_axes_offset",
170                traversal::FieldType::offset_to_array_of_records(
171                    self.design_axes_offset(),
172                    self.design_axes(),
173                    stringify!(AxisRecord),
174                    self.offset_data(),
175                ),
176            )),
177            4usize => Some(Field::new("axis_value_count", self.axis_value_count())),
178            5usize => Some(Field::new(
179                "offset_to_axis_value_offsets",
180                FieldType::offset(
181                    self.offset_to_axis_value_offsets(),
182                    self.offset_to_axis_values(),
183                ),
184            )),
185            6usize if self.version().compatible((1u16, 1u16)) => Some(Field::new(
186                "elided_fallback_name_id",
187                self.elided_fallback_name_id().unwrap(),
188            )),
189            _ => None,
190        }
191    }
192}
193
194#[cfg(feature = "experimental_traverse")]
195#[allow(clippy::needless_lifetimes)]
196impl<'a> std::fmt::Debug for Stat<'a> {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        (self as &dyn SomeTable<'a>).fmt(f)
199    }
200}
201
202/// [Axis Records](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-records)
203#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
204#[repr(C)]
205#[repr(packed)]
206pub struct AxisRecord {
207    /// A tag identifying the axis of design variation.
208    pub axis_tag: BigEndian<Tag>,
209    /// The name ID for entries in the 'name' table that provide a
210    /// display string for this axis.
211    pub axis_name_id: BigEndian<NameId>,
212    /// A value that applications can use to determine primary sorting
213    /// of face names, or for ordering of labels when composing family
214    /// or face names.
215    pub axis_ordering: BigEndian<u16>,
216}
217
218impl AxisRecord {
219    /// A tag identifying the axis of design variation.
220    pub fn axis_tag(&self) -> Tag {
221        self.axis_tag.get()
222    }
223
224    /// The name ID for entries in the 'name' table that provide a
225    /// display string for this axis.
226    pub fn axis_name_id(&self) -> NameId {
227        self.axis_name_id.get()
228    }
229
230    /// A value that applications can use to determine primary sorting
231    /// of face names, or for ordering of labels when composing family
232    /// or face names.
233    pub fn axis_ordering(&self) -> u16 {
234        self.axis_ordering.get()
235    }
236}
237
238impl FixedSize for AxisRecord {
239    const RAW_BYTE_LEN: usize = Tag::RAW_BYTE_LEN + NameId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
240}
241
242#[cfg(feature = "experimental_traverse")]
243impl<'a> SomeRecord<'a> for AxisRecord {
244    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
245        RecordResolver {
246            name: "AxisRecord",
247            get_field: Box::new(move |idx, _data| match idx {
248                0usize => Some(Field::new("axis_tag", self.axis_tag())),
249                1usize => Some(Field::new("axis_name_id", self.axis_name_id())),
250                2usize => Some(Field::new("axis_ordering", self.axis_ordering())),
251                _ => None,
252            }),
253            data,
254        }
255    }
256}
257
258impl<'a> MinByteRange<'a> for AxisValueArray<'a> {
259    fn min_byte_range(&self) -> Range<usize> {
260        0..self.axis_value_offsets_byte_range().end
261    }
262    fn min_table_bytes(&self) -> &'a [u8] {
263        let range = self.min_byte_range();
264        self.data.as_bytes().get(range).unwrap_or_default()
265    }
266}
267
268impl ReadArgs for AxisValueArray<'_> {
269    type Args = u16;
270}
271
272impl<'a> FontReadWithArgs<'a> for AxisValueArray<'a> {
273    fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
274        let axis_value_count = *args;
275
276        #[allow(clippy::absurd_extreme_comparisons)]
277        if data.len() < Self::MIN_SIZE {
278            return Err(ReadError::OutOfBounds);
279        }
280        Ok(Self {
281            data,
282            axis_value_count,
283        })
284    }
285}
286
287impl<'a> AxisValueArray<'a> {
288    /// A constructor that requires additional arguments.
289    ///
290    /// This type requires some external state in order to be
291    /// parsed.
292    pub fn read(data: FontData<'a>, axis_value_count: u16) -> Result<Self, ReadError> {
293        let args = axis_value_count;
294        Self::read_with_args(data, &args)
295    }
296}
297
298/// An array of [AxisValue] tables.
299#[derive(Clone)]
300pub struct AxisValueArray<'a> {
301    data: FontData<'a>,
302    axis_value_count: u16,
303}
304
305#[allow(clippy::needless_lifetimes)]
306impl<'a> AxisValueArray<'a> {
307    pub const MIN_SIZE: usize = 0;
308    basic_table_impls!(impl_the_methods);
309
310    /// Array of offsets to axis value tables, in bytes from the start
311    /// of the axis value offsets array.
312    pub fn axis_value_offsets(&self) -> &'a [BigEndian<Offset16>] {
313        let range = self.axis_value_offsets_byte_range();
314        self.data.read_array(range).ok().unwrap_or_default()
315    }
316
317    /// A dynamically resolving wrapper for [`axis_value_offsets`][Self::axis_value_offsets].
318    pub fn axis_values(&self) -> ArrayOfOffsets<'a, AxisValue<'a>, Offset16> {
319        let data = self.data;
320        let offsets = self.axis_value_offsets();
321        ArrayOfOffsets::new(offsets, data, ())
322    }
323
324    pub(crate) fn axis_value_count(&self) -> u16 {
325        self.axis_value_count
326    }
327
328    pub fn axis_value_offsets_byte_range(&self) -> Range<usize> {
329        let axis_value_count = self.axis_value_count();
330        let start = 0;
331        start..start + (axis_value_count as usize).saturating_mul(Offset16::RAW_BYTE_LEN)
332    }
333}
334
335#[cfg(feature = "experimental_traverse")]
336impl<'a> SomeTable<'a> for AxisValueArray<'a> {
337    fn type_name(&self) -> &str {
338        "AxisValueArray"
339    }
340    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
341        match idx {
342            0usize => Some({
343                let data = self.data;
344                Field::new(
345                    "axis_value_offsets",
346                    FieldType::array_of_offsets(
347                        better_type_name::<AxisValue>(),
348                        self.axis_value_offsets(),
349                        move |off| {
350                            let target = off.get().resolve::<AxisValue>(data);
351                            FieldType::offset(off.get(), target)
352                        },
353                    ),
354                )
355            }),
356            _ => None,
357        }
358    }
359}
360
361#[cfg(feature = "experimental_traverse")]
362#[allow(clippy::needless_lifetimes)]
363impl<'a> std::fmt::Debug for AxisValueArray<'a> {
364    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
365        (self as &dyn SomeTable<'a>).fmt(f)
366    }
367}
368
369/// [Axis Value Tables](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-tables)
370#[derive(Clone)]
371pub enum AxisValue<'a> {
372    Format1(AxisValueFormat1<'a>),
373    Format2(AxisValueFormat2<'a>),
374    Format3(AxisValueFormat3<'a>),
375    Format4(AxisValueFormat4<'a>),
376}
377
378impl<'a> AxisValue<'a> {
379    ///Return the `FontData` used to resolve offsets for this table.
380    pub fn offset_data(&self) -> FontData<'a> {
381        match self {
382            Self::Format1(item) => item.offset_data(),
383            Self::Format2(item) => item.offset_data(),
384            Self::Format3(item) => item.offset_data(),
385            Self::Format4(item) => item.offset_data(),
386        }
387    }
388
389    /// Format identifier — set to 1.
390    pub fn format(&self) -> u16 {
391        match self {
392            Self::Format1(item) => item.format(),
393            Self::Format2(item) => item.format(),
394            Self::Format3(item) => item.format(),
395            Self::Format4(item) => item.format(),
396        }
397    }
398
399    /// Flags — see below for details.
400    pub fn flags(&self) -> AxisValueTableFlags {
401        match self {
402            Self::Format1(item) => item.flags(),
403            Self::Format2(item) => item.flags(),
404            Self::Format3(item) => item.flags(),
405            Self::Format4(item) => item.flags(),
406        }
407    }
408
409    /// The name ID for entries in the 'name' table that provide a
410    /// display string for this attribute value.
411    pub fn value_name_id(&self) -> NameId {
412        match self {
413            Self::Format1(item) => item.value_name_id(),
414            Self::Format2(item) => item.value_name_id(),
415            Self::Format3(item) => item.value_name_id(),
416            Self::Format4(item) => item.value_name_id(),
417        }
418    }
419}
420
421impl<'a> FontRead<'a> for AxisValue<'a> {
422    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
423        let format: u16 = data.read_at(0usize)?;
424        match format {
425            AxisValueFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
426            AxisValueFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
427            AxisValueFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
428            AxisValueFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
429            other => Err(ReadError::InvalidFormat(other.into())),
430        }
431    }
432}
433
434impl<'a> MinByteRange<'a> for AxisValue<'a> {
435    fn min_byte_range(&self) -> Range<usize> {
436        match self {
437            Self::Format1(item) => item.min_byte_range(),
438            Self::Format2(item) => item.min_byte_range(),
439            Self::Format3(item) => item.min_byte_range(),
440            Self::Format4(item) => item.min_byte_range(),
441        }
442    }
443    fn min_table_bytes(&self) -> &'a [u8] {
444        match self {
445            Self::Format1(item) => item.min_table_bytes(),
446            Self::Format2(item) => item.min_table_bytes(),
447            Self::Format3(item) => item.min_table_bytes(),
448            Self::Format4(item) => item.min_table_bytes(),
449        }
450    }
451}
452
453#[cfg(feature = "experimental_traverse")]
454impl<'a> AxisValue<'a> {
455    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
456        match self {
457            Self::Format1(table) => table,
458            Self::Format2(table) => table,
459            Self::Format3(table) => table,
460            Self::Format4(table) => table,
461        }
462    }
463}
464
465#[cfg(feature = "experimental_traverse")]
466impl std::fmt::Debug for AxisValue<'_> {
467    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468        self.dyn_inner().fmt(f)
469    }
470}
471
472#[cfg(feature = "experimental_traverse")]
473impl<'a> SomeTable<'a> for AxisValue<'a> {
474    fn type_name(&self) -> &str {
475        self.dyn_inner().type_name()
476    }
477    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
478        self.dyn_inner().get_field(idx)
479    }
480}
481
482impl Format<u16> for AxisValueFormat1<'_> {
483    const FORMAT: u16 = 1;
484}
485
486impl<'a> MinByteRange<'a> for AxisValueFormat1<'a> {
487    fn min_byte_range(&self) -> Range<usize> {
488        0..self.value_byte_range().end
489    }
490    fn min_table_bytes(&self) -> &'a [u8] {
491        let range = self.min_byte_range();
492        self.data.as_bytes().get(range).unwrap_or_default()
493    }
494}
495
496impl<'a> FontRead<'a> for AxisValueFormat1<'a> {
497    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
498        #[allow(clippy::absurd_extreme_comparisons)]
499        if data.len() < Self::MIN_SIZE {
500            return Err(ReadError::OutOfBounds);
501        }
502        Ok(Self { data })
503    }
504}
505
506/// [Axis value table format 1](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-1)
507#[derive(Clone)]
508pub struct AxisValueFormat1<'a> {
509    data: FontData<'a>,
510}
511
512#[allow(clippy::needless_lifetimes)]
513impl<'a> AxisValueFormat1<'a> {
514    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
515        + u16::RAW_BYTE_LEN
516        + AxisValueTableFlags::RAW_BYTE_LEN
517        + NameId::RAW_BYTE_LEN
518        + Fixed::RAW_BYTE_LEN);
519    basic_table_impls!(impl_the_methods);
520
521    /// Format identifier — set to 1.
522    pub fn format(&self) -> u16 {
523        let range = self.format_byte_range();
524        self.data.read_at(range.start).ok().unwrap()
525    }
526
527    /// Zero-base index into the axis record array identifying the axis
528    /// of design variation to which the axis value table applies. Must
529    /// be less than designAxisCount.
530    pub fn axis_index(&self) -> u16 {
531        let range = self.axis_index_byte_range();
532        self.data.read_at(range.start).ok().unwrap()
533    }
534
535    /// Flags — see below for details.
536    pub fn flags(&self) -> AxisValueTableFlags {
537        let range = self.flags_byte_range();
538        self.data.read_at(range.start).ok().unwrap()
539    }
540
541    /// The name ID for entries in the 'name' table that provide a
542    /// display string for this attribute value.
543    pub fn value_name_id(&self) -> NameId {
544        let range = self.value_name_id_byte_range();
545        self.data.read_at(range.start).ok().unwrap()
546    }
547
548    /// A numeric value for this attribute value.
549    pub fn value(&self) -> Fixed {
550        let range = self.value_byte_range();
551        self.data.read_at(range.start).ok().unwrap()
552    }
553
554    pub fn format_byte_range(&self) -> Range<usize> {
555        let start = 0;
556        start..start + u16::RAW_BYTE_LEN
557    }
558
559    pub fn axis_index_byte_range(&self) -> Range<usize> {
560        let start = self.format_byte_range().end;
561        start..start + u16::RAW_BYTE_LEN
562    }
563
564    pub fn flags_byte_range(&self) -> Range<usize> {
565        let start = self.axis_index_byte_range().end;
566        start..start + AxisValueTableFlags::RAW_BYTE_LEN
567    }
568
569    pub fn value_name_id_byte_range(&self) -> Range<usize> {
570        let start = self.flags_byte_range().end;
571        start..start + NameId::RAW_BYTE_LEN
572    }
573
574    pub fn value_byte_range(&self) -> Range<usize> {
575        let start = self.value_name_id_byte_range().end;
576        start..start + Fixed::RAW_BYTE_LEN
577    }
578}
579
580#[cfg(feature = "experimental_traverse")]
581impl<'a> SomeTable<'a> for AxisValueFormat1<'a> {
582    fn type_name(&self) -> &str {
583        "AxisValueFormat1"
584    }
585    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
586        match idx {
587            0usize => Some(Field::new("format", self.format())),
588            1usize => Some(Field::new("axis_index", self.axis_index())),
589            2usize => Some(Field::new("flags", self.flags())),
590            3usize => Some(Field::new("value_name_id", self.value_name_id())),
591            4usize => Some(Field::new("value", self.value())),
592            _ => None,
593        }
594    }
595}
596
597#[cfg(feature = "experimental_traverse")]
598#[allow(clippy::needless_lifetimes)]
599impl<'a> std::fmt::Debug for AxisValueFormat1<'a> {
600    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
601        (self as &dyn SomeTable<'a>).fmt(f)
602    }
603}
604
605impl Format<u16> for AxisValueFormat2<'_> {
606    const FORMAT: u16 = 2;
607}
608
609impl<'a> MinByteRange<'a> for AxisValueFormat2<'a> {
610    fn min_byte_range(&self) -> Range<usize> {
611        0..self.range_max_value_byte_range().end
612    }
613    fn min_table_bytes(&self) -> &'a [u8] {
614        let range = self.min_byte_range();
615        self.data.as_bytes().get(range).unwrap_or_default()
616    }
617}
618
619impl<'a> FontRead<'a> for AxisValueFormat2<'a> {
620    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
621        #[allow(clippy::absurd_extreme_comparisons)]
622        if data.len() < Self::MIN_SIZE {
623            return Err(ReadError::OutOfBounds);
624        }
625        Ok(Self { data })
626    }
627}
628
629/// [Axis value table format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-2)
630#[derive(Clone)]
631pub struct AxisValueFormat2<'a> {
632    data: FontData<'a>,
633}
634
635#[allow(clippy::needless_lifetimes)]
636impl<'a> AxisValueFormat2<'a> {
637    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
638        + u16::RAW_BYTE_LEN
639        + AxisValueTableFlags::RAW_BYTE_LEN
640        + NameId::RAW_BYTE_LEN
641        + Fixed::RAW_BYTE_LEN
642        + Fixed::RAW_BYTE_LEN
643        + Fixed::RAW_BYTE_LEN);
644    basic_table_impls!(impl_the_methods);
645
646    /// Format identifier — set to 2.
647    pub fn format(&self) -> u16 {
648        let range = self.format_byte_range();
649        self.data.read_at(range.start).ok().unwrap()
650    }
651
652    /// Zero-base index into the axis record array identifying the axis
653    /// of design variation to which the axis value table applies. Must
654    /// be less than designAxisCount.
655    pub fn axis_index(&self) -> u16 {
656        let range = self.axis_index_byte_range();
657        self.data.read_at(range.start).ok().unwrap()
658    }
659
660    /// Flags — see below for details.
661    pub fn flags(&self) -> AxisValueTableFlags {
662        let range = self.flags_byte_range();
663        self.data.read_at(range.start).ok().unwrap()
664    }
665
666    /// The name ID for entries in the 'name' table that provide a
667    /// display string for this attribute value.
668    pub fn value_name_id(&self) -> NameId {
669        let range = self.value_name_id_byte_range();
670        self.data.read_at(range.start).ok().unwrap()
671    }
672
673    /// A nominal numeric value for this attribute value.
674    pub fn nominal_value(&self) -> Fixed {
675        let range = self.nominal_value_byte_range();
676        self.data.read_at(range.start).ok().unwrap()
677    }
678
679    /// The minimum value for a range associated with the specified
680    /// name ID.
681    pub fn range_min_value(&self) -> Fixed {
682        let range = self.range_min_value_byte_range();
683        self.data.read_at(range.start).ok().unwrap()
684    }
685
686    /// The maximum value for a range associated with the specified
687    /// name ID.
688    pub fn range_max_value(&self) -> Fixed {
689        let range = self.range_max_value_byte_range();
690        self.data.read_at(range.start).ok().unwrap()
691    }
692
693    pub fn format_byte_range(&self) -> Range<usize> {
694        let start = 0;
695        start..start + u16::RAW_BYTE_LEN
696    }
697
698    pub fn axis_index_byte_range(&self) -> Range<usize> {
699        let start = self.format_byte_range().end;
700        start..start + u16::RAW_BYTE_LEN
701    }
702
703    pub fn flags_byte_range(&self) -> Range<usize> {
704        let start = self.axis_index_byte_range().end;
705        start..start + AxisValueTableFlags::RAW_BYTE_LEN
706    }
707
708    pub fn value_name_id_byte_range(&self) -> Range<usize> {
709        let start = self.flags_byte_range().end;
710        start..start + NameId::RAW_BYTE_LEN
711    }
712
713    pub fn nominal_value_byte_range(&self) -> Range<usize> {
714        let start = self.value_name_id_byte_range().end;
715        start..start + Fixed::RAW_BYTE_LEN
716    }
717
718    pub fn range_min_value_byte_range(&self) -> Range<usize> {
719        let start = self.nominal_value_byte_range().end;
720        start..start + Fixed::RAW_BYTE_LEN
721    }
722
723    pub fn range_max_value_byte_range(&self) -> Range<usize> {
724        let start = self.range_min_value_byte_range().end;
725        start..start + Fixed::RAW_BYTE_LEN
726    }
727}
728
729#[cfg(feature = "experimental_traverse")]
730impl<'a> SomeTable<'a> for AxisValueFormat2<'a> {
731    fn type_name(&self) -> &str {
732        "AxisValueFormat2"
733    }
734    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
735        match idx {
736            0usize => Some(Field::new("format", self.format())),
737            1usize => Some(Field::new("axis_index", self.axis_index())),
738            2usize => Some(Field::new("flags", self.flags())),
739            3usize => Some(Field::new("value_name_id", self.value_name_id())),
740            4usize => Some(Field::new("nominal_value", self.nominal_value())),
741            5usize => Some(Field::new("range_min_value", self.range_min_value())),
742            6usize => Some(Field::new("range_max_value", self.range_max_value())),
743            _ => None,
744        }
745    }
746}
747
748#[cfg(feature = "experimental_traverse")]
749#[allow(clippy::needless_lifetimes)]
750impl<'a> std::fmt::Debug for AxisValueFormat2<'a> {
751    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
752        (self as &dyn SomeTable<'a>).fmt(f)
753    }
754}
755
756impl Format<u16> for AxisValueFormat3<'_> {
757    const FORMAT: u16 = 3;
758}
759
760impl<'a> MinByteRange<'a> for AxisValueFormat3<'a> {
761    fn min_byte_range(&self) -> Range<usize> {
762        0..self.linked_value_byte_range().end
763    }
764    fn min_table_bytes(&self) -> &'a [u8] {
765        let range = self.min_byte_range();
766        self.data.as_bytes().get(range).unwrap_or_default()
767    }
768}
769
770impl<'a> FontRead<'a> for AxisValueFormat3<'a> {
771    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
772        #[allow(clippy::absurd_extreme_comparisons)]
773        if data.len() < Self::MIN_SIZE {
774            return Err(ReadError::OutOfBounds);
775        }
776        Ok(Self { data })
777    }
778}
779
780/// [Axis value table format 3](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-3)
781#[derive(Clone)]
782pub struct AxisValueFormat3<'a> {
783    data: FontData<'a>,
784}
785
786#[allow(clippy::needless_lifetimes)]
787impl<'a> AxisValueFormat3<'a> {
788    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
789        + u16::RAW_BYTE_LEN
790        + AxisValueTableFlags::RAW_BYTE_LEN
791        + NameId::RAW_BYTE_LEN
792        + Fixed::RAW_BYTE_LEN
793        + Fixed::RAW_BYTE_LEN);
794    basic_table_impls!(impl_the_methods);
795
796    /// Format identifier — set to 3.
797    pub fn format(&self) -> u16 {
798        let range = self.format_byte_range();
799        self.data.read_at(range.start).ok().unwrap()
800    }
801
802    /// Zero-base index into the axis record array identifying the axis
803    /// of design variation to which the axis value table applies. Must
804    /// be less than designAxisCount.
805    pub fn axis_index(&self) -> u16 {
806        let range = self.axis_index_byte_range();
807        self.data.read_at(range.start).ok().unwrap()
808    }
809
810    /// Flags — see below for details.
811    pub fn flags(&self) -> AxisValueTableFlags {
812        let range = self.flags_byte_range();
813        self.data.read_at(range.start).ok().unwrap()
814    }
815
816    /// The name ID for entries in the 'name' table that provide a
817    /// display string for this attribute value.
818    pub fn value_name_id(&self) -> NameId {
819        let range = self.value_name_id_byte_range();
820        self.data.read_at(range.start).ok().unwrap()
821    }
822
823    /// A numeric value for this attribute value.
824    pub fn value(&self) -> Fixed {
825        let range = self.value_byte_range();
826        self.data.read_at(range.start).ok().unwrap()
827    }
828
829    /// The numeric value for a style-linked mapping from this value.
830    pub fn linked_value(&self) -> Fixed {
831        let range = self.linked_value_byte_range();
832        self.data.read_at(range.start).ok().unwrap()
833    }
834
835    pub fn format_byte_range(&self) -> Range<usize> {
836        let start = 0;
837        start..start + u16::RAW_BYTE_LEN
838    }
839
840    pub fn axis_index_byte_range(&self) -> Range<usize> {
841        let start = self.format_byte_range().end;
842        start..start + u16::RAW_BYTE_LEN
843    }
844
845    pub fn flags_byte_range(&self) -> Range<usize> {
846        let start = self.axis_index_byte_range().end;
847        start..start + AxisValueTableFlags::RAW_BYTE_LEN
848    }
849
850    pub fn value_name_id_byte_range(&self) -> Range<usize> {
851        let start = self.flags_byte_range().end;
852        start..start + NameId::RAW_BYTE_LEN
853    }
854
855    pub fn value_byte_range(&self) -> Range<usize> {
856        let start = self.value_name_id_byte_range().end;
857        start..start + Fixed::RAW_BYTE_LEN
858    }
859
860    pub fn linked_value_byte_range(&self) -> Range<usize> {
861        let start = self.value_byte_range().end;
862        start..start + Fixed::RAW_BYTE_LEN
863    }
864}
865
866#[cfg(feature = "experimental_traverse")]
867impl<'a> SomeTable<'a> for AxisValueFormat3<'a> {
868    fn type_name(&self) -> &str {
869        "AxisValueFormat3"
870    }
871    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
872        match idx {
873            0usize => Some(Field::new("format", self.format())),
874            1usize => Some(Field::new("axis_index", self.axis_index())),
875            2usize => Some(Field::new("flags", self.flags())),
876            3usize => Some(Field::new("value_name_id", self.value_name_id())),
877            4usize => Some(Field::new("value", self.value())),
878            5usize => Some(Field::new("linked_value", self.linked_value())),
879            _ => None,
880        }
881    }
882}
883
884#[cfg(feature = "experimental_traverse")]
885#[allow(clippy::needless_lifetimes)]
886impl<'a> std::fmt::Debug for AxisValueFormat3<'a> {
887    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
888        (self as &dyn SomeTable<'a>).fmt(f)
889    }
890}
891
892impl Format<u16> for AxisValueFormat4<'_> {
893    const FORMAT: u16 = 4;
894}
895
896impl<'a> MinByteRange<'a> for AxisValueFormat4<'a> {
897    fn min_byte_range(&self) -> Range<usize> {
898        0..self.axis_values_byte_range().end
899    }
900    fn min_table_bytes(&self) -> &'a [u8] {
901        let range = self.min_byte_range();
902        self.data.as_bytes().get(range).unwrap_or_default()
903    }
904}
905
906impl<'a> FontRead<'a> for AxisValueFormat4<'a> {
907    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
908        #[allow(clippy::absurd_extreme_comparisons)]
909        if data.len() < Self::MIN_SIZE {
910            return Err(ReadError::OutOfBounds);
911        }
912        Ok(Self { data })
913    }
914}
915
916/// [Axis value table format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-table-format-4)
917#[derive(Clone)]
918pub struct AxisValueFormat4<'a> {
919    data: FontData<'a>,
920}
921
922#[allow(clippy::needless_lifetimes)]
923impl<'a> AxisValueFormat4<'a> {
924    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
925        + u16::RAW_BYTE_LEN
926        + AxisValueTableFlags::RAW_BYTE_LEN
927        + NameId::RAW_BYTE_LEN);
928    basic_table_impls!(impl_the_methods);
929
930    /// Format identifier — set to 4.
931    pub fn format(&self) -> u16 {
932        let range = self.format_byte_range();
933        self.data.read_at(range.start).ok().unwrap()
934    }
935
936    /// The total number of axes contributing to this axis-values
937    /// combination.
938    pub fn axis_count(&self) -> u16 {
939        let range = self.axis_count_byte_range();
940        self.data.read_at(range.start).ok().unwrap()
941    }
942
943    /// Flags — see below for details.
944    pub fn flags(&self) -> AxisValueTableFlags {
945        let range = self.flags_byte_range();
946        self.data.read_at(range.start).ok().unwrap()
947    }
948
949    /// The name ID for entries in the 'name' table that provide a
950    /// display string for this combination of axis values.
951    pub fn value_name_id(&self) -> NameId {
952        let range = self.value_name_id_byte_range();
953        self.data.read_at(range.start).ok().unwrap()
954    }
955
956    /// Array of AxisValue records that provide the combination of axis
957    /// values, one for each contributing axis.
958    pub fn axis_values(&self) -> &'a [AxisValueRecord] {
959        let range = self.axis_values_byte_range();
960        self.data.read_array(range).ok().unwrap_or_default()
961    }
962
963    pub fn format_byte_range(&self) -> Range<usize> {
964        let start = 0;
965        start..start + u16::RAW_BYTE_LEN
966    }
967
968    pub fn axis_count_byte_range(&self) -> Range<usize> {
969        let start = self.format_byte_range().end;
970        start..start + u16::RAW_BYTE_LEN
971    }
972
973    pub fn flags_byte_range(&self) -> Range<usize> {
974        let start = self.axis_count_byte_range().end;
975        start..start + AxisValueTableFlags::RAW_BYTE_LEN
976    }
977
978    pub fn value_name_id_byte_range(&self) -> Range<usize> {
979        let start = self.flags_byte_range().end;
980        start..start + NameId::RAW_BYTE_LEN
981    }
982
983    pub fn axis_values_byte_range(&self) -> Range<usize> {
984        let axis_count = self.axis_count();
985        let start = self.value_name_id_byte_range().end;
986        start..start + (axis_count as usize).saturating_mul(AxisValueRecord::RAW_BYTE_LEN)
987    }
988}
989
990#[cfg(feature = "experimental_traverse")]
991impl<'a> SomeTable<'a> for AxisValueFormat4<'a> {
992    fn type_name(&self) -> &str {
993        "AxisValueFormat4"
994    }
995    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
996        match idx {
997            0usize => Some(Field::new("format", self.format())),
998            1usize => Some(Field::new("axis_count", self.axis_count())),
999            2usize => Some(Field::new("flags", self.flags())),
1000            3usize => Some(Field::new("value_name_id", self.value_name_id())),
1001            4usize => Some(Field::new(
1002                "axis_values",
1003                traversal::FieldType::array_of_records(
1004                    stringify!(AxisValueRecord),
1005                    self.axis_values(),
1006                    self.offset_data(),
1007                ),
1008            )),
1009            _ => None,
1010        }
1011    }
1012}
1013
1014#[cfg(feature = "experimental_traverse")]
1015#[allow(clippy::needless_lifetimes)]
1016impl<'a> std::fmt::Debug for AxisValueFormat4<'a> {
1017    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1018        (self as &dyn SomeTable<'a>).fmt(f)
1019    }
1020}
1021
1022/// Part of [AxisValueFormat4]
1023#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1024#[repr(C)]
1025#[repr(packed)]
1026pub struct AxisValueRecord {
1027    /// Zero-base index into the axis record array identifying the axis
1028    /// to which this value applies. Must be less than designAxisCount.
1029    pub axis_index: BigEndian<u16>,
1030    /// A numeric value for this attribute value.
1031    pub value: BigEndian<Fixed>,
1032}
1033
1034impl AxisValueRecord {
1035    /// Zero-base index into the axis record array identifying the axis
1036    /// to which this value applies. Must be less than designAxisCount.
1037    pub fn axis_index(&self) -> u16 {
1038        self.axis_index.get()
1039    }
1040
1041    /// A numeric value for this attribute value.
1042    pub fn value(&self) -> Fixed {
1043        self.value.get()
1044    }
1045}
1046
1047impl FixedSize for AxisValueRecord {
1048    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Fixed::RAW_BYTE_LEN;
1049}
1050
1051#[cfg(feature = "experimental_traverse")]
1052impl<'a> SomeRecord<'a> for AxisValueRecord {
1053    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1054        RecordResolver {
1055            name: "AxisValueRecord",
1056            get_field: Box::new(move |idx, _data| match idx {
1057                0usize => Some(Field::new("axis_index", self.axis_index())),
1058                1usize => Some(Field::new("value", self.value())),
1059                _ => None,
1060            }),
1061            data,
1062        }
1063    }
1064}
1065
1066/// [Axis value table flags](https://docs.microsoft.com/en-us/typography/opentype/spec/stat#flags).
1067#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
1068#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1069#[repr(transparent)]
1070pub struct AxisValueTableFlags {
1071    bits: u16,
1072}
1073
1074impl AxisValueTableFlags {
1075    /// If set, this axis value table provides axis value information
1076    /// that is applicable to other fonts within the same font family.
1077    /// This is used if the other fonts were released earlier and did
1078    /// not include information about values for some axis. If newer
1079    /// versions of the other fonts include the information themselves
1080    /// and are present, then this table is ignored.
1081    pub const OLDER_SIBLING_FONT_ATTRIBUTE: Self = Self { bits: 0x0001 };
1082
1083    /// If set, it indicates that the axis value represents the
1084    /// “normal” value for the axis and may be omitted when
1085    /// composing name strings.
1086    pub const ELIDABLE_AXIS_VALUE_NAME: Self = Self { bits: 0x0002 };
1087}
1088
1089impl AxisValueTableFlags {
1090    ///  Returns an empty set of flags.
1091    #[inline]
1092    pub const fn empty() -> Self {
1093        Self { bits: 0 }
1094    }
1095
1096    /// Returns the set containing all flags.
1097    #[inline]
1098    pub const fn all() -> Self {
1099        Self {
1100            bits: Self::OLDER_SIBLING_FONT_ATTRIBUTE.bits | Self::ELIDABLE_AXIS_VALUE_NAME.bits,
1101        }
1102    }
1103
1104    /// Returns the raw value of the flags currently stored.
1105    #[inline]
1106    pub const fn bits(&self) -> u16 {
1107        self.bits
1108    }
1109
1110    /// Convert from underlying bit representation, unless that
1111    /// representation contains bits that do not correspond to a flag.
1112    #[inline]
1113    pub const fn from_bits(bits: u16) -> Option<Self> {
1114        if (bits & !Self::all().bits()) == 0 {
1115            Some(Self { bits })
1116        } else {
1117            None
1118        }
1119    }
1120
1121    /// Convert from underlying bit representation, dropping any bits
1122    /// that do not correspond to flags.
1123    #[inline]
1124    pub const fn from_bits_truncate(bits: u16) -> Self {
1125        Self {
1126            bits: bits & Self::all().bits,
1127        }
1128    }
1129
1130    /// Returns `true` if no flags are currently stored.
1131    #[inline]
1132    pub const fn is_empty(&self) -> bool {
1133        self.bits() == Self::empty().bits()
1134    }
1135
1136    /// Returns `true` if there are flags common to both `self` and `other`.
1137    #[inline]
1138    pub const fn intersects(&self, other: Self) -> bool {
1139        !(Self {
1140            bits: self.bits & other.bits,
1141        })
1142        .is_empty()
1143    }
1144
1145    /// Returns `true` if all of the flags in `other` are contained within `self`.
1146    #[inline]
1147    pub const fn contains(&self, other: Self) -> bool {
1148        (self.bits & other.bits) == other.bits
1149    }
1150
1151    /// Inserts the specified flags in-place.
1152    #[inline]
1153    pub fn insert(&mut self, other: Self) {
1154        self.bits |= other.bits;
1155    }
1156
1157    /// Removes the specified flags in-place.
1158    #[inline]
1159    pub fn remove(&mut self, other: Self) {
1160        self.bits &= !other.bits;
1161    }
1162
1163    /// Toggles the specified flags in-place.
1164    #[inline]
1165    pub fn toggle(&mut self, other: Self) {
1166        self.bits ^= other.bits;
1167    }
1168
1169    /// Returns the intersection between the flags in `self` and
1170    /// `other`.
1171    ///
1172    /// Specifically, the returned set contains only the flags which are
1173    /// present in *both* `self` *and* `other`.
1174    ///
1175    /// This is equivalent to using the `&` operator (e.g.
1176    /// [`ops::BitAnd`]), as in `flags & other`.
1177    ///
1178    /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
1179    #[inline]
1180    #[must_use]
1181    pub const fn intersection(self, other: Self) -> Self {
1182        Self {
1183            bits: self.bits & other.bits,
1184        }
1185    }
1186
1187    /// Returns the union of between the flags in `self` and `other`.
1188    ///
1189    /// Specifically, the returned set contains all flags which are
1190    /// present in *either* `self` *or* `other`, including any which are
1191    /// present in both.
1192    ///
1193    /// This is equivalent to using the `|` operator (e.g.
1194    /// [`ops::BitOr`]), as in `flags | other`.
1195    ///
1196    /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
1197    #[inline]
1198    #[must_use]
1199    pub const fn union(self, other: Self) -> Self {
1200        Self {
1201            bits: self.bits | other.bits,
1202        }
1203    }
1204
1205    /// Returns the difference between the flags in `self` and `other`.
1206    ///
1207    /// Specifically, the returned set contains all flags present in
1208    /// `self`, except for the ones present in `other`.
1209    ///
1210    /// It is also conceptually equivalent to the "bit-clear" operation:
1211    /// `flags & !other` (and this syntax is also supported).
1212    ///
1213    /// This is equivalent to using the `-` operator (e.g.
1214    /// [`ops::Sub`]), as in `flags - other`.
1215    ///
1216    /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
1217    #[inline]
1218    #[must_use]
1219    pub const fn difference(self, other: Self) -> Self {
1220        Self {
1221            bits: self.bits & !other.bits,
1222        }
1223    }
1224}
1225
1226impl std::ops::BitOr for AxisValueTableFlags {
1227    type Output = Self;
1228
1229    /// Returns the union of the two sets of flags.
1230    #[inline]
1231    fn bitor(self, other: AxisValueTableFlags) -> Self {
1232        Self {
1233            bits: self.bits | other.bits,
1234        }
1235    }
1236}
1237
1238impl std::ops::BitOrAssign for AxisValueTableFlags {
1239    /// Adds the set of flags.
1240    #[inline]
1241    fn bitor_assign(&mut self, other: Self) {
1242        self.bits |= other.bits;
1243    }
1244}
1245
1246impl std::ops::BitXor for AxisValueTableFlags {
1247    type Output = Self;
1248
1249    /// Returns the left flags, but with all the right flags toggled.
1250    #[inline]
1251    fn bitxor(self, other: Self) -> Self {
1252        Self {
1253            bits: self.bits ^ other.bits,
1254        }
1255    }
1256}
1257
1258impl std::ops::BitXorAssign for AxisValueTableFlags {
1259    /// Toggles the set of flags.
1260    #[inline]
1261    fn bitxor_assign(&mut self, other: Self) {
1262        self.bits ^= other.bits;
1263    }
1264}
1265
1266impl std::ops::BitAnd for AxisValueTableFlags {
1267    type Output = Self;
1268
1269    /// Returns the intersection between the two sets of flags.
1270    #[inline]
1271    fn bitand(self, other: Self) -> Self {
1272        Self {
1273            bits: self.bits & other.bits,
1274        }
1275    }
1276}
1277
1278impl std::ops::BitAndAssign for AxisValueTableFlags {
1279    /// Disables all flags disabled in the set.
1280    #[inline]
1281    fn bitand_assign(&mut self, other: Self) {
1282        self.bits &= other.bits;
1283    }
1284}
1285
1286impl std::ops::Sub for AxisValueTableFlags {
1287    type Output = Self;
1288
1289    /// Returns the set difference of the two sets of flags.
1290    #[inline]
1291    fn sub(self, other: Self) -> Self {
1292        Self {
1293            bits: self.bits & !other.bits,
1294        }
1295    }
1296}
1297
1298impl std::ops::SubAssign for AxisValueTableFlags {
1299    /// Disables all flags enabled in the set.
1300    #[inline]
1301    fn sub_assign(&mut self, other: Self) {
1302        self.bits &= !other.bits;
1303    }
1304}
1305
1306impl std::ops::Not for AxisValueTableFlags {
1307    type Output = Self;
1308
1309    /// Returns the complement of this set of flags.
1310    #[inline]
1311    fn not(self) -> Self {
1312        Self { bits: !self.bits } & Self::all()
1313    }
1314}
1315
1316impl std::fmt::Debug for AxisValueTableFlags {
1317    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1318        let members: &[(&str, Self)] = &[
1319            (
1320                "OLDER_SIBLING_FONT_ATTRIBUTE",
1321                Self::OLDER_SIBLING_FONT_ATTRIBUTE,
1322            ),
1323            ("ELIDABLE_AXIS_VALUE_NAME", Self::ELIDABLE_AXIS_VALUE_NAME),
1324        ];
1325        let mut first = true;
1326        for (name, value) in members {
1327            if self.contains(*value) {
1328                if !first {
1329                    f.write_str(" | ")?;
1330                }
1331                first = false;
1332                f.write_str(name)?;
1333            }
1334        }
1335        if first {
1336            f.write_str("(empty)")?;
1337        }
1338        Ok(())
1339    }
1340}
1341
1342impl std::fmt::Binary for AxisValueTableFlags {
1343    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1344        std::fmt::Binary::fmt(&self.bits, f)
1345    }
1346}
1347
1348impl std::fmt::Octal for AxisValueTableFlags {
1349    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1350        std::fmt::Octal::fmt(&self.bits, f)
1351    }
1352}
1353
1354impl std::fmt::LowerHex for AxisValueTableFlags {
1355    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1356        std::fmt::LowerHex::fmt(&self.bits, f)
1357    }
1358}
1359
1360impl std::fmt::UpperHex for AxisValueTableFlags {
1361    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1362        std::fmt::UpperHex::fmt(&self.bits, f)
1363    }
1364}
1365
1366impl font_types::Scalar for AxisValueTableFlags {
1367    type Raw = <u16 as font_types::Scalar>::Raw;
1368    fn to_raw(self) -> Self::Raw {
1369        self.bits().to_raw()
1370    }
1371    fn from_raw(raw: Self::Raw) -> Self {
1372        let t = <u16>::from_raw(raw);
1373        Self::from_bits_truncate(t)
1374    }
1375}
1376
1377#[cfg(feature = "experimental_traverse")]
1378impl<'a> From<AxisValueTableFlags> for FieldType<'a> {
1379    fn from(src: AxisValueTableFlags) -> FieldType<'a> {
1380        src.bits().into()
1381    }
1382}