1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Gpos<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.lookup_list_offset_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 Gpos<'_> {
19 const TAG: Tag = Tag::new(b"GPOS");
21}
22
23impl ReadArgs for Gpos<'_> {
24 type Args = ();
25}
26
27impl<'a> FontRead<'a> for Gpos<'a> {
28 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29 #[allow(clippy::absurd_extreme_comparisons)]
30 if data.len() < Self::MIN_SIZE {
31 return Err(ReadError::OutOfBounds);
32 }
33 Ok(Self { data })
34 }
35}
36
37#[derive(Clone)]
40pub struct Gpos<'a> {
41 data: FontData<'a>,
42}
43
44#[allow(clippy::needless_lifetimes)]
45impl<'a> Gpos<'a> {
46 pub const MIN_SIZE: usize = (MajorMinor::RAW_BYTE_LEN
47 + Offset16::RAW_BYTE_LEN
48 + Offset16::RAW_BYTE_LEN
49 + Offset16::RAW_BYTE_LEN);
50 basic_table_impls!(impl_the_methods);
51
52 pub fn version(&self) -> MajorMinor {
54 let range = self.version_byte_range();
55 self.data.read_at(range.start).ok().unwrap()
56 }
57
58 pub fn script_list_offset(&self) -> Offset16 {
60 let range = self.script_list_offset_byte_range();
61 self.data.read_at(range.start).ok().unwrap()
62 }
63
64 pub fn script_list(&self) -> Result<ScriptList<'a>, ReadError> {
66 let data = self.data;
67 self.script_list_offset().resolve(data)
68 }
69
70 pub fn feature_list_offset(&self) -> Offset16 {
72 let range = self.feature_list_offset_byte_range();
73 self.data.read_at(range.start).ok().unwrap()
74 }
75
76 pub fn feature_list(&self) -> Result<FeatureList<'a>, ReadError> {
78 let data = self.data;
79 self.feature_list_offset().resolve(data)
80 }
81
82 pub fn lookup_list_offset(&self) -> Offset16 {
84 let range = self.lookup_list_offset_byte_range();
85 self.data.read_at(range.start).ok().unwrap()
86 }
87
88 pub fn lookup_list(&self) -> Result<PositionLookupList<'a>, ReadError> {
90 let data = self.data;
91 self.lookup_list_offset().resolve(data)
92 }
93
94 pub fn feature_variations_offset(&self) -> Option<Nullable<Offset32>> {
95 let range = self.feature_variations_offset_byte_range();
96 (!range.is_empty())
97 .then(|| self.data.read_at(range.start).ok())
98 .flatten()
99 }
100
101 pub fn feature_variations(&self) -> Option<Result<FeatureVariations<'a>, ReadError>> {
103 let data = self.data;
104 self.feature_variations_offset().map(|x| x.resolve(data))?
105 }
106
107 pub fn version_byte_range(&self) -> Range<usize> {
108 let start = 0;
109 let end = start + MajorMinor::RAW_BYTE_LEN;
110 start..end
111 }
112
113 pub fn script_list_offset_byte_range(&self) -> Range<usize> {
114 let start = self.version_byte_range().end;
115 let end = start + Offset16::RAW_BYTE_LEN;
116 start..end
117 }
118
119 pub fn feature_list_offset_byte_range(&self) -> Range<usize> {
120 let start = self.script_list_offset_byte_range().end;
121 let end = start + Offset16::RAW_BYTE_LEN;
122 start..end
123 }
124
125 pub fn lookup_list_offset_byte_range(&self) -> Range<usize> {
126 let start = self.feature_list_offset_byte_range().end;
127 let end = start + Offset16::RAW_BYTE_LEN;
128 start..end
129 }
130
131 pub fn feature_variations_offset_byte_range(&self) -> Range<usize> {
132 let start = self.lookup_list_offset_byte_range().end;
133 let end = if self.version().compatible((1u16, 1u16)) {
134 start + Offset32::RAW_BYTE_LEN
135 } else {
136 start
137 };
138 start..end
139 }
140}
141
142const _: () = assert!(FontData::default_data_long_enough(Gpos::MIN_SIZE));
143
144impl Default for Gpos<'_> {
145 fn default() -> Self {
146 Self {
147 data: FontData::default_table_data(),
148 }
149 }
150}
151
152#[cfg(feature = "experimental_traverse")]
153impl<'a> SomeTable<'a> for Gpos<'a> {
154 fn type_name(&self) -> &str {
155 "Gpos"
156 }
157 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
158 match idx {
159 0usize => Some(Field::new("version", self.version())),
160 1usize => Some(Field::new(
161 "script_list_offset",
162 FieldType::offset(self.script_list_offset(), self.script_list()),
163 )),
164 2usize => Some(Field::new(
165 "feature_list_offset",
166 FieldType::offset(self.feature_list_offset(), self.feature_list()),
167 )),
168 3usize => Some(Field::new(
169 "lookup_list_offset",
170 FieldType::offset(self.lookup_list_offset(), self.lookup_list()),
171 )),
172 4usize if self.version().compatible((1u16, 1u16)) => Some(Field::new(
173 "feature_variations_offset",
174 FieldType::offset(
175 self.feature_variations_offset().unwrap(),
176 self.feature_variations(),
177 ),
178 )),
179 _ => None,
180 }
181 }
182}
183
184#[cfg(feature = "experimental_traverse")]
185#[allow(clippy::needless_lifetimes)]
186impl<'a> std::fmt::Debug for Gpos<'a> {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 (self as &dyn SomeTable<'a>).fmt(f)
189 }
190}
191
192pub enum PositionLookup<'a> {
194 Single(Lookup<'a, SinglePos<'a>>),
195 Pair(Lookup<'a, PairPos<'a>>),
196 Cursive(Lookup<'a, CursivePosFormat1<'a>>),
197 MarkToBase(Lookup<'a, MarkBasePosFormat1<'a>>),
198 MarkToLig(Lookup<'a, MarkLigPosFormat1<'a>>),
199 MarkToMark(Lookup<'a, MarkMarkPosFormat1<'a>>),
200 Contextual(Lookup<'a, PositionSequenceContext<'a>>),
201 ChainContextual(Lookup<'a, PositionChainContext<'a>>),
202 Extension(Lookup<'a, ExtensionSubtable<'a>>),
203}
204
205impl Default for PositionLookup<'_> {
206 fn default() -> Self {
207 Self::Single(Default::default())
208 }
209}
210
211impl ReadArgs for PositionLookup<'_> {
212 type Args = ();
213}
214
215impl<'a> FontRead<'a> for PositionLookup<'a> {
216 fn read_with_args(bytes: FontData<'a>, _: ()) -> Result<Self, ReadError> {
217 let discriminant = Lookup::read_discriminant(bytes)?;
218 match discriminant {
219 1 => Ok(PositionLookup::Single(FontRead::read(bytes)?)),
220 2 => Ok(PositionLookup::Pair(FontRead::read(bytes)?)),
221 3 => Ok(PositionLookup::Cursive(FontRead::read(bytes)?)),
222 4 => Ok(PositionLookup::MarkToBase(FontRead::read(bytes)?)),
223 5 => Ok(PositionLookup::MarkToLig(FontRead::read(bytes)?)),
224 6 => Ok(PositionLookup::MarkToMark(FontRead::read(bytes)?)),
225 7 => Ok(PositionLookup::Contextual(FontRead::read(bytes)?)),
226 8 => Ok(PositionLookup::ChainContextual(FontRead::read(bytes)?)),
227 9 => Ok(PositionLookup::Extension(FontRead::read(bytes)?)),
228 other => Err(ReadError::InvalidFormat(other.into())),
229 }
230 }
231}
232
233impl<'a> PositionLookup<'a> {
234 #[allow(dead_code)]
235 pub(crate) fn of_unit_type(&self) -> Lookup<'a, ()> {
239 match self {
240 PositionLookup::Single(inner) => inner.of_unit_type(),
241 PositionLookup::Pair(inner) => inner.of_unit_type(),
242 PositionLookup::Cursive(inner) => inner.of_unit_type(),
243 PositionLookup::MarkToBase(inner) => inner.of_unit_type(),
244 PositionLookup::MarkToLig(inner) => inner.of_unit_type(),
245 PositionLookup::MarkToMark(inner) => inner.of_unit_type(),
246 PositionLookup::Contextual(inner) => inner.of_unit_type(),
247 PositionLookup::ChainContextual(inner) => inner.of_unit_type(),
248 PositionLookup::Extension(inner) => inner.of_unit_type(),
249 }
250 }
251}
252
253#[cfg(feature = "experimental_traverse")]
254impl<'a> PositionLookup<'a> {
255 fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
256 match self {
257 PositionLookup::Single(table) => table,
258 PositionLookup::Pair(table) => table,
259 PositionLookup::Cursive(table) => table,
260 PositionLookup::MarkToBase(table) => table,
261 PositionLookup::MarkToLig(table) => table,
262 PositionLookup::MarkToMark(table) => table,
263 PositionLookup::Contextual(table) => table,
264 PositionLookup::ChainContextual(table) => table,
265 PositionLookup::Extension(table) => table,
266 }
267 }
268}
269
270#[cfg(feature = "experimental_traverse")]
271impl<'a> SomeTable<'a> for PositionLookup<'a> {
272 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
273 self.dyn_inner().get_field(idx)
274 }
275 fn type_name(&self) -> &str {
276 self.dyn_inner().type_name()
277 }
278}
279
280#[cfg(feature = "experimental_traverse")]
281impl std::fmt::Debug for PositionLookup<'_> {
282 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283 self.dyn_inner().fmt(f)
284 }
285}
286
287#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, bytemuck :: AnyBitPattern)]
289#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
290#[repr(transparent)]
291pub struct ValueFormat {
292 bits: u16,
293}
294
295impl ValueFormat {
296 pub const X_PLACEMENT: Self = Self { bits: 0x0001 };
298
299 pub const Y_PLACEMENT: Self = Self { bits: 0x0002 };
301
302 pub const X_ADVANCE: Self = Self { bits: 0x0004 };
304
305 pub const Y_ADVANCE: Self = Self { bits: 0x0008 };
307
308 pub const X_PLACEMENT_DEVICE: Self = Self { bits: 0x0010 };
311
312 pub const Y_PLACEMENT_DEVICE: Self = Self { bits: 0x0020 };
315
316 pub const X_ADVANCE_DEVICE: Self = Self { bits: 0x0040 };
319
320 pub const Y_ADVANCE_DEVICE: Self = Self { bits: 0x0080 };
323}
324
325impl ValueFormat {
326 #[inline]
328 pub const fn empty() -> Self {
329 Self { bits: 0 }
330 }
331
332 #[inline]
334 pub const fn all() -> Self {
335 Self {
336 bits: Self::X_PLACEMENT.bits
337 | Self::Y_PLACEMENT.bits
338 | Self::X_ADVANCE.bits
339 | Self::Y_ADVANCE.bits
340 | Self::X_PLACEMENT_DEVICE.bits
341 | Self::Y_PLACEMENT_DEVICE.bits
342 | Self::X_ADVANCE_DEVICE.bits
343 | Self::Y_ADVANCE_DEVICE.bits,
344 }
345 }
346
347 #[inline]
349 pub const fn bits(&self) -> u16 {
350 self.bits
351 }
352
353 #[inline]
356 pub const fn from_bits(bits: u16) -> Option<Self> {
357 if (bits & !Self::all().bits()) == 0 {
358 Some(Self { bits })
359 } else {
360 None
361 }
362 }
363
364 #[inline]
367 pub const fn from_bits_truncate(bits: u16) -> Self {
368 Self {
369 bits: bits & Self::all().bits,
370 }
371 }
372
373 #[inline]
375 pub const fn is_empty(&self) -> bool {
376 self.bits() == Self::empty().bits()
377 }
378
379 #[inline]
381 pub const fn intersects(&self, other: Self) -> bool {
382 !(Self {
383 bits: self.bits & other.bits,
384 })
385 .is_empty()
386 }
387
388 #[inline]
390 pub const fn contains(&self, other: Self) -> bool {
391 (self.bits & other.bits) == other.bits
392 }
393
394 #[inline]
396 pub fn insert(&mut self, other: Self) {
397 self.bits |= other.bits;
398 }
399
400 #[inline]
402 pub fn remove(&mut self, other: Self) {
403 self.bits &= !other.bits;
404 }
405
406 #[inline]
408 pub fn toggle(&mut self, other: Self) {
409 self.bits ^= other.bits;
410 }
411
412 #[inline]
423 #[must_use]
424 pub const fn intersection(self, other: Self) -> Self {
425 Self {
426 bits: self.bits & other.bits,
427 }
428 }
429
430 #[inline]
441 #[must_use]
442 pub const fn union(self, other: Self) -> Self {
443 Self {
444 bits: self.bits | other.bits,
445 }
446 }
447
448 #[inline]
461 #[must_use]
462 pub const fn difference(self, other: Self) -> Self {
463 Self {
464 bits: self.bits & !other.bits,
465 }
466 }
467}
468
469impl std::ops::BitOr for ValueFormat {
470 type Output = Self;
471
472 #[inline]
474 fn bitor(self, other: ValueFormat) -> Self {
475 Self {
476 bits: self.bits | other.bits,
477 }
478 }
479}
480
481impl std::ops::BitOrAssign for ValueFormat {
482 #[inline]
484 fn bitor_assign(&mut self, other: Self) {
485 self.bits |= other.bits;
486 }
487}
488
489impl std::ops::BitXor for ValueFormat {
490 type Output = Self;
491
492 #[inline]
494 fn bitxor(self, other: Self) -> Self {
495 Self {
496 bits: self.bits ^ other.bits,
497 }
498 }
499}
500
501impl std::ops::BitXorAssign for ValueFormat {
502 #[inline]
504 fn bitxor_assign(&mut self, other: Self) {
505 self.bits ^= other.bits;
506 }
507}
508
509impl std::ops::BitAnd for ValueFormat {
510 type Output = Self;
511
512 #[inline]
514 fn bitand(self, other: Self) -> Self {
515 Self {
516 bits: self.bits & other.bits,
517 }
518 }
519}
520
521impl std::ops::BitAndAssign for ValueFormat {
522 #[inline]
524 fn bitand_assign(&mut self, other: Self) {
525 self.bits &= other.bits;
526 }
527}
528
529impl std::ops::Sub for ValueFormat {
530 type Output = Self;
531
532 #[inline]
534 fn sub(self, other: Self) -> Self {
535 Self {
536 bits: self.bits & !other.bits,
537 }
538 }
539}
540
541impl std::ops::SubAssign for ValueFormat {
542 #[inline]
544 fn sub_assign(&mut self, other: Self) {
545 self.bits &= !other.bits;
546 }
547}
548
549impl std::ops::Not for ValueFormat {
550 type Output = Self;
551
552 #[inline]
554 fn not(self) -> Self {
555 Self { bits: !self.bits } & Self::all()
556 }
557}
558
559impl std::fmt::Debug for ValueFormat {
560 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
561 let members: &[(&str, Self)] = &[
562 ("X_PLACEMENT", Self::X_PLACEMENT),
563 ("Y_PLACEMENT", Self::Y_PLACEMENT),
564 ("X_ADVANCE", Self::X_ADVANCE),
565 ("Y_ADVANCE", Self::Y_ADVANCE),
566 ("X_PLACEMENT_DEVICE", Self::X_PLACEMENT_DEVICE),
567 ("Y_PLACEMENT_DEVICE", Self::Y_PLACEMENT_DEVICE),
568 ("X_ADVANCE_DEVICE", Self::X_ADVANCE_DEVICE),
569 ("Y_ADVANCE_DEVICE", Self::Y_ADVANCE_DEVICE),
570 ];
571 let mut first = true;
572 for (name, value) in members {
573 if self.contains(*value) {
574 if !first {
575 f.write_str(" | ")?;
576 }
577 first = false;
578 f.write_str(name)?;
579 }
580 }
581 if first {
582 f.write_str("(empty)")?;
583 }
584 Ok(())
585 }
586}
587
588impl std::fmt::Binary for ValueFormat {
589 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
590 std::fmt::Binary::fmt(&self.bits, f)
591 }
592}
593
594impl std::fmt::Octal for ValueFormat {
595 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
596 std::fmt::Octal::fmt(&self.bits, f)
597 }
598}
599
600impl std::fmt::LowerHex for ValueFormat {
601 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
602 std::fmt::LowerHex::fmt(&self.bits, f)
603 }
604}
605
606impl std::fmt::UpperHex for ValueFormat {
607 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
608 std::fmt::UpperHex::fmt(&self.bits, f)
609 }
610}
611
612impl font_types::Scalar for ValueFormat {
613 type Raw = <u16 as font_types::Scalar>::Raw;
614 fn to_raw(self) -> Self::Raw {
615 self.bits().to_raw()
616 }
617 fn from_raw(raw: Self::Raw) -> Self {
618 let t = <u16>::from_raw(raw);
619 Self::from_bits_truncate(t)
620 }
621}
622
623#[cfg(feature = "experimental_traverse")]
624impl<'a> From<ValueFormat> for FieldType<'a> {
625 fn from(src: ValueFormat) -> FieldType<'a> {
626 src.bits().into()
627 }
628}
629
630#[derive(Clone)]
633pub enum AnchorTable<'a> {
634 Format1(AnchorFormat1<'a>),
635 Format2(AnchorFormat2<'a>),
636 Format3(AnchorFormat3<'a>),
637}
638
639impl Default for AnchorTable<'_> {
640 fn default() -> Self {
641 Self::Format1(Default::default())
642 }
643}
644
645impl<'a> AnchorTable<'a> {
646 pub fn offset_data(&self) -> FontData<'a> {
648 match self {
649 Self::Format1(item) => item.offset_data(),
650 Self::Format2(item) => item.offset_data(),
651 Self::Format3(item) => item.offset_data(),
652 }
653 }
654
655 pub fn anchor_format(&self) -> u16 {
657 match self {
658 Self::Format1(item) => item.anchor_format(),
659 Self::Format2(item) => item.anchor_format(),
660 Self::Format3(item) => item.anchor_format(),
661 }
662 }
663
664 pub fn x_coordinate(&self) -> i16 {
666 match self {
667 Self::Format1(item) => item.x_coordinate(),
668 Self::Format2(item) => item.x_coordinate(),
669 Self::Format3(item) => item.x_coordinate(),
670 }
671 }
672
673 pub fn y_coordinate(&self) -> i16 {
675 match self {
676 Self::Format1(item) => item.y_coordinate(),
677 Self::Format2(item) => item.y_coordinate(),
678 Self::Format3(item) => item.y_coordinate(),
679 }
680 }
681}
682
683impl ReadArgs for AnchorTable<'_> {
684 type Args = ();
685}
686
687impl<'a> FontRead<'a> for AnchorTable<'a> {
688 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
689 let format: u16 = data.read_at(0usize)?;
690 match format {
691 AnchorFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
692 AnchorFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
693 AnchorFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
694 other => Err(ReadError::InvalidFormat(other.into())),
695 }
696 }
697}
698
699impl<'a> MinByteRange<'a> for AnchorTable<'a> {
700 fn min_byte_range(&self) -> Range<usize> {
701 match self {
702 Self::Format1(item) => item.min_byte_range(),
703 Self::Format2(item) => item.min_byte_range(),
704 Self::Format3(item) => item.min_byte_range(),
705 }
706 }
707 fn min_table_bytes(&self) -> &'a [u8] {
708 match self {
709 Self::Format1(item) => item.min_table_bytes(),
710 Self::Format2(item) => item.min_table_bytes(),
711 Self::Format3(item) => item.min_table_bytes(),
712 }
713 }
714}
715
716#[cfg(feature = "experimental_traverse")]
717impl<'a> AnchorTable<'a> {
718 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
719 match self {
720 Self::Format1(table) => table,
721 Self::Format2(table) => table,
722 Self::Format3(table) => table,
723 }
724 }
725}
726
727#[cfg(feature = "experimental_traverse")]
728impl std::fmt::Debug for AnchorTable<'_> {
729 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
730 self.dyn_inner().fmt(f)
731 }
732}
733
734#[cfg(feature = "experimental_traverse")]
735impl<'a> SomeTable<'a> for AnchorTable<'a> {
736 fn type_name(&self) -> &str {
737 self.dyn_inner().type_name()
738 }
739 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
740 self.dyn_inner().get_field(idx)
741 }
742}
743
744impl Format<u16> for AnchorFormat1<'_> {
745 const FORMAT: u16 = 1;
746}
747
748impl<'a> MinByteRange<'a> for AnchorFormat1<'a> {
749 fn min_byte_range(&self) -> Range<usize> {
750 0..self.y_coordinate_byte_range().end
751 }
752 fn min_table_bytes(&self) -> &'a [u8] {
753 let range = self.min_byte_range();
754 self.data.as_bytes().get(range).unwrap_or_default()
755 }
756}
757
758impl ReadArgs for AnchorFormat1<'_> {
759 type Args = ();
760}
761
762impl<'a> FontRead<'a> for AnchorFormat1<'a> {
763 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
764 #[allow(clippy::absurd_extreme_comparisons)]
765 if data.len() < Self::MIN_SIZE {
766 return Err(ReadError::OutOfBounds);
767 }
768 Ok(Self { data })
769 }
770}
771
772#[derive(Clone)]
774pub struct AnchorFormat1<'a> {
775 data: FontData<'a>,
776}
777
778#[allow(clippy::needless_lifetimes)]
779impl<'a> AnchorFormat1<'a> {
780 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN);
781 basic_table_impls!(impl_the_methods);
782
783 pub fn anchor_format(&self) -> u16 {
785 let range = self.anchor_format_byte_range();
786 self.data.read_at(range.start).ok().unwrap()
787 }
788
789 pub fn x_coordinate(&self) -> i16 {
791 let range = self.x_coordinate_byte_range();
792 self.data.read_at(range.start).ok().unwrap()
793 }
794
795 pub fn y_coordinate(&self) -> i16 {
797 let range = self.y_coordinate_byte_range();
798 self.data.read_at(range.start).ok().unwrap()
799 }
800
801 pub fn anchor_format_byte_range(&self) -> Range<usize> {
802 let start = 0;
803 let end = start + u16::RAW_BYTE_LEN;
804 start..end
805 }
806
807 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
808 let start = self.anchor_format_byte_range().end;
809 let end = start + i16::RAW_BYTE_LEN;
810 start..end
811 }
812
813 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
814 let start = self.x_coordinate_byte_range().end;
815 let end = start + i16::RAW_BYTE_LEN;
816 start..end
817 }
818}
819
820const _: () = assert!(FontData::default_data_long_enough(AnchorFormat1::MIN_SIZE));
821
822impl Default for AnchorFormat1<'_> {
823 fn default() -> Self {
824 Self {
825 data: FontData::default_format_1_u16_table_data(),
826 }
827 }
828}
829
830#[cfg(feature = "experimental_traverse")]
831impl<'a> SomeTable<'a> for AnchorFormat1<'a> {
832 fn type_name(&self) -> &str {
833 "AnchorFormat1"
834 }
835 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
836 match idx {
837 0usize => Some(Field::new("anchor_format", self.anchor_format())),
838 1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
839 2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
840 _ => None,
841 }
842 }
843}
844
845#[cfg(feature = "experimental_traverse")]
846#[allow(clippy::needless_lifetimes)]
847impl<'a> std::fmt::Debug for AnchorFormat1<'a> {
848 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
849 (self as &dyn SomeTable<'a>).fmt(f)
850 }
851}
852
853impl Format<u16> for AnchorFormat2<'_> {
854 const FORMAT: u16 = 2;
855}
856
857impl<'a> MinByteRange<'a> for AnchorFormat2<'a> {
858 fn min_byte_range(&self) -> Range<usize> {
859 0..self.anchor_point_byte_range().end
860 }
861 fn min_table_bytes(&self) -> &'a [u8] {
862 let range = self.min_byte_range();
863 self.data.as_bytes().get(range).unwrap_or_default()
864 }
865}
866
867impl ReadArgs for AnchorFormat2<'_> {
868 type Args = ();
869}
870
871impl<'a> FontRead<'a> for AnchorFormat2<'a> {
872 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
873 #[allow(clippy::absurd_extreme_comparisons)]
874 if data.len() < Self::MIN_SIZE {
875 return Err(ReadError::OutOfBounds);
876 }
877 Ok(Self { data })
878 }
879}
880
881#[derive(Clone)]
883pub struct AnchorFormat2<'a> {
884 data: FontData<'a>,
885}
886
887#[allow(clippy::needless_lifetimes)]
888impl<'a> AnchorFormat2<'a> {
889 pub const MIN_SIZE: usize =
890 (u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
891 basic_table_impls!(impl_the_methods);
892
893 pub fn anchor_format(&self) -> u16 {
895 let range = self.anchor_format_byte_range();
896 self.data.read_at(range.start).ok().unwrap()
897 }
898
899 pub fn x_coordinate(&self) -> i16 {
901 let range = self.x_coordinate_byte_range();
902 self.data.read_at(range.start).ok().unwrap()
903 }
904
905 pub fn y_coordinate(&self) -> i16 {
907 let range = self.y_coordinate_byte_range();
908 self.data.read_at(range.start).ok().unwrap()
909 }
910
911 pub fn anchor_point(&self) -> u16 {
913 let range = self.anchor_point_byte_range();
914 self.data.read_at(range.start).ok().unwrap()
915 }
916
917 pub fn anchor_format_byte_range(&self) -> Range<usize> {
918 let start = 0;
919 let end = start + u16::RAW_BYTE_LEN;
920 start..end
921 }
922
923 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
924 let start = self.anchor_format_byte_range().end;
925 let end = start + i16::RAW_BYTE_LEN;
926 start..end
927 }
928
929 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
930 let start = self.x_coordinate_byte_range().end;
931 let end = start + i16::RAW_BYTE_LEN;
932 start..end
933 }
934
935 pub fn anchor_point_byte_range(&self) -> Range<usize> {
936 let start = self.y_coordinate_byte_range().end;
937 let end = start + u16::RAW_BYTE_LEN;
938 start..end
939 }
940}
941
942#[cfg(feature = "experimental_traverse")]
943impl<'a> SomeTable<'a> for AnchorFormat2<'a> {
944 fn type_name(&self) -> &str {
945 "AnchorFormat2"
946 }
947 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
948 match idx {
949 0usize => Some(Field::new("anchor_format", self.anchor_format())),
950 1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
951 2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
952 3usize => Some(Field::new("anchor_point", self.anchor_point())),
953 _ => None,
954 }
955 }
956}
957
958#[cfg(feature = "experimental_traverse")]
959#[allow(clippy::needless_lifetimes)]
960impl<'a> std::fmt::Debug for AnchorFormat2<'a> {
961 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
962 (self as &dyn SomeTable<'a>).fmt(f)
963 }
964}
965
966impl Format<u16> for AnchorFormat3<'_> {
967 const FORMAT: u16 = 3;
968}
969
970impl<'a> MinByteRange<'a> for AnchorFormat3<'a> {
971 fn min_byte_range(&self) -> Range<usize> {
972 0..self.y_device_offset_byte_range().end
973 }
974 fn min_table_bytes(&self) -> &'a [u8] {
975 let range = self.min_byte_range();
976 self.data.as_bytes().get(range).unwrap_or_default()
977 }
978}
979
980impl ReadArgs for AnchorFormat3<'_> {
981 type Args = ();
982}
983
984impl<'a> FontRead<'a> for AnchorFormat3<'a> {
985 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
986 #[allow(clippy::absurd_extreme_comparisons)]
987 if data.len() < Self::MIN_SIZE {
988 return Err(ReadError::OutOfBounds);
989 }
990 Ok(Self { data })
991 }
992}
993
994#[derive(Clone)]
996pub struct AnchorFormat3<'a> {
997 data: FontData<'a>,
998}
999
1000#[allow(clippy::needless_lifetimes)]
1001impl<'a> AnchorFormat3<'a> {
1002 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1003 + i16::RAW_BYTE_LEN
1004 + i16::RAW_BYTE_LEN
1005 + Offset16::RAW_BYTE_LEN
1006 + Offset16::RAW_BYTE_LEN);
1007 basic_table_impls!(impl_the_methods);
1008
1009 pub fn anchor_format(&self) -> u16 {
1011 let range = self.anchor_format_byte_range();
1012 self.data.read_at(range.start).ok().unwrap()
1013 }
1014
1015 pub fn x_coordinate(&self) -> i16 {
1017 let range = self.x_coordinate_byte_range();
1018 self.data.read_at(range.start).ok().unwrap()
1019 }
1020
1021 pub fn y_coordinate(&self) -> i16 {
1023 let range = self.y_coordinate_byte_range();
1024 self.data.read_at(range.start).ok().unwrap()
1025 }
1026
1027 pub fn x_device_offset(&self) -> Nullable<Offset16> {
1031 let range = self.x_device_offset_byte_range();
1032 self.data.read_at(range.start).ok().unwrap()
1033 }
1034
1035 pub fn x_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1037 let data = self.data;
1038 self.x_device_offset().resolve(data)
1039 }
1040
1041 pub fn y_device_offset(&self) -> Nullable<Offset16> {
1045 let range = self.y_device_offset_byte_range();
1046 self.data.read_at(range.start).ok().unwrap()
1047 }
1048
1049 pub fn y_device(&self) -> Option<Result<DeviceOrVariationIndex<'a>, ReadError>> {
1051 let data = self.data;
1052 self.y_device_offset().resolve(data)
1053 }
1054
1055 pub fn anchor_format_byte_range(&self) -> Range<usize> {
1056 let start = 0;
1057 let end = start + u16::RAW_BYTE_LEN;
1058 start..end
1059 }
1060
1061 pub fn x_coordinate_byte_range(&self) -> Range<usize> {
1062 let start = self.anchor_format_byte_range().end;
1063 let end = start + i16::RAW_BYTE_LEN;
1064 start..end
1065 }
1066
1067 pub fn y_coordinate_byte_range(&self) -> Range<usize> {
1068 let start = self.x_coordinate_byte_range().end;
1069 let end = start + i16::RAW_BYTE_LEN;
1070 start..end
1071 }
1072
1073 pub fn x_device_offset_byte_range(&self) -> Range<usize> {
1074 let start = self.y_coordinate_byte_range().end;
1075 let end = start + Offset16::RAW_BYTE_LEN;
1076 start..end
1077 }
1078
1079 pub fn y_device_offset_byte_range(&self) -> Range<usize> {
1080 let start = self.x_device_offset_byte_range().end;
1081 let end = start + Offset16::RAW_BYTE_LEN;
1082 start..end
1083 }
1084}
1085
1086#[cfg(feature = "experimental_traverse")]
1087impl<'a> SomeTable<'a> for AnchorFormat3<'a> {
1088 fn type_name(&self) -> &str {
1089 "AnchorFormat3"
1090 }
1091 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1092 match idx {
1093 0usize => Some(Field::new("anchor_format", self.anchor_format())),
1094 1usize => Some(Field::new("x_coordinate", self.x_coordinate())),
1095 2usize => Some(Field::new("y_coordinate", self.y_coordinate())),
1096 3usize => Some(Field::new(
1097 "x_device_offset",
1098 FieldType::offset(self.x_device_offset(), self.x_device()),
1099 )),
1100 4usize => Some(Field::new(
1101 "y_device_offset",
1102 FieldType::offset(self.y_device_offset(), self.y_device()),
1103 )),
1104 _ => None,
1105 }
1106 }
1107}
1108
1109#[cfg(feature = "experimental_traverse")]
1110#[allow(clippy::needless_lifetimes)]
1111impl<'a> std::fmt::Debug for AnchorFormat3<'a> {
1112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1113 (self as &dyn SomeTable<'a>).fmt(f)
1114 }
1115}
1116
1117impl<'a> MinByteRange<'a> for MarkArray<'a> {
1118 fn min_byte_range(&self) -> Range<usize> {
1119 0..self.mark_records_byte_range().end
1120 }
1121 fn min_table_bytes(&self) -> &'a [u8] {
1122 let range = self.min_byte_range();
1123 self.data.as_bytes().get(range).unwrap_or_default()
1124 }
1125}
1126
1127impl ReadArgs for MarkArray<'_> {
1128 type Args = ();
1129}
1130
1131impl<'a> FontRead<'a> for MarkArray<'a> {
1132 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1133 #[allow(clippy::absurd_extreme_comparisons)]
1134 if data.len() < Self::MIN_SIZE {
1135 return Err(ReadError::OutOfBounds);
1136 }
1137 Ok(Self { data })
1138 }
1139}
1140
1141#[derive(Clone)]
1143pub struct MarkArray<'a> {
1144 data: FontData<'a>,
1145}
1146
1147#[allow(clippy::needless_lifetimes)]
1148impl<'a> MarkArray<'a> {
1149 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
1150 basic_table_impls!(impl_the_methods);
1151
1152 pub fn mark_count(&self) -> u16 {
1154 let range = self.mark_count_byte_range();
1155 self.data.read_at(range.start).ok().unwrap()
1156 }
1157
1158 pub fn mark_records(&self) -> &'a [MarkRecord] {
1161 let range = self.mark_records_byte_range();
1162 self.data.read_array(range).ok().unwrap_or_default()
1163 }
1164
1165 pub fn mark_count_byte_range(&self) -> Range<usize> {
1166 let start = 0;
1167 let end = start + u16::RAW_BYTE_LEN;
1168 start..end
1169 }
1170
1171 pub fn mark_records_byte_range(&self) -> Range<usize> {
1172 let mark_count = self.mark_count();
1173 let start = self.mark_count_byte_range().end;
1174 let end =
1175 start + (transforms::to_usize(mark_count)).saturating_mul(MarkRecord::RAW_BYTE_LEN);
1176 start..end
1177 }
1178}
1179
1180const _: () = assert!(FontData::default_data_long_enough(MarkArray::MIN_SIZE));
1181
1182impl Default for MarkArray<'_> {
1183 fn default() -> Self {
1184 Self {
1185 data: FontData::default_table_data(),
1186 }
1187 }
1188}
1189
1190#[cfg(feature = "experimental_traverse")]
1191impl<'a> SomeTable<'a> for MarkArray<'a> {
1192 fn type_name(&self) -> &str {
1193 "MarkArray"
1194 }
1195 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1196 match idx {
1197 0usize => Some(Field::new("mark_count", self.mark_count())),
1198 1usize => Some(Field::new(
1199 "mark_records",
1200 traversal::FieldType::array_of_records(
1201 stringify!(MarkRecord),
1202 self.mark_records(),
1203 self.offset_data(),
1204 ),
1205 )),
1206 _ => None,
1207 }
1208 }
1209}
1210
1211#[cfg(feature = "experimental_traverse")]
1212#[allow(clippy::needless_lifetimes)]
1213impl<'a> std::fmt::Debug for MarkArray<'a> {
1214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1215 (self as &dyn SomeTable<'a>).fmt(f)
1216 }
1217}
1218
1219#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1221#[repr(C)]
1222#[repr(packed)]
1223pub struct MarkRecord {
1224 pub mark_class: BigEndian<u16>,
1226 pub mark_anchor_offset: BigEndian<Offset16>,
1228}
1229
1230impl MarkRecord {
1231 pub fn mark_class(&self) -> u16 {
1233 self.mark_class.get()
1234 }
1235
1236 pub fn mark_anchor_offset(&self) -> Offset16 {
1238 self.mark_anchor_offset.get()
1239 }
1240
1241 pub fn mark_anchor<'a>(&self, data: FontData<'a>) -> Result<AnchorTable<'a>, ReadError> {
1246 self.mark_anchor_offset().resolve(data)
1247 }
1248}
1249
1250impl FixedSize for MarkRecord {
1251 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
1252}
1253
1254#[cfg(feature = "experimental_traverse")]
1255impl<'a> SomeRecord<'a> for MarkRecord {
1256 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1257 RecordResolver {
1258 name: "MarkRecord",
1259 get_field: Box::new(move |idx, _data| match idx {
1260 0usize => Some(Field::new("mark_class", self.mark_class())),
1261 1usize => Some(Field::new(
1262 "mark_anchor_offset",
1263 FieldType::offset(self.mark_anchor_offset(), self.mark_anchor(_data)),
1264 )),
1265 _ => None,
1266 }),
1267 data,
1268 }
1269 }
1270}
1271
1272#[derive(Clone)]
1274pub enum SinglePos<'a> {
1275 Format1(SinglePosFormat1<'a>),
1276 Format2(SinglePosFormat2<'a>),
1277}
1278
1279impl Default for SinglePos<'_> {
1280 fn default() -> Self {
1281 Self::Format1(Default::default())
1282 }
1283}
1284
1285impl<'a> SinglePos<'a> {
1286 pub fn offset_data(&self) -> FontData<'a> {
1288 match self {
1289 Self::Format1(item) => item.offset_data(),
1290 Self::Format2(item) => item.offset_data(),
1291 }
1292 }
1293
1294 pub fn pos_format(&self) -> u16 {
1296 match self {
1297 Self::Format1(item) => item.pos_format(),
1298 Self::Format2(item) => item.pos_format(),
1299 }
1300 }
1301
1302 pub fn coverage_offset(&self) -> Offset16 {
1304 match self {
1305 Self::Format1(item) => item.coverage_offset(),
1306 Self::Format2(item) => item.coverage_offset(),
1307 }
1308 }
1309
1310 pub fn value_format(&self) -> ValueFormat {
1312 match self {
1313 Self::Format1(item) => item.value_format(),
1314 Self::Format2(item) => item.value_format(),
1315 }
1316 }
1317}
1318
1319impl ReadArgs for SinglePos<'_> {
1320 type Args = ();
1321}
1322
1323impl<'a> FontRead<'a> for SinglePos<'a> {
1324 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1325 let format: u16 = data.read_at(0usize)?;
1326 match format {
1327 SinglePosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1328 SinglePosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1329 other => Err(ReadError::InvalidFormat(other.into())),
1330 }
1331 }
1332}
1333
1334impl<'a> MinByteRange<'a> for SinglePos<'a> {
1335 fn min_byte_range(&self) -> Range<usize> {
1336 match self {
1337 Self::Format1(item) => item.min_byte_range(),
1338 Self::Format2(item) => item.min_byte_range(),
1339 }
1340 }
1341 fn min_table_bytes(&self) -> &'a [u8] {
1342 match self {
1343 Self::Format1(item) => item.min_table_bytes(),
1344 Self::Format2(item) => item.min_table_bytes(),
1345 }
1346 }
1347}
1348
1349#[cfg(feature = "experimental_traverse")]
1350impl<'a> SinglePos<'a> {
1351 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1352 match self {
1353 Self::Format1(table) => table,
1354 Self::Format2(table) => table,
1355 }
1356 }
1357}
1358
1359#[cfg(feature = "experimental_traverse")]
1360impl std::fmt::Debug for SinglePos<'_> {
1361 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1362 self.dyn_inner().fmt(f)
1363 }
1364}
1365
1366#[cfg(feature = "experimental_traverse")]
1367impl<'a> SomeTable<'a> for SinglePos<'a> {
1368 fn type_name(&self) -> &str {
1369 self.dyn_inner().type_name()
1370 }
1371 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1372 self.dyn_inner().get_field(idx)
1373 }
1374}
1375
1376impl Format<u16> for SinglePosFormat1<'_> {
1377 const FORMAT: u16 = 1;
1378}
1379
1380impl<'a> MinByteRange<'a> for SinglePosFormat1<'a> {
1381 fn min_byte_range(&self) -> Range<usize> {
1382 0..self.value_record_byte_range().end
1383 }
1384 fn min_table_bytes(&self) -> &'a [u8] {
1385 let range = self.min_byte_range();
1386 self.data.as_bytes().get(range).unwrap_or_default()
1387 }
1388}
1389
1390impl ReadArgs for SinglePosFormat1<'_> {
1391 type Args = ();
1392}
1393
1394impl<'a> FontRead<'a> for SinglePosFormat1<'a> {
1395 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1396 #[allow(clippy::absurd_extreme_comparisons)]
1397 if data.len() < Self::MIN_SIZE {
1398 return Err(ReadError::OutOfBounds);
1399 }
1400 Ok(Self { data })
1401 }
1402}
1403
1404#[derive(Clone)]
1406pub struct SinglePosFormat1<'a> {
1407 data: FontData<'a>,
1408}
1409
1410#[allow(clippy::needless_lifetimes)]
1411impl<'a> SinglePosFormat1<'a> {
1412 pub const MIN_SIZE: usize =
1413 (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + ValueFormat::RAW_BYTE_LEN);
1414 basic_table_impls!(impl_the_methods);
1415
1416 pub fn pos_format(&self) -> u16 {
1418 let range = self.pos_format_byte_range();
1419 self.data.read_at(range.start).ok().unwrap()
1420 }
1421
1422 pub fn coverage_offset(&self) -> Offset16 {
1424 let range = self.coverage_offset_byte_range();
1425 self.data.read_at(range.start).ok().unwrap()
1426 }
1427
1428 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1430 let data = self.data;
1431 self.coverage_offset().resolve(data)
1432 }
1433
1434 pub fn value_format(&self) -> ValueFormat {
1436 let range = self.value_format_byte_range();
1437 self.data.read_at(range.start).ok().unwrap()
1438 }
1439
1440 pub fn value_record(&self) -> ValueRecord {
1443 let range = self.value_record_byte_range();
1444 self.data
1445 .read_with_args(range, self.value_format())
1446 .unwrap_or_default()
1447 }
1448
1449 pub fn pos_format_byte_range(&self) -> Range<usize> {
1450 let start = 0;
1451 let end = start + u16::RAW_BYTE_LEN;
1452 start..end
1453 }
1454
1455 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1456 let start = self.pos_format_byte_range().end;
1457 let end = start + Offset16::RAW_BYTE_LEN;
1458 start..end
1459 }
1460
1461 pub fn value_format_byte_range(&self) -> Range<usize> {
1462 let start = self.coverage_offset_byte_range().end;
1463 let end = start + ValueFormat::RAW_BYTE_LEN;
1464 start..end
1465 }
1466
1467 pub fn value_record_byte_range(&self) -> Range<usize> {
1468 let start = self.value_format_byte_range().end;
1469 let end =
1470 start + <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0);
1471 start..end
1472 }
1473}
1474
1475const _: () = assert!(FontData::default_data_long_enough(
1476 SinglePosFormat1::MIN_SIZE
1477));
1478
1479impl Default for SinglePosFormat1<'_> {
1480 fn default() -> Self {
1481 Self {
1482 data: FontData::default_format_1_u16_table_data(),
1483 }
1484 }
1485}
1486
1487#[cfg(feature = "experimental_traverse")]
1488impl<'a> SomeTable<'a> for SinglePosFormat1<'a> {
1489 fn type_name(&self) -> &str {
1490 "SinglePosFormat1"
1491 }
1492 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1493 match idx {
1494 0usize => Some(Field::new("pos_format", self.pos_format())),
1495 1usize => Some(Field::new(
1496 "coverage_offset",
1497 FieldType::offset(self.coverage_offset(), self.coverage()),
1498 )),
1499 2usize => Some(Field::new("value_format", self.value_format())),
1500 3usize => Some(Field::new(
1501 "value_record",
1502 self.value_record().traversal_type(self.offset_data()),
1503 )),
1504 _ => None,
1505 }
1506 }
1507}
1508
1509#[cfg(feature = "experimental_traverse")]
1510#[allow(clippy::needless_lifetimes)]
1511impl<'a> std::fmt::Debug for SinglePosFormat1<'a> {
1512 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1513 (self as &dyn SomeTable<'a>).fmt(f)
1514 }
1515}
1516
1517impl Format<u16> for SinglePosFormat2<'_> {
1518 const FORMAT: u16 = 2;
1519}
1520
1521impl<'a> MinByteRange<'a> for SinglePosFormat2<'a> {
1522 fn min_byte_range(&self) -> Range<usize> {
1523 0..self.value_records_byte_range().end
1524 }
1525 fn min_table_bytes(&self) -> &'a [u8] {
1526 let range = self.min_byte_range();
1527 self.data.as_bytes().get(range).unwrap_or_default()
1528 }
1529}
1530
1531impl ReadArgs for SinglePosFormat2<'_> {
1532 type Args = ();
1533}
1534
1535impl<'a> FontRead<'a> for SinglePosFormat2<'a> {
1536 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1537 #[allow(clippy::absurd_extreme_comparisons)]
1538 if data.len() < Self::MIN_SIZE {
1539 return Err(ReadError::OutOfBounds);
1540 }
1541 Ok(Self { data })
1542 }
1543}
1544
1545#[derive(Clone)]
1547pub struct SinglePosFormat2<'a> {
1548 data: FontData<'a>,
1549}
1550
1551#[allow(clippy::needless_lifetimes)]
1552impl<'a> SinglePosFormat2<'a> {
1553 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1554 + Offset16::RAW_BYTE_LEN
1555 + ValueFormat::RAW_BYTE_LEN
1556 + u16::RAW_BYTE_LEN);
1557 basic_table_impls!(impl_the_methods);
1558
1559 pub fn pos_format(&self) -> u16 {
1561 let range = self.pos_format_byte_range();
1562 self.data.read_at(range.start).ok().unwrap()
1563 }
1564
1565 pub fn coverage_offset(&self) -> Offset16 {
1567 let range = self.coverage_offset_byte_range();
1568 self.data.read_at(range.start).ok().unwrap()
1569 }
1570
1571 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1573 let data = self.data;
1574 self.coverage_offset().resolve(data)
1575 }
1576
1577 pub fn value_format(&self) -> ValueFormat {
1579 let range = self.value_format_byte_range();
1580 self.data.read_at(range.start).ok().unwrap()
1581 }
1582
1583 pub fn value_count(&self) -> u16 {
1586 let range = self.value_count_byte_range();
1587 self.data.read_at(range.start).ok().unwrap()
1588 }
1589
1590 pub fn value_records(&self) -> ComputedArray<'a, ValueRecord> {
1592 let range = self.value_records_byte_range();
1593 self.data
1594 .read_with_args(range, self.value_format())
1595 .unwrap_or_default()
1596 }
1597
1598 pub fn pos_format_byte_range(&self) -> Range<usize> {
1599 let start = 0;
1600 let end = start + u16::RAW_BYTE_LEN;
1601 start..end
1602 }
1603
1604 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1605 let start = self.pos_format_byte_range().end;
1606 let end = start + Offset16::RAW_BYTE_LEN;
1607 start..end
1608 }
1609
1610 pub fn value_format_byte_range(&self) -> Range<usize> {
1611 let start = self.coverage_offset_byte_range().end;
1612 let end = start + ValueFormat::RAW_BYTE_LEN;
1613 start..end
1614 }
1615
1616 pub fn value_count_byte_range(&self) -> Range<usize> {
1617 let start = self.value_format_byte_range().end;
1618 let end = start + u16::RAW_BYTE_LEN;
1619 start..end
1620 }
1621
1622 pub fn value_records_byte_range(&self) -> Range<usize> {
1623 let value_count = self.value_count();
1624 let start = self.value_count_byte_range().end;
1625 let end = start
1626 + (transforms::to_usize(value_count)).saturating_mul(
1627 <ValueRecord as ComputeSize>::compute_size(self.value_format()).unwrap_or(0),
1628 );
1629 start..end
1630 }
1631}
1632
1633#[cfg(feature = "experimental_traverse")]
1634impl<'a> SomeTable<'a> for SinglePosFormat2<'a> {
1635 fn type_name(&self) -> &str {
1636 "SinglePosFormat2"
1637 }
1638 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1639 match idx {
1640 0usize => Some(Field::new("pos_format", self.pos_format())),
1641 1usize => Some(Field::new(
1642 "coverage_offset",
1643 FieldType::offset(self.coverage_offset(), self.coverage()),
1644 )),
1645 2usize => Some(Field::new("value_format", self.value_format())),
1646 3usize => Some(Field::new("value_count", self.value_count())),
1647 4usize => Some(Field::new(
1648 "value_records",
1649 traversal::FieldType::computed_array(
1650 "ValueRecord",
1651 self.value_records(),
1652 self.offset_data(),
1653 ),
1654 )),
1655 _ => None,
1656 }
1657 }
1658}
1659
1660#[cfg(feature = "experimental_traverse")]
1661#[allow(clippy::needless_lifetimes)]
1662impl<'a> std::fmt::Debug for SinglePosFormat2<'a> {
1663 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1664 (self as &dyn SomeTable<'a>).fmt(f)
1665 }
1666}
1667
1668#[derive(Clone)]
1670pub enum PairPos<'a> {
1671 Format1(PairPosFormat1<'a>),
1672 Format2(PairPosFormat2<'a>),
1673}
1674
1675impl Default for PairPos<'_> {
1676 fn default() -> Self {
1677 Self::Format1(Default::default())
1678 }
1679}
1680
1681impl<'a> PairPos<'a> {
1682 pub fn offset_data(&self) -> FontData<'a> {
1684 match self {
1685 Self::Format1(item) => item.offset_data(),
1686 Self::Format2(item) => item.offset_data(),
1687 }
1688 }
1689
1690 pub fn pos_format(&self) -> u16 {
1692 match self {
1693 Self::Format1(item) => item.pos_format(),
1694 Self::Format2(item) => item.pos_format(),
1695 }
1696 }
1697
1698 pub fn coverage_offset(&self) -> Offset16 {
1700 match self {
1701 Self::Format1(item) => item.coverage_offset(),
1702 Self::Format2(item) => item.coverage_offset(),
1703 }
1704 }
1705
1706 pub fn value_format1(&self) -> ValueFormat {
1709 match self {
1710 Self::Format1(item) => item.value_format1(),
1711 Self::Format2(item) => item.value_format1(),
1712 }
1713 }
1714
1715 pub fn value_format2(&self) -> ValueFormat {
1718 match self {
1719 Self::Format1(item) => item.value_format2(),
1720 Self::Format2(item) => item.value_format2(),
1721 }
1722 }
1723}
1724
1725impl ReadArgs for PairPos<'_> {
1726 type Args = ();
1727}
1728
1729impl<'a> FontRead<'a> for PairPos<'a> {
1730 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1731 let format: u16 = data.read_at(0usize)?;
1732 match format {
1733 PairPosFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
1734 PairPosFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
1735 other => Err(ReadError::InvalidFormat(other.into())),
1736 }
1737 }
1738}
1739
1740impl<'a> MinByteRange<'a> for PairPos<'a> {
1741 fn min_byte_range(&self) -> Range<usize> {
1742 match self {
1743 Self::Format1(item) => item.min_byte_range(),
1744 Self::Format2(item) => item.min_byte_range(),
1745 }
1746 }
1747 fn min_table_bytes(&self) -> &'a [u8] {
1748 match self {
1749 Self::Format1(item) => item.min_table_bytes(),
1750 Self::Format2(item) => item.min_table_bytes(),
1751 }
1752 }
1753}
1754
1755#[cfg(feature = "experimental_traverse")]
1756impl<'a> PairPos<'a> {
1757 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
1758 match self {
1759 Self::Format1(table) => table,
1760 Self::Format2(table) => table,
1761 }
1762 }
1763}
1764
1765#[cfg(feature = "experimental_traverse")]
1766impl std::fmt::Debug for PairPos<'_> {
1767 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1768 self.dyn_inner().fmt(f)
1769 }
1770}
1771
1772#[cfg(feature = "experimental_traverse")]
1773impl<'a> SomeTable<'a> for PairPos<'a> {
1774 fn type_name(&self) -> &str {
1775 self.dyn_inner().type_name()
1776 }
1777 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1778 self.dyn_inner().get_field(idx)
1779 }
1780}
1781
1782impl Format<u16> for PairPosFormat1<'_> {
1783 const FORMAT: u16 = 1;
1784}
1785
1786impl<'a> MinByteRange<'a> for PairPosFormat1<'a> {
1787 fn min_byte_range(&self) -> Range<usize> {
1788 0..self.pair_set_offsets_byte_range().end
1789 }
1790 fn min_table_bytes(&self) -> &'a [u8] {
1791 let range = self.min_byte_range();
1792 self.data.as_bytes().get(range).unwrap_or_default()
1793 }
1794}
1795
1796impl ReadArgs for PairPosFormat1<'_> {
1797 type Args = ();
1798}
1799
1800impl<'a> FontRead<'a> for PairPosFormat1<'a> {
1801 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1802 #[allow(clippy::absurd_extreme_comparisons)]
1803 if data.len() < Self::MIN_SIZE {
1804 return Err(ReadError::OutOfBounds);
1805 }
1806 Ok(Self { data })
1807 }
1808}
1809
1810#[derive(Clone)]
1812pub struct PairPosFormat1<'a> {
1813 data: FontData<'a>,
1814}
1815
1816#[allow(clippy::needless_lifetimes)]
1817impl<'a> PairPosFormat1<'a> {
1818 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1819 + Offset16::RAW_BYTE_LEN
1820 + ValueFormat::RAW_BYTE_LEN
1821 + ValueFormat::RAW_BYTE_LEN
1822 + u16::RAW_BYTE_LEN);
1823 basic_table_impls!(impl_the_methods);
1824
1825 pub fn pos_format(&self) -> u16 {
1827 let range = self.pos_format_byte_range();
1828 self.data.read_at(range.start).ok().unwrap()
1829 }
1830
1831 pub fn coverage_offset(&self) -> Offset16 {
1833 let range = self.coverage_offset_byte_range();
1834 self.data.read_at(range.start).ok().unwrap()
1835 }
1836
1837 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
1839 let data = self.data;
1840 self.coverage_offset().resolve(data)
1841 }
1842
1843 pub fn value_format1(&self) -> ValueFormat {
1846 let range = self.value_format1_byte_range();
1847 self.data.read_at(range.start).ok().unwrap()
1848 }
1849
1850 pub fn value_format2(&self) -> ValueFormat {
1853 let range = self.value_format2_byte_range();
1854 self.data.read_at(range.start).ok().unwrap()
1855 }
1856
1857 pub fn pair_set_count(&self) -> u16 {
1859 let range = self.pair_set_count_byte_range();
1860 self.data.read_at(range.start).ok().unwrap()
1861 }
1862
1863 pub fn pair_set_offsets(&self) -> &'a [BigEndian<Offset16>] {
1866 let range = self.pair_set_offsets_byte_range();
1867 self.data.read_array(range).ok().unwrap_or_default()
1868 }
1869
1870 pub fn pair_sets(&self) -> ArrayOfOffsets<'a, PairSet<'a>, Offset16> {
1872 let data = self.data;
1873 let offsets = self.pair_set_offsets();
1874 let args = (self.value_format1(), self.value_format2());
1875 ArrayOfOffsets::new(offsets, data, args)
1876 }
1877
1878 pub fn pos_format_byte_range(&self) -> Range<usize> {
1879 let start = 0;
1880 let end = start + u16::RAW_BYTE_LEN;
1881 start..end
1882 }
1883
1884 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
1885 let start = self.pos_format_byte_range().end;
1886 let end = start + Offset16::RAW_BYTE_LEN;
1887 start..end
1888 }
1889
1890 pub fn value_format1_byte_range(&self) -> Range<usize> {
1891 let start = self.coverage_offset_byte_range().end;
1892 let end = start + ValueFormat::RAW_BYTE_LEN;
1893 start..end
1894 }
1895
1896 pub fn value_format2_byte_range(&self) -> Range<usize> {
1897 let start = self.value_format1_byte_range().end;
1898 let end = start + ValueFormat::RAW_BYTE_LEN;
1899 start..end
1900 }
1901
1902 pub fn pair_set_count_byte_range(&self) -> Range<usize> {
1903 let start = self.value_format2_byte_range().end;
1904 let end = start + u16::RAW_BYTE_LEN;
1905 start..end
1906 }
1907
1908 pub fn pair_set_offsets_byte_range(&self) -> Range<usize> {
1909 let pair_set_count = self.pair_set_count();
1910 let start = self.pair_set_count_byte_range().end;
1911 let end =
1912 start + (transforms::to_usize(pair_set_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
1913 start..end
1914 }
1915}
1916
1917const _: () = assert!(FontData::default_data_long_enough(PairPosFormat1::MIN_SIZE));
1918
1919impl Default for PairPosFormat1<'_> {
1920 fn default() -> Self {
1921 Self {
1922 data: FontData::default_format_1_u16_table_data(),
1923 }
1924 }
1925}
1926
1927#[cfg(feature = "experimental_traverse")]
1928impl<'a> SomeTable<'a> for PairPosFormat1<'a> {
1929 fn type_name(&self) -> &str {
1930 "PairPosFormat1"
1931 }
1932 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1933 match idx {
1934 0usize => Some(Field::new("pos_format", self.pos_format())),
1935 1usize => Some(Field::new(
1936 "coverage_offset",
1937 FieldType::offset(self.coverage_offset(), self.coverage()),
1938 )),
1939 2usize => Some(Field::new("value_format1", self.value_format1())),
1940 3usize => Some(Field::new("value_format2", self.value_format2())),
1941 4usize => Some(Field::new("pair_set_count", self.pair_set_count())),
1942 5usize => Some(Field::new(
1943 "pair_set_offsets",
1944 FieldType::from(self.pair_sets()),
1945 )),
1946 _ => None,
1947 }
1948 }
1949}
1950
1951#[cfg(feature = "experimental_traverse")]
1952#[allow(clippy::needless_lifetimes)]
1953impl<'a> std::fmt::Debug for PairPosFormat1<'a> {
1954 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1955 (self as &dyn SomeTable<'a>).fmt(f)
1956 }
1957}
1958
1959impl<'a> MinByteRange<'a> for PairSet<'a> {
1960 fn min_byte_range(&self) -> Range<usize> {
1961 0..self.pair_value_records_byte_range().end
1962 }
1963 fn min_table_bytes(&self) -> &'a [u8] {
1964 let range = self.min_byte_range();
1965 self.data.as_bytes().get(range).unwrap_or_default()
1966 }
1967}
1968
1969impl ReadArgs for PairSet<'_> {
1970 type Args = (ValueFormat, ValueFormat);
1971}
1972
1973impl<'a> FontRead<'a> for PairSet<'a> {
1974 fn read_with_args(
1975 data: FontData<'a>,
1976 args: (ValueFormat, ValueFormat),
1977 ) -> Result<Self, ReadError> {
1978 let (value_format1, value_format2) = args;
1979
1980 #[allow(clippy::absurd_extreme_comparisons)]
1981 if data.len() < Self::MIN_SIZE {
1982 return Err(ReadError::OutOfBounds);
1983 }
1984 Ok(Self {
1985 data,
1986 value_format1,
1987 value_format2,
1988 })
1989 }
1990}
1991
1992impl<'a> PairSet<'a> {
1993 pub fn read(
1998 data: FontData<'a>,
1999 value_format1: ValueFormat,
2000 value_format2: ValueFormat,
2001 ) -> Result<Self, ReadError> {
2002 let args = (value_format1, value_format2);
2003 Self::read_with_args(data, args)
2004 }
2005}
2006
2007#[derive(Clone)]
2009pub struct PairSet<'a> {
2010 data: FontData<'a>,
2011 value_format1: ValueFormat,
2012 value_format2: ValueFormat,
2013}
2014
2015#[allow(clippy::needless_lifetimes)]
2016impl<'a> PairSet<'a> {
2017 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
2018 basic_table_impls!(impl_the_methods);
2019
2020 pub fn pair_value_count(&self) -> u16 {
2022 let range = self.pair_value_count_byte_range();
2023 self.data.read_at(range.start).ok().unwrap()
2024 }
2025
2026 pub fn pair_value_records(&self) -> ComputedArray<'a, PairValueRecord> {
2029 let range = self.pair_value_records_byte_range();
2030 self.data
2031 .read_with_args(range, (self.value_format1(), self.value_format2()))
2032 .unwrap_or_default()
2033 }
2034
2035 pub(crate) fn value_format1(&self) -> ValueFormat {
2036 self.value_format1
2037 }
2038
2039 pub(crate) fn value_format2(&self) -> ValueFormat {
2040 self.value_format2
2041 }
2042
2043 pub fn pair_value_count_byte_range(&self) -> Range<usize> {
2044 let start = 0;
2045 let end = start + u16::RAW_BYTE_LEN;
2046 start..end
2047 }
2048
2049 pub fn pair_value_records_byte_range(&self) -> Range<usize> {
2050 let pair_value_count = self.pair_value_count();
2051 let start = self.pair_value_count_byte_range().end;
2052 let end = start
2053 + (transforms::to_usize(pair_value_count)).saturating_mul(
2054 <PairValueRecord as ComputeSize>::compute_size((
2055 self.value_format1(),
2056 self.value_format2(),
2057 ))
2058 .unwrap_or(0),
2059 );
2060 start..end
2061 }
2062}
2063
2064const _: () = assert!(FontData::default_data_long_enough(PairSet::MIN_SIZE));
2065
2066impl Default for PairSet<'_> {
2067 fn default() -> Self {
2068 Self {
2069 data: FontData::default_table_data(),
2070 value_format1: Default::default(),
2071 value_format2: Default::default(),
2072 }
2073 }
2074}
2075
2076#[cfg(feature = "experimental_traverse")]
2077impl<'a> SomeTable<'a> for PairSet<'a> {
2078 fn type_name(&self) -> &str {
2079 "PairSet"
2080 }
2081 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2082 match idx {
2083 0usize => Some(Field::new("pair_value_count", self.pair_value_count())),
2084 1usize => Some(Field::new(
2085 "pair_value_records",
2086 traversal::FieldType::computed_array(
2087 "PairValueRecord",
2088 self.pair_value_records(),
2089 self.offset_data(),
2090 ),
2091 )),
2092 _ => None,
2093 }
2094 }
2095}
2096
2097#[cfg(feature = "experimental_traverse")]
2098#[allow(clippy::needless_lifetimes)]
2099impl<'a> std::fmt::Debug for PairSet<'a> {
2100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2101 (self as &dyn SomeTable<'a>).fmt(f)
2102 }
2103}
2104
2105#[derive(Clone, Debug)]
2107pub struct PairValueRecord {
2108 pub second_glyph: BigEndian<GlyphId16>,
2111 pub value_record1: ValueRecord,
2113 pub value_record2: ValueRecord,
2115}
2116
2117impl PairValueRecord {
2118 pub fn second_glyph(&self) -> GlyphId16 {
2121 self.second_glyph.get()
2122 }
2123
2124 pub fn value_record1(&self) -> &ValueRecord {
2126 &self.value_record1
2127 }
2128
2129 pub fn value_record2(&self) -> &ValueRecord {
2131 &self.value_record2
2132 }
2133}
2134
2135impl ReadArgs for PairValueRecord {
2136 type Args = (ValueFormat, ValueFormat);
2137}
2138
2139impl ComputeSize for PairValueRecord {
2140 #[allow(clippy::needless_question_mark)]
2141 fn compute_size(args: (ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2142 let (value_format1, value_format2) = args;
2143 let mut result = 0usize;
2144 result = result
2145 .checked_add(GlyphId16::RAW_BYTE_LEN)
2146 .ok_or(ReadError::OutOfBounds)?;
2147 result = result
2148 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format1).unwrap_or(0))
2149 .ok_or(ReadError::OutOfBounds)?;
2150 result = result
2151 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format2).unwrap_or(0))
2152 .ok_or(ReadError::OutOfBounds)?;
2153 Ok(result)
2154 }
2155}
2156
2157impl<'a> FontRead<'a> for PairValueRecord {
2158 fn read_with_args(
2159 data: FontData<'a>,
2160 args: (ValueFormat, ValueFormat),
2161 ) -> Result<Self, ReadError> {
2162 let mut cursor = data.cursor();
2163 let (value_format1, value_format2) = args;
2164 Ok(Self {
2165 second_glyph: cursor.read_be()?,
2166 value_record1: cursor.read_with_args(value_format1)?,
2167 value_record2: cursor.read_with_args(value_format2)?,
2168 })
2169 }
2170}
2171
2172#[allow(clippy::needless_lifetimes)]
2173impl<'a> PairValueRecord {
2174 pub fn read(
2179 data: FontData<'a>,
2180 value_format1: ValueFormat,
2181 value_format2: ValueFormat,
2182 ) -> Result<Self, ReadError> {
2183 let args = (value_format1, value_format2);
2184 Self::read_with_args(data, args)
2185 }
2186}
2187
2188#[cfg(feature = "experimental_traverse")]
2189impl<'a> SomeRecord<'a> for PairValueRecord {
2190 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2191 RecordResolver {
2192 name: "PairValueRecord",
2193 get_field: Box::new(move |idx, _data| match idx {
2194 0usize => Some(Field::new("second_glyph", self.second_glyph())),
2195 1usize => Some(Field::new(
2196 "value_record1",
2197 self.value_record1().traversal_type(_data),
2198 )),
2199 2usize => Some(Field::new(
2200 "value_record2",
2201 self.value_record2().traversal_type(_data),
2202 )),
2203 _ => None,
2204 }),
2205 data,
2206 }
2207 }
2208}
2209
2210impl Format<u16> for PairPosFormat2<'_> {
2211 const FORMAT: u16 = 2;
2212}
2213
2214impl<'a> MinByteRange<'a> for PairPosFormat2<'a> {
2215 fn min_byte_range(&self) -> Range<usize> {
2216 0..self.class1_records_byte_range().end
2217 }
2218 fn min_table_bytes(&self) -> &'a [u8] {
2219 let range = self.min_byte_range();
2220 self.data.as_bytes().get(range).unwrap_or_default()
2221 }
2222}
2223
2224impl ReadArgs for PairPosFormat2<'_> {
2225 type Args = ();
2226}
2227
2228impl<'a> FontRead<'a> for PairPosFormat2<'a> {
2229 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2230 #[allow(clippy::absurd_extreme_comparisons)]
2231 if data.len() < Self::MIN_SIZE {
2232 return Err(ReadError::OutOfBounds);
2233 }
2234 Ok(Self { data })
2235 }
2236}
2237
2238#[derive(Clone)]
2240pub struct PairPosFormat2<'a> {
2241 data: FontData<'a>,
2242}
2243
2244#[allow(clippy::needless_lifetimes)]
2245impl<'a> PairPosFormat2<'a> {
2246 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2247 + Offset16::RAW_BYTE_LEN
2248 + ValueFormat::RAW_BYTE_LEN
2249 + ValueFormat::RAW_BYTE_LEN
2250 + Offset16::RAW_BYTE_LEN
2251 + Offset16::RAW_BYTE_LEN
2252 + u16::RAW_BYTE_LEN
2253 + u16::RAW_BYTE_LEN);
2254 basic_table_impls!(impl_the_methods);
2255
2256 pub fn pos_format(&self) -> u16 {
2258 let range = self.pos_format_byte_range();
2259 self.data.read_at(range.start).ok().unwrap()
2260 }
2261
2262 pub fn coverage_offset(&self) -> Offset16 {
2264 let range = self.coverage_offset_byte_range();
2265 self.data.read_at(range.start).ok().unwrap()
2266 }
2267
2268 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2270 let data = self.data;
2271 self.coverage_offset().resolve(data)
2272 }
2273
2274 pub fn value_format1(&self) -> ValueFormat {
2277 let range = self.value_format1_byte_range();
2278 self.data.read_at(range.start).ok().unwrap()
2279 }
2280
2281 pub fn value_format2(&self) -> ValueFormat {
2284 let range = self.value_format2_byte_range();
2285 self.data.read_at(range.start).ok().unwrap()
2286 }
2287
2288 pub fn class_def1_offset(&self) -> Offset16 {
2291 let range = self.class_def1_offset_byte_range();
2292 self.data.read_at(range.start).ok().unwrap()
2293 }
2294
2295 pub fn class_def1(&self) -> Result<ClassDef<'a>, ReadError> {
2297 let data = self.data;
2298 self.class_def1_offset().resolve(data)
2299 }
2300
2301 pub fn class_def2_offset(&self) -> Offset16 {
2304 let range = self.class_def2_offset_byte_range();
2305 self.data.read_at(range.start).ok().unwrap()
2306 }
2307
2308 pub fn class_def2(&self) -> Result<ClassDef<'a>, ReadError> {
2310 let data = self.data;
2311 self.class_def2_offset().resolve(data)
2312 }
2313
2314 pub fn class1_count(&self) -> u16 {
2316 let range = self.class1_count_byte_range();
2317 self.data.read_at(range.start).ok().unwrap()
2318 }
2319
2320 pub fn class2_count(&self) -> u16 {
2322 let range = self.class2_count_byte_range();
2323 self.data.read_at(range.start).ok().unwrap()
2324 }
2325
2326 pub fn class1_records(&self) -> ComputedArray<'a, Class1Record<'a>> {
2328 let range = self.class1_records_byte_range();
2329 self.data
2330 .read_with_args(
2331 range,
2332 (
2333 self.class2_count(),
2334 self.value_format1(),
2335 self.value_format2(),
2336 ),
2337 )
2338 .unwrap_or_default()
2339 }
2340
2341 pub fn pos_format_byte_range(&self) -> Range<usize> {
2342 let start = 0;
2343 let end = start + u16::RAW_BYTE_LEN;
2344 start..end
2345 }
2346
2347 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2348 let start = self.pos_format_byte_range().end;
2349 let end = start + Offset16::RAW_BYTE_LEN;
2350 start..end
2351 }
2352
2353 pub fn value_format1_byte_range(&self) -> Range<usize> {
2354 let start = self.coverage_offset_byte_range().end;
2355 let end = start + ValueFormat::RAW_BYTE_LEN;
2356 start..end
2357 }
2358
2359 pub fn value_format2_byte_range(&self) -> Range<usize> {
2360 let start = self.value_format1_byte_range().end;
2361 let end = start + ValueFormat::RAW_BYTE_LEN;
2362 start..end
2363 }
2364
2365 pub fn class_def1_offset_byte_range(&self) -> Range<usize> {
2366 let start = self.value_format2_byte_range().end;
2367 let end = start + Offset16::RAW_BYTE_LEN;
2368 start..end
2369 }
2370
2371 pub fn class_def2_offset_byte_range(&self) -> Range<usize> {
2372 let start = self.class_def1_offset_byte_range().end;
2373 let end = start + Offset16::RAW_BYTE_LEN;
2374 start..end
2375 }
2376
2377 pub fn class1_count_byte_range(&self) -> Range<usize> {
2378 let start = self.class_def2_offset_byte_range().end;
2379 let end = start + u16::RAW_BYTE_LEN;
2380 start..end
2381 }
2382
2383 pub fn class2_count_byte_range(&self) -> Range<usize> {
2384 let start = self.class1_count_byte_range().end;
2385 let end = start + u16::RAW_BYTE_LEN;
2386 start..end
2387 }
2388
2389 pub fn class1_records_byte_range(&self) -> Range<usize> {
2390 let class1_count = self.class1_count();
2391 let start = self.class2_count_byte_range().end;
2392 let end = start
2393 + (transforms::to_usize(class1_count)).saturating_mul(
2394 <Class1Record as ComputeSize>::compute_size((
2395 self.class2_count(),
2396 self.value_format1(),
2397 self.value_format2(),
2398 ))
2399 .unwrap_or(0),
2400 );
2401 start..end
2402 }
2403}
2404
2405#[cfg(feature = "experimental_traverse")]
2406impl<'a> SomeTable<'a> for PairPosFormat2<'a> {
2407 fn type_name(&self) -> &str {
2408 "PairPosFormat2"
2409 }
2410 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2411 match idx {
2412 0usize => Some(Field::new("pos_format", self.pos_format())),
2413 1usize => Some(Field::new(
2414 "coverage_offset",
2415 FieldType::offset(self.coverage_offset(), self.coverage()),
2416 )),
2417 2usize => Some(Field::new("value_format1", self.value_format1())),
2418 3usize => Some(Field::new("value_format2", self.value_format2())),
2419 4usize => Some(Field::new(
2420 "class_def1_offset",
2421 FieldType::offset(self.class_def1_offset(), self.class_def1()),
2422 )),
2423 5usize => Some(Field::new(
2424 "class_def2_offset",
2425 FieldType::offset(self.class_def2_offset(), self.class_def2()),
2426 )),
2427 6usize => Some(Field::new("class1_count", self.class1_count())),
2428 7usize => Some(Field::new("class2_count", self.class2_count())),
2429 8usize => Some(Field::new(
2430 "class1_records",
2431 traversal::FieldType::computed_array(
2432 "Class1Record",
2433 self.class1_records(),
2434 self.offset_data(),
2435 ),
2436 )),
2437 _ => None,
2438 }
2439 }
2440}
2441
2442#[cfg(feature = "experimental_traverse")]
2443#[allow(clippy::needless_lifetimes)]
2444impl<'a> std::fmt::Debug for PairPosFormat2<'a> {
2445 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2446 (self as &dyn SomeTable<'a>).fmt(f)
2447 }
2448}
2449
2450#[derive(Clone, Debug)]
2452pub struct Class1Record<'a> {
2453 pub class2_records: ComputedArray<'a, Class2Record>,
2455}
2456
2457impl<'a> Class1Record<'a> {
2458 pub fn class2_records(&self) -> &ComputedArray<'a, Class2Record> {
2460 &self.class2_records
2461 }
2462}
2463
2464impl ReadArgs for Class1Record<'_> {
2465 type Args = (u16, ValueFormat, ValueFormat);
2466}
2467
2468impl ComputeSize for Class1Record<'_> {
2469 #[allow(clippy::needless_question_mark)]
2470 fn compute_size(args: (u16, ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2471 let (class2_count, value_format1, value_format2) = args;
2472 Ok((transforms::to_usize(class2_count)).saturating_mul(
2473 <Class2Record as ComputeSize>::compute_size((value_format1, value_format2))
2474 .unwrap_or(0),
2475 ))
2476 }
2477}
2478
2479impl<'a> FontRead<'a> for Class1Record<'a> {
2480 fn read_with_args(
2481 data: FontData<'a>,
2482 args: (u16, ValueFormat, ValueFormat),
2483 ) -> Result<Self, ReadError> {
2484 let mut cursor = data.cursor();
2485 let (class2_count, value_format1, value_format2) = args;
2486 Ok(Self {
2487 class2_records: cursor.read_computed_array(
2488 transforms::to_usize(class2_count),
2489 (value_format1, value_format2),
2490 )?,
2491 })
2492 }
2493}
2494
2495#[allow(clippy::needless_lifetimes)]
2496impl<'a> Class1Record<'a> {
2497 pub fn read(
2502 data: FontData<'a>,
2503 class2_count: u16,
2504 value_format1: ValueFormat,
2505 value_format2: ValueFormat,
2506 ) -> Result<Self, ReadError> {
2507 let args = (class2_count, value_format1, value_format2);
2508 Self::read_with_args(data, args)
2509 }
2510}
2511
2512#[cfg(feature = "experimental_traverse")]
2513impl<'a> SomeRecord<'a> for Class1Record<'a> {
2514 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2515 RecordResolver {
2516 name: "Class1Record",
2517 get_field: Box::new(move |idx, _data| match idx {
2518 0usize => Some(Field::new(
2519 "class2_records",
2520 traversal::FieldType::computed_array(
2521 "Class2Record",
2522 self.class2_records().clone(),
2523 FontData::new(&[]),
2524 ),
2525 )),
2526 _ => None,
2527 }),
2528 data,
2529 }
2530 }
2531}
2532
2533#[derive(Clone, Debug)]
2535pub struct Class2Record {
2536 pub value_record1: ValueRecord,
2538 pub value_record2: ValueRecord,
2540}
2541
2542impl Class2Record {
2543 pub fn value_record1(&self) -> &ValueRecord {
2545 &self.value_record1
2546 }
2547
2548 pub fn value_record2(&self) -> &ValueRecord {
2550 &self.value_record2
2551 }
2552}
2553
2554impl ReadArgs for Class2Record {
2555 type Args = (ValueFormat, ValueFormat);
2556}
2557
2558impl ComputeSize for Class2Record {
2559 #[allow(clippy::needless_question_mark)]
2560 fn compute_size(args: (ValueFormat, ValueFormat)) -> Result<usize, ReadError> {
2561 let (value_format1, value_format2) = args;
2562 let mut result = 0usize;
2563 result = result
2564 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format1).unwrap_or(0))
2565 .ok_or(ReadError::OutOfBounds)?;
2566 result = result
2567 .checked_add(<ValueRecord as ComputeSize>::compute_size(value_format2).unwrap_or(0))
2568 .ok_or(ReadError::OutOfBounds)?;
2569 Ok(result)
2570 }
2571}
2572
2573impl<'a> FontRead<'a> for Class2Record {
2574 fn read_with_args(
2575 data: FontData<'a>,
2576 args: (ValueFormat, ValueFormat),
2577 ) -> Result<Self, ReadError> {
2578 let mut cursor = data.cursor();
2579 let (value_format1, value_format2) = args;
2580 Ok(Self {
2581 value_record1: cursor.read_with_args(value_format1)?,
2582 value_record2: cursor.read_with_args(value_format2)?,
2583 })
2584 }
2585}
2586
2587#[allow(clippy::needless_lifetimes)]
2588impl<'a> Class2Record {
2589 pub fn read(
2594 data: FontData<'a>,
2595 value_format1: ValueFormat,
2596 value_format2: ValueFormat,
2597 ) -> Result<Self, ReadError> {
2598 let args = (value_format1, value_format2);
2599 Self::read_with_args(data, args)
2600 }
2601}
2602
2603#[cfg(feature = "experimental_traverse")]
2604impl<'a> SomeRecord<'a> for Class2Record {
2605 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2606 RecordResolver {
2607 name: "Class2Record",
2608 get_field: Box::new(move |idx, _data| match idx {
2609 0usize => Some(Field::new(
2610 "value_record1",
2611 self.value_record1().traversal_type(_data),
2612 )),
2613 1usize => Some(Field::new(
2614 "value_record2",
2615 self.value_record2().traversal_type(_data),
2616 )),
2617 _ => None,
2618 }),
2619 data,
2620 }
2621 }
2622}
2623
2624impl Format<u16> for CursivePosFormat1<'_> {
2625 const FORMAT: u16 = 1;
2626}
2627
2628impl<'a> MinByteRange<'a> for CursivePosFormat1<'a> {
2629 fn min_byte_range(&self) -> Range<usize> {
2630 0..self.entry_exit_record_byte_range().end
2631 }
2632 fn min_table_bytes(&self) -> &'a [u8] {
2633 let range = self.min_byte_range();
2634 self.data.as_bytes().get(range).unwrap_or_default()
2635 }
2636}
2637
2638impl ReadArgs for CursivePosFormat1<'_> {
2639 type Args = ();
2640}
2641
2642impl<'a> FontRead<'a> for CursivePosFormat1<'a> {
2643 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2644 #[allow(clippy::absurd_extreme_comparisons)]
2645 if data.len() < Self::MIN_SIZE {
2646 return Err(ReadError::OutOfBounds);
2647 }
2648 Ok(Self { data })
2649 }
2650}
2651
2652#[derive(Clone)]
2654pub struct CursivePosFormat1<'a> {
2655 data: FontData<'a>,
2656}
2657
2658#[allow(clippy::needless_lifetimes)]
2659impl<'a> CursivePosFormat1<'a> {
2660 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
2661 basic_table_impls!(impl_the_methods);
2662
2663 pub fn pos_format(&self) -> u16 {
2665 let range = self.pos_format_byte_range();
2666 self.data.read_at(range.start).ok().unwrap()
2667 }
2668
2669 pub fn coverage_offset(&self) -> Offset16 {
2671 let range = self.coverage_offset_byte_range();
2672 self.data.read_at(range.start).ok().unwrap()
2673 }
2674
2675 pub fn coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2677 let data = self.data;
2678 self.coverage_offset().resolve(data)
2679 }
2680
2681 pub fn entry_exit_count(&self) -> u16 {
2683 let range = self.entry_exit_count_byte_range();
2684 self.data.read_at(range.start).ok().unwrap()
2685 }
2686
2687 pub fn entry_exit_record(&self) -> &'a [EntryExitRecord] {
2689 let range = self.entry_exit_record_byte_range();
2690 self.data.read_array(range).ok().unwrap_or_default()
2691 }
2692
2693 pub fn pos_format_byte_range(&self) -> Range<usize> {
2694 let start = 0;
2695 let end = start + u16::RAW_BYTE_LEN;
2696 start..end
2697 }
2698
2699 pub fn coverage_offset_byte_range(&self) -> Range<usize> {
2700 let start = self.pos_format_byte_range().end;
2701 let end = start + Offset16::RAW_BYTE_LEN;
2702 start..end
2703 }
2704
2705 pub fn entry_exit_count_byte_range(&self) -> Range<usize> {
2706 let start = self.coverage_offset_byte_range().end;
2707 let end = start + u16::RAW_BYTE_LEN;
2708 start..end
2709 }
2710
2711 pub fn entry_exit_record_byte_range(&self) -> Range<usize> {
2712 let entry_exit_count = self.entry_exit_count();
2713 let start = self.entry_exit_count_byte_range().end;
2714 let end = start
2715 + (transforms::to_usize(entry_exit_count))
2716 .saturating_mul(EntryExitRecord::RAW_BYTE_LEN);
2717 start..end
2718 }
2719}
2720
2721const _: () = assert!(FontData::default_data_long_enough(
2722 CursivePosFormat1::MIN_SIZE
2723));
2724
2725impl Default for CursivePosFormat1<'_> {
2726 fn default() -> Self {
2727 Self {
2728 data: FontData::default_format_1_u16_table_data(),
2729 }
2730 }
2731}
2732
2733#[cfg(feature = "experimental_traverse")]
2734impl<'a> SomeTable<'a> for CursivePosFormat1<'a> {
2735 fn type_name(&self) -> &str {
2736 "CursivePosFormat1"
2737 }
2738 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
2739 match idx {
2740 0usize => Some(Field::new("pos_format", self.pos_format())),
2741 1usize => Some(Field::new(
2742 "coverage_offset",
2743 FieldType::offset(self.coverage_offset(), self.coverage()),
2744 )),
2745 2usize => Some(Field::new("entry_exit_count", self.entry_exit_count())),
2746 3usize => Some(Field::new(
2747 "entry_exit_record",
2748 traversal::FieldType::array_of_records(
2749 stringify!(EntryExitRecord),
2750 self.entry_exit_record(),
2751 self.offset_data(),
2752 ),
2753 )),
2754 _ => None,
2755 }
2756 }
2757}
2758
2759#[cfg(feature = "experimental_traverse")]
2760#[allow(clippy::needless_lifetimes)]
2761impl<'a> std::fmt::Debug for CursivePosFormat1<'a> {
2762 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2763 (self as &dyn SomeTable<'a>).fmt(f)
2764 }
2765}
2766
2767#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
2769#[repr(C)]
2770#[repr(packed)]
2771pub struct EntryExitRecord {
2772 pub entry_anchor_offset: BigEndian<Nullable<Offset16>>,
2775 pub exit_anchor_offset: BigEndian<Nullable<Offset16>>,
2778}
2779
2780impl EntryExitRecord {
2781 pub fn entry_anchor_offset(&self) -> Nullable<Offset16> {
2784 self.entry_anchor_offset.get()
2785 }
2786
2787 pub fn entry_anchor<'a>(
2793 &self,
2794 data: FontData<'a>,
2795 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2796 self.entry_anchor_offset().resolve(data)
2797 }
2798
2799 pub fn exit_anchor_offset(&self) -> Nullable<Offset16> {
2802 self.exit_anchor_offset.get()
2803 }
2804
2805 pub fn exit_anchor<'a>(
2811 &self,
2812 data: FontData<'a>,
2813 ) -> Option<Result<AnchorTable<'a>, ReadError>> {
2814 self.exit_anchor_offset().resolve(data)
2815 }
2816}
2817
2818impl FixedSize for EntryExitRecord {
2819 const RAW_BYTE_LEN: usize = Offset16::RAW_BYTE_LEN + Offset16::RAW_BYTE_LEN;
2820}
2821
2822#[cfg(feature = "experimental_traverse")]
2823impl<'a> SomeRecord<'a> for EntryExitRecord {
2824 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
2825 RecordResolver {
2826 name: "EntryExitRecord",
2827 get_field: Box::new(move |idx, _data| match idx {
2828 0usize => Some(Field::new(
2829 "entry_anchor_offset",
2830 FieldType::offset(self.entry_anchor_offset(), self.entry_anchor(_data)),
2831 )),
2832 1usize => Some(Field::new(
2833 "exit_anchor_offset",
2834 FieldType::offset(self.exit_anchor_offset(), self.exit_anchor(_data)),
2835 )),
2836 _ => None,
2837 }),
2838 data,
2839 }
2840 }
2841}
2842
2843impl Format<u16> for MarkBasePosFormat1<'_> {
2844 const FORMAT: u16 = 1;
2845}
2846
2847impl<'a> MinByteRange<'a> for MarkBasePosFormat1<'a> {
2848 fn min_byte_range(&self) -> Range<usize> {
2849 0..self.base_array_offset_byte_range().end
2850 }
2851 fn min_table_bytes(&self) -> &'a [u8] {
2852 let range = self.min_byte_range();
2853 self.data.as_bytes().get(range).unwrap_or_default()
2854 }
2855}
2856
2857impl ReadArgs for MarkBasePosFormat1<'_> {
2858 type Args = ();
2859}
2860
2861impl<'a> FontRead<'a> for MarkBasePosFormat1<'a> {
2862 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
2863 #[allow(clippy::absurd_extreme_comparisons)]
2864 if data.len() < Self::MIN_SIZE {
2865 return Err(ReadError::OutOfBounds);
2866 }
2867 Ok(Self { data })
2868 }
2869}
2870
2871#[derive(Clone)]
2873pub struct MarkBasePosFormat1<'a> {
2874 data: FontData<'a>,
2875}
2876
2877#[allow(clippy::needless_lifetimes)]
2878impl<'a> MarkBasePosFormat1<'a> {
2879 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
2880 + Offset16::RAW_BYTE_LEN
2881 + Offset16::RAW_BYTE_LEN
2882 + u16::RAW_BYTE_LEN
2883 + Offset16::RAW_BYTE_LEN
2884 + Offset16::RAW_BYTE_LEN);
2885 basic_table_impls!(impl_the_methods);
2886
2887 pub fn pos_format(&self) -> u16 {
2889 let range = self.pos_format_byte_range();
2890 self.data.read_at(range.start).ok().unwrap()
2891 }
2892
2893 pub fn mark_coverage_offset(&self) -> Offset16 {
2896 let range = self.mark_coverage_offset_byte_range();
2897 self.data.read_at(range.start).ok().unwrap()
2898 }
2899
2900 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2902 let data = self.data;
2903 self.mark_coverage_offset().resolve(data)
2904 }
2905
2906 pub fn base_coverage_offset(&self) -> Offset16 {
2909 let range = self.base_coverage_offset_byte_range();
2910 self.data.read_at(range.start).ok().unwrap()
2911 }
2912
2913 pub fn base_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
2915 let data = self.data;
2916 self.base_coverage_offset().resolve(data)
2917 }
2918
2919 pub fn mark_class_count(&self) -> u16 {
2921 let range = self.mark_class_count_byte_range();
2922 self.data.read_at(range.start).ok().unwrap()
2923 }
2924
2925 pub fn mark_array_offset(&self) -> Offset16 {
2928 let range = self.mark_array_offset_byte_range();
2929 self.data.read_at(range.start).ok().unwrap()
2930 }
2931
2932 pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
2934 let data = self.data;
2935 self.mark_array_offset().resolve(data)
2936 }
2937
2938 pub fn base_array_offset(&self) -> Offset16 {
2941 let range = self.base_array_offset_byte_range();
2942 self.data.read_at(range.start).ok().unwrap()
2943 }
2944
2945 pub fn base_array(&self) -> Result<BaseArray<'a>, ReadError> {
2947 let data = self.data;
2948 let args = self.mark_class_count();
2949 self.base_array_offset().resolve_with_args(data, args)
2950 }
2951
2952 pub fn pos_format_byte_range(&self) -> Range<usize> {
2953 let start = 0;
2954 let end = start + u16::RAW_BYTE_LEN;
2955 start..end
2956 }
2957
2958 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
2959 let start = self.pos_format_byte_range().end;
2960 let end = start + Offset16::RAW_BYTE_LEN;
2961 start..end
2962 }
2963
2964 pub fn base_coverage_offset_byte_range(&self) -> Range<usize> {
2965 let start = self.mark_coverage_offset_byte_range().end;
2966 let end = start + Offset16::RAW_BYTE_LEN;
2967 start..end
2968 }
2969
2970 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
2971 let start = self.base_coverage_offset_byte_range().end;
2972 let end = start + u16::RAW_BYTE_LEN;
2973 start..end
2974 }
2975
2976 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
2977 let start = self.mark_class_count_byte_range().end;
2978 let end = start + Offset16::RAW_BYTE_LEN;
2979 start..end
2980 }
2981
2982 pub fn base_array_offset_byte_range(&self) -> Range<usize> {
2983 let start = self.mark_array_offset_byte_range().end;
2984 let end = start + Offset16::RAW_BYTE_LEN;
2985 start..end
2986 }
2987}
2988
2989const _: () = assert!(FontData::default_data_long_enough(
2990 MarkBasePosFormat1::MIN_SIZE
2991));
2992
2993impl Default for MarkBasePosFormat1<'_> {
2994 fn default() -> Self {
2995 Self {
2996 data: FontData::default_format_1_u16_table_data(),
2997 }
2998 }
2999}
3000
3001#[cfg(feature = "experimental_traverse")]
3002impl<'a> SomeTable<'a> for MarkBasePosFormat1<'a> {
3003 fn type_name(&self) -> &str {
3004 "MarkBasePosFormat1"
3005 }
3006 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3007 match idx {
3008 0usize => Some(Field::new("pos_format", self.pos_format())),
3009 1usize => Some(Field::new(
3010 "mark_coverage_offset",
3011 FieldType::offset(self.mark_coverage_offset(), self.mark_coverage()),
3012 )),
3013 2usize => Some(Field::new(
3014 "base_coverage_offset",
3015 FieldType::offset(self.base_coverage_offset(), self.base_coverage()),
3016 )),
3017 3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3018 4usize => Some(Field::new(
3019 "mark_array_offset",
3020 FieldType::offset(self.mark_array_offset(), self.mark_array()),
3021 )),
3022 5usize => Some(Field::new(
3023 "base_array_offset",
3024 FieldType::offset(self.base_array_offset(), self.base_array()),
3025 )),
3026 _ => None,
3027 }
3028 }
3029}
3030
3031#[cfg(feature = "experimental_traverse")]
3032#[allow(clippy::needless_lifetimes)]
3033impl<'a> std::fmt::Debug for MarkBasePosFormat1<'a> {
3034 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3035 (self as &dyn SomeTable<'a>).fmt(f)
3036 }
3037}
3038
3039impl<'a> MinByteRange<'a> for BaseArray<'a> {
3040 fn min_byte_range(&self) -> Range<usize> {
3041 0..self.base_records_byte_range().end
3042 }
3043 fn min_table_bytes(&self) -> &'a [u8] {
3044 let range = self.min_byte_range();
3045 self.data.as_bytes().get(range).unwrap_or_default()
3046 }
3047}
3048
3049impl ReadArgs for BaseArray<'_> {
3050 type Args = u16;
3051}
3052
3053impl<'a> FontRead<'a> for BaseArray<'a> {
3054 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3055 let mark_class_count = args;
3056
3057 #[allow(clippy::absurd_extreme_comparisons)]
3058 if data.len() < Self::MIN_SIZE {
3059 return Err(ReadError::OutOfBounds);
3060 }
3061 Ok(Self {
3062 data,
3063 mark_class_count,
3064 })
3065 }
3066}
3067
3068impl<'a> BaseArray<'a> {
3069 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3074 let args = mark_class_count;
3075 Self::read_with_args(data, args)
3076 }
3077}
3078
3079#[derive(Clone)]
3081pub struct BaseArray<'a> {
3082 data: FontData<'a>,
3083 mark_class_count: u16,
3084}
3085
3086#[allow(clippy::needless_lifetimes)]
3087impl<'a> BaseArray<'a> {
3088 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3089 basic_table_impls!(impl_the_methods);
3090
3091 pub fn base_count(&self) -> u16 {
3093 let range = self.base_count_byte_range();
3094 self.data.read_at(range.start).ok().unwrap()
3095 }
3096
3097 pub fn base_records(&self) -> ComputedArray<'a, BaseRecord<'a>> {
3099 let range = self.base_records_byte_range();
3100 self.data
3101 .read_with_args(range, self.mark_class_count())
3102 .unwrap_or_default()
3103 }
3104
3105 pub(crate) fn mark_class_count(&self) -> u16 {
3106 self.mark_class_count
3107 }
3108
3109 pub fn base_count_byte_range(&self) -> Range<usize> {
3110 let start = 0;
3111 let end = start + u16::RAW_BYTE_LEN;
3112 start..end
3113 }
3114
3115 pub fn base_records_byte_range(&self) -> Range<usize> {
3116 let base_count = self.base_count();
3117 let start = self.base_count_byte_range().end;
3118 let end = start
3119 + (transforms::to_usize(base_count)).saturating_mul(
3120 <BaseRecord as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
3121 );
3122 start..end
3123 }
3124}
3125
3126const _: () = assert!(FontData::default_data_long_enough(BaseArray::MIN_SIZE));
3127
3128impl Default for BaseArray<'_> {
3129 fn default() -> Self {
3130 Self {
3131 data: FontData::default_table_data(),
3132 mark_class_count: Default::default(),
3133 }
3134 }
3135}
3136
3137#[cfg(feature = "experimental_traverse")]
3138impl<'a> SomeTable<'a> for BaseArray<'a> {
3139 fn type_name(&self) -> &str {
3140 "BaseArray"
3141 }
3142 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3143 match idx {
3144 0usize => Some(Field::new("base_count", self.base_count())),
3145 1usize => Some(Field::new(
3146 "base_records",
3147 traversal::FieldType::computed_array(
3148 "BaseRecord",
3149 self.base_records(),
3150 self.offset_data(),
3151 ),
3152 )),
3153 _ => None,
3154 }
3155 }
3156}
3157
3158#[cfg(feature = "experimental_traverse")]
3159#[allow(clippy::needless_lifetimes)]
3160impl<'a> std::fmt::Debug for BaseArray<'a> {
3161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3162 (self as &dyn SomeTable<'a>).fmt(f)
3163 }
3164}
3165
3166#[derive(Clone, Debug)]
3168pub struct BaseRecord<'a> {
3169 pub base_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3173}
3174
3175impl<'a> BaseRecord<'a> {
3176 pub fn base_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3180 self.base_anchor_offsets
3181 }
3182
3183 pub fn base_anchors(
3190 &self,
3191 data: FontData<'a>,
3192 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3193 let offsets = self.base_anchor_offsets();
3194 ArrayOfNullableOffsets::new(offsets, data, ())
3195 }
3196}
3197
3198impl ReadArgs for BaseRecord<'_> {
3199 type Args = u16;
3200}
3201
3202impl ComputeSize for BaseRecord<'_> {
3203 #[allow(clippy::needless_question_mark)]
3204 fn compute_size(args: u16) -> Result<usize, ReadError> {
3205 let mark_class_count = args;
3206 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
3207 }
3208}
3209
3210impl<'a> FontRead<'a> for BaseRecord<'a> {
3211 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3212 let mut cursor = data.cursor();
3213 let mark_class_count = args;
3214 Ok(Self {
3215 base_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
3216 })
3217 }
3218}
3219
3220#[allow(clippy::needless_lifetimes)]
3221impl<'a> BaseRecord<'a> {
3222 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3227 let args = mark_class_count;
3228 Self::read_with_args(data, args)
3229 }
3230}
3231
3232#[cfg(feature = "experimental_traverse")]
3233impl<'a> SomeRecord<'a> for BaseRecord<'a> {
3234 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
3235 RecordResolver {
3236 name: "BaseRecord",
3237 get_field: Box::new(move |idx, _data| match idx {
3238 0usize => Some(Field::new(
3239 "base_anchor_offsets",
3240 FieldType::from(self.base_anchors(_data)),
3241 )),
3242 _ => None,
3243 }),
3244 data,
3245 }
3246 }
3247}
3248
3249impl Format<u16> for MarkLigPosFormat1<'_> {
3250 const FORMAT: u16 = 1;
3251}
3252
3253impl<'a> MinByteRange<'a> for MarkLigPosFormat1<'a> {
3254 fn min_byte_range(&self) -> Range<usize> {
3255 0..self.ligature_array_offset_byte_range().end
3256 }
3257 fn min_table_bytes(&self) -> &'a [u8] {
3258 let range = self.min_byte_range();
3259 self.data.as_bytes().get(range).unwrap_or_default()
3260 }
3261}
3262
3263impl ReadArgs for MarkLigPosFormat1<'_> {
3264 type Args = ();
3265}
3266
3267impl<'a> FontRead<'a> for MarkLigPosFormat1<'a> {
3268 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3269 #[allow(clippy::absurd_extreme_comparisons)]
3270 if data.len() < Self::MIN_SIZE {
3271 return Err(ReadError::OutOfBounds);
3272 }
3273 Ok(Self { data })
3274 }
3275}
3276
3277#[derive(Clone)]
3279pub struct MarkLigPosFormat1<'a> {
3280 data: FontData<'a>,
3281}
3282
3283#[allow(clippy::needless_lifetimes)]
3284impl<'a> MarkLigPosFormat1<'a> {
3285 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3286 + Offset16::RAW_BYTE_LEN
3287 + Offset16::RAW_BYTE_LEN
3288 + u16::RAW_BYTE_LEN
3289 + Offset16::RAW_BYTE_LEN
3290 + Offset16::RAW_BYTE_LEN);
3291 basic_table_impls!(impl_the_methods);
3292
3293 pub fn pos_format(&self) -> u16 {
3295 let range = self.pos_format_byte_range();
3296 self.data.read_at(range.start).ok().unwrap()
3297 }
3298
3299 pub fn mark_coverage_offset(&self) -> Offset16 {
3302 let range = self.mark_coverage_offset_byte_range();
3303 self.data.read_at(range.start).ok().unwrap()
3304 }
3305
3306 pub fn mark_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3308 let data = self.data;
3309 self.mark_coverage_offset().resolve(data)
3310 }
3311
3312 pub fn ligature_coverage_offset(&self) -> Offset16 {
3315 let range = self.ligature_coverage_offset_byte_range();
3316 self.data.read_at(range.start).ok().unwrap()
3317 }
3318
3319 pub fn ligature_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3321 let data = self.data;
3322 self.ligature_coverage_offset().resolve(data)
3323 }
3324
3325 pub fn mark_class_count(&self) -> u16 {
3327 let range = self.mark_class_count_byte_range();
3328 self.data.read_at(range.start).ok().unwrap()
3329 }
3330
3331 pub fn mark_array_offset(&self) -> Offset16 {
3334 let range = self.mark_array_offset_byte_range();
3335 self.data.read_at(range.start).ok().unwrap()
3336 }
3337
3338 pub fn mark_array(&self) -> Result<MarkArray<'a>, ReadError> {
3340 let data = self.data;
3341 self.mark_array_offset().resolve(data)
3342 }
3343
3344 pub fn ligature_array_offset(&self) -> Offset16 {
3347 let range = self.ligature_array_offset_byte_range();
3348 self.data.read_at(range.start).ok().unwrap()
3349 }
3350
3351 pub fn ligature_array(&self) -> Result<LigatureArray<'a>, ReadError> {
3353 let data = self.data;
3354 let args = self.mark_class_count();
3355 self.ligature_array_offset().resolve_with_args(data, args)
3356 }
3357
3358 pub fn pos_format_byte_range(&self) -> Range<usize> {
3359 let start = 0;
3360 let end = start + u16::RAW_BYTE_LEN;
3361 start..end
3362 }
3363
3364 pub fn mark_coverage_offset_byte_range(&self) -> Range<usize> {
3365 let start = self.pos_format_byte_range().end;
3366 let end = start + Offset16::RAW_BYTE_LEN;
3367 start..end
3368 }
3369
3370 pub fn ligature_coverage_offset_byte_range(&self) -> Range<usize> {
3371 let start = self.mark_coverage_offset_byte_range().end;
3372 let end = start + Offset16::RAW_BYTE_LEN;
3373 start..end
3374 }
3375
3376 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3377 let start = self.ligature_coverage_offset_byte_range().end;
3378 let end = start + u16::RAW_BYTE_LEN;
3379 start..end
3380 }
3381
3382 pub fn mark_array_offset_byte_range(&self) -> Range<usize> {
3383 let start = self.mark_class_count_byte_range().end;
3384 let end = start + Offset16::RAW_BYTE_LEN;
3385 start..end
3386 }
3387
3388 pub fn ligature_array_offset_byte_range(&self) -> Range<usize> {
3389 let start = self.mark_array_offset_byte_range().end;
3390 let end = start + Offset16::RAW_BYTE_LEN;
3391 start..end
3392 }
3393}
3394
3395const _: () = assert!(FontData::default_data_long_enough(
3396 MarkLigPosFormat1::MIN_SIZE
3397));
3398
3399impl Default for MarkLigPosFormat1<'_> {
3400 fn default() -> Self {
3401 Self {
3402 data: FontData::default_format_1_u16_table_data(),
3403 }
3404 }
3405}
3406
3407#[cfg(feature = "experimental_traverse")]
3408impl<'a> SomeTable<'a> for MarkLigPosFormat1<'a> {
3409 fn type_name(&self) -> &str {
3410 "MarkLigPosFormat1"
3411 }
3412 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3413 match idx {
3414 0usize => Some(Field::new("pos_format", self.pos_format())),
3415 1usize => Some(Field::new(
3416 "mark_coverage_offset",
3417 FieldType::offset(self.mark_coverage_offset(), self.mark_coverage()),
3418 )),
3419 2usize => Some(Field::new(
3420 "ligature_coverage_offset",
3421 FieldType::offset(self.ligature_coverage_offset(), self.ligature_coverage()),
3422 )),
3423 3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3424 4usize => Some(Field::new(
3425 "mark_array_offset",
3426 FieldType::offset(self.mark_array_offset(), self.mark_array()),
3427 )),
3428 5usize => Some(Field::new(
3429 "ligature_array_offset",
3430 FieldType::offset(self.ligature_array_offset(), self.ligature_array()),
3431 )),
3432 _ => None,
3433 }
3434 }
3435}
3436
3437#[cfg(feature = "experimental_traverse")]
3438#[allow(clippy::needless_lifetimes)]
3439impl<'a> std::fmt::Debug for MarkLigPosFormat1<'a> {
3440 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3441 (self as &dyn SomeTable<'a>).fmt(f)
3442 }
3443}
3444
3445impl<'a> MinByteRange<'a> for LigatureArray<'a> {
3446 fn min_byte_range(&self) -> Range<usize> {
3447 0..self.ligature_attach_offsets_byte_range().end
3448 }
3449 fn min_table_bytes(&self) -> &'a [u8] {
3450 let range = self.min_byte_range();
3451 self.data.as_bytes().get(range).unwrap_or_default()
3452 }
3453}
3454
3455impl ReadArgs for LigatureArray<'_> {
3456 type Args = u16;
3457}
3458
3459impl<'a> FontRead<'a> for LigatureArray<'a> {
3460 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3461 let mark_class_count = args;
3462
3463 #[allow(clippy::absurd_extreme_comparisons)]
3464 if data.len() < Self::MIN_SIZE {
3465 return Err(ReadError::OutOfBounds);
3466 }
3467 Ok(Self {
3468 data,
3469 mark_class_count,
3470 })
3471 }
3472}
3473
3474impl<'a> LigatureArray<'a> {
3475 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3480 let args = mark_class_count;
3481 Self::read_with_args(data, args)
3482 }
3483}
3484
3485#[derive(Clone)]
3487pub struct LigatureArray<'a> {
3488 data: FontData<'a>,
3489 mark_class_count: u16,
3490}
3491
3492#[allow(clippy::needless_lifetimes)]
3493impl<'a> LigatureArray<'a> {
3494 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3495 basic_table_impls!(impl_the_methods);
3496
3497 pub fn ligature_count(&self) -> u16 {
3499 let range = self.ligature_count_byte_range();
3500 self.data.read_at(range.start).ok().unwrap()
3501 }
3502
3503 pub fn ligature_attach_offsets(&self) -> &'a [BigEndian<Offset16>] {
3507 let range = self.ligature_attach_offsets_byte_range();
3508 self.data.read_array(range).ok().unwrap_or_default()
3509 }
3510
3511 pub fn ligature_attaches(&self) -> ArrayOfOffsets<'a, LigatureAttach<'a>, Offset16> {
3513 let data = self.data;
3514 let offsets = self.ligature_attach_offsets();
3515 let args = self.mark_class_count();
3516 ArrayOfOffsets::new(offsets, data, args)
3517 }
3518
3519 pub(crate) fn mark_class_count(&self) -> u16 {
3520 self.mark_class_count
3521 }
3522
3523 pub fn ligature_count_byte_range(&self) -> Range<usize> {
3524 let start = 0;
3525 let end = start + u16::RAW_BYTE_LEN;
3526 start..end
3527 }
3528
3529 pub fn ligature_attach_offsets_byte_range(&self) -> Range<usize> {
3530 let ligature_count = self.ligature_count();
3531 let start = self.ligature_count_byte_range().end;
3532 let end =
3533 start + (transforms::to_usize(ligature_count)).saturating_mul(Offset16::RAW_BYTE_LEN);
3534 start..end
3535 }
3536}
3537
3538const _: () = assert!(FontData::default_data_long_enough(LigatureArray::MIN_SIZE));
3539
3540impl Default for LigatureArray<'_> {
3541 fn default() -> Self {
3542 Self {
3543 data: FontData::default_table_data(),
3544 mark_class_count: Default::default(),
3545 }
3546 }
3547}
3548
3549#[cfg(feature = "experimental_traverse")]
3550impl<'a> SomeTable<'a> for LigatureArray<'a> {
3551 fn type_name(&self) -> &str {
3552 "LigatureArray"
3553 }
3554 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3555 match idx {
3556 0usize => Some(Field::new("ligature_count", self.ligature_count())),
3557 1usize => Some(Field::new(
3558 "ligature_attach_offsets",
3559 FieldType::from(self.ligature_attaches()),
3560 )),
3561 _ => None,
3562 }
3563 }
3564}
3565
3566#[cfg(feature = "experimental_traverse")]
3567#[allow(clippy::needless_lifetimes)]
3568impl<'a> std::fmt::Debug for LigatureArray<'a> {
3569 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3570 (self as &dyn SomeTable<'a>).fmt(f)
3571 }
3572}
3573
3574impl<'a> MinByteRange<'a> for LigatureAttach<'a> {
3575 fn min_byte_range(&self) -> Range<usize> {
3576 0..self.component_records_byte_range().end
3577 }
3578 fn min_table_bytes(&self) -> &'a [u8] {
3579 let range = self.min_byte_range();
3580 self.data.as_bytes().get(range).unwrap_or_default()
3581 }
3582}
3583
3584impl ReadArgs for LigatureAttach<'_> {
3585 type Args = u16;
3586}
3587
3588impl<'a> FontRead<'a> for LigatureAttach<'a> {
3589 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3590 let mark_class_count = args;
3591
3592 #[allow(clippy::absurd_extreme_comparisons)]
3593 if data.len() < Self::MIN_SIZE {
3594 return Err(ReadError::OutOfBounds);
3595 }
3596 Ok(Self {
3597 data,
3598 mark_class_count,
3599 })
3600 }
3601}
3602
3603impl<'a> LigatureAttach<'a> {
3604 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3609 let args = mark_class_count;
3610 Self::read_with_args(data, args)
3611 }
3612}
3613
3614#[derive(Clone)]
3616pub struct LigatureAttach<'a> {
3617 data: FontData<'a>,
3618 mark_class_count: u16,
3619}
3620
3621#[allow(clippy::needless_lifetimes)]
3622impl<'a> LigatureAttach<'a> {
3623 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
3624 basic_table_impls!(impl_the_methods);
3625
3626 pub fn component_count(&self) -> u16 {
3628 let range = self.component_count_byte_range();
3629 self.data.read_at(range.start).ok().unwrap()
3630 }
3631
3632 pub fn component_records(&self) -> ComputedArray<'a, ComponentRecord<'a>> {
3634 let range = self.component_records_byte_range();
3635 self.data
3636 .read_with_args(range, self.mark_class_count())
3637 .unwrap_or_default()
3638 }
3639
3640 pub(crate) fn mark_class_count(&self) -> u16 {
3641 self.mark_class_count
3642 }
3643
3644 pub fn component_count_byte_range(&self) -> Range<usize> {
3645 let start = 0;
3646 let end = start + u16::RAW_BYTE_LEN;
3647 start..end
3648 }
3649
3650 pub fn component_records_byte_range(&self) -> Range<usize> {
3651 let component_count = self.component_count();
3652 let start = self.component_count_byte_range().end;
3653 let end = start
3654 + (transforms::to_usize(component_count)).saturating_mul(
3655 <ComponentRecord as ComputeSize>::compute_size(self.mark_class_count())
3656 .unwrap_or(0),
3657 );
3658 start..end
3659 }
3660}
3661
3662const _: () = assert!(FontData::default_data_long_enough(LigatureAttach::MIN_SIZE));
3663
3664impl Default for LigatureAttach<'_> {
3665 fn default() -> Self {
3666 Self {
3667 data: FontData::default_table_data(),
3668 mark_class_count: Default::default(),
3669 }
3670 }
3671}
3672
3673#[cfg(feature = "experimental_traverse")]
3674impl<'a> SomeTable<'a> for LigatureAttach<'a> {
3675 fn type_name(&self) -> &str {
3676 "LigatureAttach"
3677 }
3678 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3679 match idx {
3680 0usize => Some(Field::new("component_count", self.component_count())),
3681 1usize => Some(Field::new(
3682 "component_records",
3683 traversal::FieldType::computed_array(
3684 "ComponentRecord",
3685 self.component_records(),
3686 self.offset_data(),
3687 ),
3688 )),
3689 _ => None,
3690 }
3691 }
3692}
3693
3694#[cfg(feature = "experimental_traverse")]
3695#[allow(clippy::needless_lifetimes)]
3696impl<'a> std::fmt::Debug for LigatureAttach<'a> {
3697 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3698 (self as &dyn SomeTable<'a>).fmt(f)
3699 }
3700}
3701
3702#[derive(Clone, Debug)]
3704pub struct ComponentRecord<'a> {
3705 pub ligature_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
3709}
3710
3711impl<'a> ComponentRecord<'a> {
3712 pub fn ligature_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
3716 self.ligature_anchor_offsets
3717 }
3718
3719 pub fn ligature_anchors(
3726 &self,
3727 data: FontData<'a>,
3728 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
3729 let offsets = self.ligature_anchor_offsets();
3730 ArrayOfNullableOffsets::new(offsets, data, ())
3731 }
3732}
3733
3734impl ReadArgs for ComponentRecord<'_> {
3735 type Args = u16;
3736}
3737
3738impl ComputeSize for ComponentRecord<'_> {
3739 #[allow(clippy::needless_question_mark)]
3740 fn compute_size(args: u16) -> Result<usize, ReadError> {
3741 let mark_class_count = args;
3742 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
3743 }
3744}
3745
3746impl<'a> FontRead<'a> for ComponentRecord<'a> {
3747 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3748 let mut cursor = data.cursor();
3749 let mark_class_count = args;
3750 Ok(Self {
3751 ligature_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
3752 })
3753 }
3754}
3755
3756#[allow(clippy::needless_lifetimes)]
3757impl<'a> ComponentRecord<'a> {
3758 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
3763 let args = mark_class_count;
3764 Self::read_with_args(data, args)
3765 }
3766}
3767
3768#[cfg(feature = "experimental_traverse")]
3769impl<'a> SomeRecord<'a> for ComponentRecord<'a> {
3770 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
3771 RecordResolver {
3772 name: "ComponentRecord",
3773 get_field: Box::new(move |idx, _data| match idx {
3774 0usize => Some(Field::new(
3775 "ligature_anchor_offsets",
3776 FieldType::from(self.ligature_anchors(_data)),
3777 )),
3778 _ => None,
3779 }),
3780 data,
3781 }
3782 }
3783}
3784
3785impl Format<u16> for MarkMarkPosFormat1<'_> {
3786 const FORMAT: u16 = 1;
3787}
3788
3789impl<'a> MinByteRange<'a> for MarkMarkPosFormat1<'a> {
3790 fn min_byte_range(&self) -> Range<usize> {
3791 0..self.mark2_array_offset_byte_range().end
3792 }
3793 fn min_table_bytes(&self) -> &'a [u8] {
3794 let range = self.min_byte_range();
3795 self.data.as_bytes().get(range).unwrap_or_default()
3796 }
3797}
3798
3799impl ReadArgs for MarkMarkPosFormat1<'_> {
3800 type Args = ();
3801}
3802
3803impl<'a> FontRead<'a> for MarkMarkPosFormat1<'a> {
3804 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
3805 #[allow(clippy::absurd_extreme_comparisons)]
3806 if data.len() < Self::MIN_SIZE {
3807 return Err(ReadError::OutOfBounds);
3808 }
3809 Ok(Self { data })
3810 }
3811}
3812
3813#[derive(Clone)]
3815pub struct MarkMarkPosFormat1<'a> {
3816 data: FontData<'a>,
3817}
3818
3819#[allow(clippy::needless_lifetimes)]
3820impl<'a> MarkMarkPosFormat1<'a> {
3821 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
3822 + Offset16::RAW_BYTE_LEN
3823 + Offset16::RAW_BYTE_LEN
3824 + u16::RAW_BYTE_LEN
3825 + Offset16::RAW_BYTE_LEN
3826 + Offset16::RAW_BYTE_LEN);
3827 basic_table_impls!(impl_the_methods);
3828
3829 pub fn pos_format(&self) -> u16 {
3831 let range = self.pos_format_byte_range();
3832 self.data.read_at(range.start).ok().unwrap()
3833 }
3834
3835 pub fn mark1_coverage_offset(&self) -> Offset16 {
3838 let range = self.mark1_coverage_offset_byte_range();
3839 self.data.read_at(range.start).ok().unwrap()
3840 }
3841
3842 pub fn mark1_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3844 let data = self.data;
3845 self.mark1_coverage_offset().resolve(data)
3846 }
3847
3848 pub fn mark2_coverage_offset(&self) -> Offset16 {
3851 let range = self.mark2_coverage_offset_byte_range();
3852 self.data.read_at(range.start).ok().unwrap()
3853 }
3854
3855 pub fn mark2_coverage(&self) -> Result<CoverageTable<'a>, ReadError> {
3857 let data = self.data;
3858 self.mark2_coverage_offset().resolve(data)
3859 }
3860
3861 pub fn mark_class_count(&self) -> u16 {
3863 let range = self.mark_class_count_byte_range();
3864 self.data.read_at(range.start).ok().unwrap()
3865 }
3866
3867 pub fn mark1_array_offset(&self) -> Offset16 {
3870 let range = self.mark1_array_offset_byte_range();
3871 self.data.read_at(range.start).ok().unwrap()
3872 }
3873
3874 pub fn mark1_array(&self) -> Result<MarkArray<'a>, ReadError> {
3876 let data = self.data;
3877 self.mark1_array_offset().resolve(data)
3878 }
3879
3880 pub fn mark2_array_offset(&self) -> Offset16 {
3883 let range = self.mark2_array_offset_byte_range();
3884 self.data.read_at(range.start).ok().unwrap()
3885 }
3886
3887 pub fn mark2_array(&self) -> Result<Mark2Array<'a>, ReadError> {
3889 let data = self.data;
3890 let args = self.mark_class_count();
3891 self.mark2_array_offset().resolve_with_args(data, args)
3892 }
3893
3894 pub fn pos_format_byte_range(&self) -> Range<usize> {
3895 let start = 0;
3896 let end = start + u16::RAW_BYTE_LEN;
3897 start..end
3898 }
3899
3900 pub fn mark1_coverage_offset_byte_range(&self) -> Range<usize> {
3901 let start = self.pos_format_byte_range().end;
3902 let end = start + Offset16::RAW_BYTE_LEN;
3903 start..end
3904 }
3905
3906 pub fn mark2_coverage_offset_byte_range(&self) -> Range<usize> {
3907 let start = self.mark1_coverage_offset_byte_range().end;
3908 let end = start + Offset16::RAW_BYTE_LEN;
3909 start..end
3910 }
3911
3912 pub fn mark_class_count_byte_range(&self) -> Range<usize> {
3913 let start = self.mark2_coverage_offset_byte_range().end;
3914 let end = start + u16::RAW_BYTE_LEN;
3915 start..end
3916 }
3917
3918 pub fn mark1_array_offset_byte_range(&self) -> Range<usize> {
3919 let start = self.mark_class_count_byte_range().end;
3920 let end = start + Offset16::RAW_BYTE_LEN;
3921 start..end
3922 }
3923
3924 pub fn mark2_array_offset_byte_range(&self) -> Range<usize> {
3925 let start = self.mark1_array_offset_byte_range().end;
3926 let end = start + Offset16::RAW_BYTE_LEN;
3927 start..end
3928 }
3929}
3930
3931const _: () = assert!(FontData::default_data_long_enough(
3932 MarkMarkPosFormat1::MIN_SIZE
3933));
3934
3935impl Default for MarkMarkPosFormat1<'_> {
3936 fn default() -> Self {
3937 Self {
3938 data: FontData::default_format_1_u16_table_data(),
3939 }
3940 }
3941}
3942
3943#[cfg(feature = "experimental_traverse")]
3944impl<'a> SomeTable<'a> for MarkMarkPosFormat1<'a> {
3945 fn type_name(&self) -> &str {
3946 "MarkMarkPosFormat1"
3947 }
3948 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
3949 match idx {
3950 0usize => Some(Field::new("pos_format", self.pos_format())),
3951 1usize => Some(Field::new(
3952 "mark1_coverage_offset",
3953 FieldType::offset(self.mark1_coverage_offset(), self.mark1_coverage()),
3954 )),
3955 2usize => Some(Field::new(
3956 "mark2_coverage_offset",
3957 FieldType::offset(self.mark2_coverage_offset(), self.mark2_coverage()),
3958 )),
3959 3usize => Some(Field::new("mark_class_count", self.mark_class_count())),
3960 4usize => Some(Field::new(
3961 "mark1_array_offset",
3962 FieldType::offset(self.mark1_array_offset(), self.mark1_array()),
3963 )),
3964 5usize => Some(Field::new(
3965 "mark2_array_offset",
3966 FieldType::offset(self.mark2_array_offset(), self.mark2_array()),
3967 )),
3968 _ => None,
3969 }
3970 }
3971}
3972
3973#[cfg(feature = "experimental_traverse")]
3974#[allow(clippy::needless_lifetimes)]
3975impl<'a> std::fmt::Debug for MarkMarkPosFormat1<'a> {
3976 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3977 (self as &dyn SomeTable<'a>).fmt(f)
3978 }
3979}
3980
3981impl<'a> MinByteRange<'a> for Mark2Array<'a> {
3982 fn min_byte_range(&self) -> Range<usize> {
3983 0..self.mark2_records_byte_range().end
3984 }
3985 fn min_table_bytes(&self) -> &'a [u8] {
3986 let range = self.min_byte_range();
3987 self.data.as_bytes().get(range).unwrap_or_default()
3988 }
3989}
3990
3991impl ReadArgs for Mark2Array<'_> {
3992 type Args = u16;
3993}
3994
3995impl<'a> FontRead<'a> for Mark2Array<'a> {
3996 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
3997 let mark_class_count = args;
3998
3999 #[allow(clippy::absurd_extreme_comparisons)]
4000 if data.len() < Self::MIN_SIZE {
4001 return Err(ReadError::OutOfBounds);
4002 }
4003 Ok(Self {
4004 data,
4005 mark_class_count,
4006 })
4007 }
4008}
4009
4010impl<'a> Mark2Array<'a> {
4011 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
4016 let args = mark_class_count;
4017 Self::read_with_args(data, args)
4018 }
4019}
4020
4021#[derive(Clone)]
4023pub struct Mark2Array<'a> {
4024 data: FontData<'a>,
4025 mark_class_count: u16,
4026}
4027
4028#[allow(clippy::needless_lifetimes)]
4029impl<'a> Mark2Array<'a> {
4030 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
4031 basic_table_impls!(impl_the_methods);
4032
4033 pub fn mark2_count(&self) -> u16 {
4035 let range = self.mark2_count_byte_range();
4036 self.data.read_at(range.start).ok().unwrap()
4037 }
4038
4039 pub fn mark2_records(&self) -> ComputedArray<'a, Mark2Record<'a>> {
4041 let range = self.mark2_records_byte_range();
4042 self.data
4043 .read_with_args(range, self.mark_class_count())
4044 .unwrap_or_default()
4045 }
4046
4047 pub(crate) fn mark_class_count(&self) -> u16 {
4048 self.mark_class_count
4049 }
4050
4051 pub fn mark2_count_byte_range(&self) -> Range<usize> {
4052 let start = 0;
4053 let end = start + u16::RAW_BYTE_LEN;
4054 start..end
4055 }
4056
4057 pub fn mark2_records_byte_range(&self) -> Range<usize> {
4058 let mark2_count = self.mark2_count();
4059 let start = self.mark2_count_byte_range().end;
4060 let end = start
4061 + (transforms::to_usize(mark2_count)).saturating_mul(
4062 <Mark2Record as ComputeSize>::compute_size(self.mark_class_count()).unwrap_or(0),
4063 );
4064 start..end
4065 }
4066}
4067
4068const _: () = assert!(FontData::default_data_long_enough(Mark2Array::MIN_SIZE));
4069
4070impl Default for Mark2Array<'_> {
4071 fn default() -> Self {
4072 Self {
4073 data: FontData::default_table_data(),
4074 mark_class_count: Default::default(),
4075 }
4076 }
4077}
4078
4079#[cfg(feature = "experimental_traverse")]
4080impl<'a> SomeTable<'a> for Mark2Array<'a> {
4081 fn type_name(&self) -> &str {
4082 "Mark2Array"
4083 }
4084 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4085 match idx {
4086 0usize => Some(Field::new("mark2_count", self.mark2_count())),
4087 1usize => Some(Field::new(
4088 "mark2_records",
4089 traversal::FieldType::computed_array(
4090 "Mark2Record",
4091 self.mark2_records(),
4092 self.offset_data(),
4093 ),
4094 )),
4095 _ => None,
4096 }
4097 }
4098}
4099
4100#[cfg(feature = "experimental_traverse")]
4101#[allow(clippy::needless_lifetimes)]
4102impl<'a> std::fmt::Debug for Mark2Array<'a> {
4103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4104 (self as &dyn SomeTable<'a>).fmt(f)
4105 }
4106}
4107
4108#[derive(Clone, Debug)]
4110pub struct Mark2Record<'a> {
4111 pub mark2_anchor_offsets: &'a [BigEndian<Nullable<Offset16>>],
4115}
4116
4117impl<'a> Mark2Record<'a> {
4118 pub fn mark2_anchor_offsets(&self) -> &'a [BigEndian<Nullable<Offset16>>] {
4122 self.mark2_anchor_offsets
4123 }
4124
4125 pub fn mark2_anchors(
4132 &self,
4133 data: FontData<'a>,
4134 ) -> ArrayOfNullableOffsets<'a, AnchorTable<'a>, Offset16> {
4135 let offsets = self.mark2_anchor_offsets();
4136 ArrayOfNullableOffsets::new(offsets, data, ())
4137 }
4138}
4139
4140impl ReadArgs for Mark2Record<'_> {
4141 type Args = u16;
4142}
4143
4144impl ComputeSize for Mark2Record<'_> {
4145 #[allow(clippy::needless_question_mark)]
4146 fn compute_size(args: u16) -> Result<usize, ReadError> {
4147 let mark_class_count = args;
4148 Ok((transforms::to_usize(mark_class_count)).saturating_mul(Offset16::RAW_BYTE_LEN))
4149 }
4150}
4151
4152impl<'a> FontRead<'a> for Mark2Record<'a> {
4153 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
4154 let mut cursor = data.cursor();
4155 let mark_class_count = args;
4156 Ok(Self {
4157 mark2_anchor_offsets: cursor.read_array(transforms::to_usize(mark_class_count))?,
4158 })
4159 }
4160}
4161
4162#[allow(clippy::needless_lifetimes)]
4163impl<'a> Mark2Record<'a> {
4164 pub fn read(data: FontData<'a>, mark_class_count: u16) -> Result<Self, ReadError> {
4169 let args = mark_class_count;
4170 Self::read_with_args(data, args)
4171 }
4172}
4173
4174#[cfg(feature = "experimental_traverse")]
4175impl<'a> SomeRecord<'a> for Mark2Record<'a> {
4176 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
4177 RecordResolver {
4178 name: "Mark2Record",
4179 get_field: Box::new(move |idx, _data| match idx {
4180 0usize => Some(Field::new(
4181 "mark2_anchor_offsets",
4182 FieldType::from(self.mark2_anchors(_data)),
4183 )),
4184 _ => None,
4185 }),
4186 data,
4187 }
4188 }
4189}
4190
4191impl Format<u16> for ExtensionPosFormat1<'_> {
4192 const FORMAT: u16 = 1;
4193}
4194
4195impl Discriminant for ExtensionPosFormat1<'_, ()> {
4196 fn read_discriminant(data: FontData<'_>) -> Result<u16, ReadError> {
4197 data.read_at(u16::RAW_BYTE_LEN)
4198 }
4199}
4200
4201impl<'a, T> MinByteRange<'a> for ExtensionPosFormat1<'a, T> {
4202 fn min_byte_range(&self) -> Range<usize> {
4203 0..self.extension_offset_byte_range().end
4204 }
4205 fn min_table_bytes(&self) -> &'a [u8] {
4206 let range = self.min_byte_range();
4207 self.data.as_bytes().get(range).unwrap_or_default()
4208 }
4209}
4210
4211impl<T> ReadArgs for ExtensionPosFormat1<'_, T> {
4212 type Args = ();
4213}
4214
4215impl<'a, T> FontRead<'a> for ExtensionPosFormat1<'a, T> {
4216 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4217 #[allow(clippy::absurd_extreme_comparisons)]
4218 if data.len() < Self::MIN_SIZE {
4219 return Err(ReadError::OutOfBounds);
4220 }
4221 Ok(Self {
4222 data,
4223 offset_type: std::marker::PhantomData,
4224 })
4225 }
4226}
4227
4228impl<'a, T> ExtensionPosFormat1<'a, T> {
4229 #[allow(dead_code)]
4230 pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
4232 ExtensionPosFormat1 {
4233 data: self.data,
4234 offset_type: std::marker::PhantomData,
4235 }
4236 }
4237}
4238
4239#[derive(Clone)]
4241pub struct ExtensionPosFormat1<'a, T = ()> {
4242 data: FontData<'a>,
4243 offset_type: std::marker::PhantomData<*const T>,
4244}
4245
4246#[allow(clippy::needless_lifetimes)]
4247impl<'a, T> ExtensionPosFormat1<'a, T> {
4248 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN);
4249 basic_table_impls!(impl_the_methods);
4250
4251 pub fn pos_format(&self) -> u16 {
4253 let range = self.pos_format_byte_range();
4254 self.data.read_at(range.start).ok().unwrap()
4255 }
4256
4257 pub fn extension_lookup_type(&self) -> u16 {
4260 let range = self.extension_lookup_type_byte_range();
4261 self.data.read_at(range.start).ok().unwrap()
4262 }
4263
4264 pub fn extension_offset(&self) -> Offset32 {
4268 let range = self.extension_offset_byte_range();
4269 self.data.read_at(range.start).ok().unwrap()
4270 }
4271
4272 pub fn extension(&self) -> Result<T, ReadError>
4274 where
4275 T: FontRead<'a, Args = ()>,
4276 {
4277 let data = self.data;
4278 self.extension_offset().resolve(data)
4279 }
4280
4281 pub fn pos_format_byte_range(&self) -> Range<usize> {
4282 let start = 0;
4283 let end = start + u16::RAW_BYTE_LEN;
4284 start..end
4285 }
4286
4287 pub fn extension_lookup_type_byte_range(&self) -> Range<usize> {
4288 let start = self.pos_format_byte_range().end;
4289 let end = start + u16::RAW_BYTE_LEN;
4290 start..end
4291 }
4292
4293 pub fn extension_offset_byte_range(&self) -> Range<usize> {
4294 let start = self.extension_lookup_type_byte_range().end;
4295 let end = start + Offset32::RAW_BYTE_LEN;
4296 start..end
4297 }
4298}
4299
4300const _: () = assert!(FontData::default_data_long_enough(
4301 ExtensionPosFormat1::<()>::MIN_SIZE
4302));
4303
4304impl<T> Default for ExtensionPosFormat1<'_, T> {
4305 fn default() -> Self {
4306 Self {
4307 data: FontData::default_format_1_u16_table_data(),
4308 offset_type: std::marker::PhantomData,
4309 }
4310 }
4311}
4312
4313#[cfg(feature = "experimental_traverse")]
4314impl<'a, T: FontRead<'a, Args = ()> + SomeTable<'a> + 'a> SomeTable<'a>
4315 for ExtensionPosFormat1<'a, T>
4316{
4317 fn type_name(&self) -> &str {
4318 "ExtensionPosFormat1"
4319 }
4320 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4321 match idx {
4322 0usize => Some(Field::new("pos_format", self.pos_format())),
4323 1usize => Some(Field::new(
4324 "extension_lookup_type",
4325 self.extension_lookup_type(),
4326 )),
4327 2usize => Some(Field::new(
4328 "extension_offset",
4329 FieldType::offset(self.extension_offset(), self.extension()),
4330 )),
4331 _ => None,
4332 }
4333 }
4334}
4335
4336#[cfg(feature = "experimental_traverse")]
4337#[allow(clippy::needless_lifetimes)]
4338impl<'a, T: FontRead<'a, Args = ()> + SomeTable<'a> + 'a> std::fmt::Debug
4339 for ExtensionPosFormat1<'a, T>
4340{
4341 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4342 (self as &dyn SomeTable<'a>).fmt(f)
4343 }
4344}
4345
4346pub enum ExtensionSubtable<'a> {
4348 Single(ExtensionPosFormat1<'a, SinglePos<'a>>),
4349 Pair(ExtensionPosFormat1<'a, PairPos<'a>>),
4350 Cursive(ExtensionPosFormat1<'a, CursivePosFormat1<'a>>),
4351 MarkToBase(ExtensionPosFormat1<'a, MarkBasePosFormat1<'a>>),
4352 MarkToLig(ExtensionPosFormat1<'a, MarkLigPosFormat1<'a>>),
4353 MarkToMark(ExtensionPosFormat1<'a, MarkMarkPosFormat1<'a>>),
4354 Contextual(ExtensionPosFormat1<'a, PositionSequenceContext<'a>>),
4355 ChainContextual(ExtensionPosFormat1<'a, PositionChainContext<'a>>),
4356}
4357
4358impl Default for ExtensionSubtable<'_> {
4359 fn default() -> Self {
4360 Self::Single(Default::default())
4361 }
4362}
4363
4364impl ReadArgs for ExtensionSubtable<'_> {
4365 type Args = ();
4366}
4367
4368impl<'a> FontRead<'a> for ExtensionSubtable<'a> {
4369 fn read_with_args(bytes: FontData<'a>, _: ()) -> Result<Self, ReadError> {
4370 let discriminant = ExtensionPosFormat1::read_discriminant(bytes)?;
4371 match discriminant {
4372 1 => Ok(ExtensionSubtable::Single(FontRead::read(bytes)?)),
4373 2 => Ok(ExtensionSubtable::Pair(FontRead::read(bytes)?)),
4374 3 => Ok(ExtensionSubtable::Cursive(FontRead::read(bytes)?)),
4375 4 => Ok(ExtensionSubtable::MarkToBase(FontRead::read(bytes)?)),
4376 5 => Ok(ExtensionSubtable::MarkToLig(FontRead::read(bytes)?)),
4377 6 => Ok(ExtensionSubtable::MarkToMark(FontRead::read(bytes)?)),
4378 7 => Ok(ExtensionSubtable::Contextual(FontRead::read(bytes)?)),
4379 8 => Ok(ExtensionSubtable::ChainContextual(FontRead::read(bytes)?)),
4380 other => Err(ReadError::InvalidFormat(other.into())),
4381 }
4382 }
4383}
4384
4385impl<'a> ExtensionSubtable<'a> {
4386 #[allow(dead_code)]
4387 pub(crate) fn of_unit_type(&self) -> ExtensionPosFormat1<'a, ()> {
4391 match self {
4392 ExtensionSubtable::Single(inner) => inner.of_unit_type(),
4393 ExtensionSubtable::Pair(inner) => inner.of_unit_type(),
4394 ExtensionSubtable::Cursive(inner) => inner.of_unit_type(),
4395 ExtensionSubtable::MarkToBase(inner) => inner.of_unit_type(),
4396 ExtensionSubtable::MarkToLig(inner) => inner.of_unit_type(),
4397 ExtensionSubtable::MarkToMark(inner) => inner.of_unit_type(),
4398 ExtensionSubtable::Contextual(inner) => inner.of_unit_type(),
4399 ExtensionSubtable::ChainContextual(inner) => inner.of_unit_type(),
4400 }
4401 }
4402}
4403
4404#[cfg(feature = "experimental_traverse")]
4405impl<'a> ExtensionSubtable<'a> {
4406 fn dyn_inner(&self) -> &(dyn SomeTable<'a> + 'a) {
4407 match self {
4408 ExtensionSubtable::Single(table) => table,
4409 ExtensionSubtable::Pair(table) => table,
4410 ExtensionSubtable::Cursive(table) => table,
4411 ExtensionSubtable::MarkToBase(table) => table,
4412 ExtensionSubtable::MarkToLig(table) => table,
4413 ExtensionSubtable::MarkToMark(table) => table,
4414 ExtensionSubtable::Contextual(table) => table,
4415 ExtensionSubtable::ChainContextual(table) => table,
4416 }
4417 }
4418}
4419
4420#[cfg(feature = "experimental_traverse")]
4421impl<'a> SomeTable<'a> for ExtensionSubtable<'a> {
4422 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
4423 self.dyn_inner().get_field(idx)
4424 }
4425 fn type_name(&self) -> &str {
4426 self.dyn_inner().type_name()
4427 }
4428}
4429
4430#[cfg(feature = "experimental_traverse")]
4431impl std::fmt::Debug for ExtensionSubtable<'_> {
4432 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4433 self.dyn_inner().fmt(f)
4434 }
4435}