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