1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8#[derive(Clone)]
11pub enum Lookup<'a> {
12 Format0(Lookup0<'a>),
13 Format2(Lookup2<'a>),
14 Format4(Lookup4<'a>),
15 Format6(Lookup6<'a>),
16 Format8(Lookup8<'a>),
17 Format10(Lookup10<'a>),
18}
19
20impl Default for Lookup<'_> {
21 fn default() -> Self {
22 Self::Format0(Default::default())
23 }
24}
25
26impl<'a> Lookup<'a> {
27 pub fn offset_data(&self) -> FontData<'a> {
29 match self {
30 Self::Format0(item) => item.offset_data(),
31 Self::Format2(item) => item.offset_data(),
32 Self::Format4(item) => item.offset_data(),
33 Self::Format6(item) => item.offset_data(),
34 Self::Format8(item) => item.offset_data(),
35 Self::Format10(item) => item.offset_data(),
36 }
37 }
38
39 pub fn format(&self) -> u16 {
41 match self {
42 Self::Format0(item) => item.format(),
43 Self::Format2(item) => item.format(),
44 Self::Format4(item) => item.format(),
45 Self::Format6(item) => item.format(),
46 Self::Format8(item) => item.format(),
47 Self::Format10(item) => item.format(),
48 }
49 }
50}
51
52impl ReadArgs for Lookup<'_> {
53 type Args = ();
54}
55
56impl<'a> FontRead<'a> for Lookup<'a> {
57 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
58 let format: u16 = data.read_at(0usize)?;
59 match format {
60 Lookup0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
61 Lookup2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
62 Lookup4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
63 Lookup6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
64 Lookup8::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
65 Lookup10::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
66 other => Err(ReadError::InvalidFormat(other.into())),
67 }
68 }
69}
70
71impl<'a> MinByteRange<'a> for Lookup<'a> {
72 fn min_byte_range(&self) -> Range<usize> {
73 match self {
74 Self::Format0(item) => item.min_byte_range(),
75 Self::Format2(item) => item.min_byte_range(),
76 Self::Format4(item) => item.min_byte_range(),
77 Self::Format6(item) => item.min_byte_range(),
78 Self::Format8(item) => item.min_byte_range(),
79 Self::Format10(item) => item.min_byte_range(),
80 }
81 }
82 fn min_table_bytes(&self) -> &'a [u8] {
83 match self {
84 Self::Format0(item) => item.min_table_bytes(),
85 Self::Format2(item) => item.min_table_bytes(),
86 Self::Format4(item) => item.min_table_bytes(),
87 Self::Format6(item) => item.min_table_bytes(),
88 Self::Format8(item) => item.min_table_bytes(),
89 Self::Format10(item) => item.min_table_bytes(),
90 }
91 }
92}
93
94#[cfg(feature = "experimental_traverse")]
95impl<'a> Lookup<'a> {
96 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
97 match self {
98 Self::Format0(table) => table,
99 Self::Format2(table) => table,
100 Self::Format4(table) => table,
101 Self::Format6(table) => table,
102 Self::Format8(table) => table,
103 Self::Format10(table) => table,
104 }
105 }
106}
107
108#[cfg(feature = "experimental_traverse")]
109impl std::fmt::Debug for Lookup<'_> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 self.dyn_inner().fmt(f)
112 }
113}
114
115#[cfg(feature = "experimental_traverse")]
116impl<'a> SomeTable<'a> for Lookup<'a> {
117 fn type_name(&self) -> &str {
118 self.dyn_inner().type_name()
119 }
120 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
121 self.dyn_inner().get_field(idx)
122 }
123}
124
125impl Format<u16> for Lookup0<'_> {
126 const FORMAT: u16 = 0;
127}
128
129impl<'a> MinByteRange<'a> for Lookup0<'a> {
130 fn min_byte_range(&self) -> Range<usize> {
131 0..self.values_data_byte_range().end
132 }
133 fn min_table_bytes(&self) -> &'a [u8] {
134 let range = self.min_byte_range();
135 self.data.as_bytes().get(range).unwrap_or_default()
136 }
137}
138
139impl ReadArgs for Lookup0<'_> {
140 type Args = ();
141}
142
143impl<'a> FontRead<'a> for Lookup0<'a> {
144 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
145 #[allow(clippy::absurd_extreme_comparisons)]
146 if data.len() < Self::MIN_SIZE {
147 return Err(ReadError::OutOfBounds);
148 }
149 Ok(Self { data })
150 }
151}
152
153#[derive(Clone)]
156pub struct Lookup0<'a> {
157 data: FontData<'a>,
158}
159
160#[allow(clippy::needless_lifetimes)]
161impl<'a> Lookup0<'a> {
162 pub const MIN_SIZE: usize = u16::RAW_BYTE_LEN;
163 basic_table_impls!(impl_the_methods);
164
165 pub fn format(&self) -> u16 {
167 let range = self.format_byte_range();
168 self.data.read_at(range.start).ok().unwrap()
169 }
170
171 pub fn values_data(&self) -> &'a [u8] {
173 let range = self.values_data_byte_range();
174 self.data.read_array(range).ok().unwrap_or_default()
175 }
176
177 pub fn format_byte_range(&self) -> Range<usize> {
178 let start = 0;
179 let end = start + u16::RAW_BYTE_LEN;
180 start..end
181 }
182
183 pub fn values_data_byte_range(&self) -> Range<usize> {
184 let start = self.format_byte_range().end;
185 let end =
186 start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
187 start..end
188 }
189}
190
191const _: () = assert!(FontData::default_data_long_enough(Lookup0::MIN_SIZE));
192
193impl Default for Lookup0<'_> {
194 fn default() -> Self {
195 Self {
196 data: FontData::default_table_data(),
197 }
198 }
199}
200
201#[cfg(feature = "experimental_traverse")]
202impl<'a> SomeTable<'a> for Lookup0<'a> {
203 fn type_name(&self) -> &str {
204 "Lookup0"
205 }
206 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
207 match idx {
208 0usize => Some(Field::new("format", self.format())),
209 1usize => Some(Field::new("values_data", self.values_data())),
210 _ => None,
211 }
212 }
213}
214
215#[cfg(feature = "experimental_traverse")]
216#[allow(clippy::needless_lifetimes)]
217impl<'a> std::fmt::Debug for Lookup0<'a> {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 (self as &dyn SomeTable<'a>).fmt(f)
220 }
221}
222
223impl Format<u16> for Lookup2<'_> {
224 const FORMAT: u16 = 2;
225}
226
227impl<'a> MinByteRange<'a> for Lookup2<'a> {
228 fn min_byte_range(&self) -> Range<usize> {
229 0..self.segments_data_byte_range().end
230 }
231 fn min_table_bytes(&self) -> &'a [u8] {
232 let range = self.min_byte_range();
233 self.data.as_bytes().get(range).unwrap_or_default()
234 }
235}
236
237impl ReadArgs for Lookup2<'_> {
238 type Args = ();
239}
240
241impl<'a> FontRead<'a> for Lookup2<'a> {
242 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
243 #[allow(clippy::absurd_extreme_comparisons)]
244 if data.len() < Self::MIN_SIZE {
245 return Err(ReadError::OutOfBounds);
246 }
247 Ok(Self { data })
248 }
249}
250
251#[derive(Clone)]
255pub struct Lookup2<'a> {
256 data: FontData<'a>,
257}
258
259#[allow(clippy::needless_lifetimes)]
260impl<'a> Lookup2<'a> {
261 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
262 + u16::RAW_BYTE_LEN
263 + u16::RAW_BYTE_LEN
264 + u16::RAW_BYTE_LEN
265 + u16::RAW_BYTE_LEN
266 + u16::RAW_BYTE_LEN);
267 basic_table_impls!(impl_the_methods);
268
269 pub fn format(&self) -> u16 {
271 let range = self.format_byte_range();
272 self.data.read_at(range.start).ok().unwrap()
273 }
274
275 pub fn unit_size(&self) -> u16 {
277 let range = self.unit_size_byte_range();
278 self.data.read_at(range.start).ok().unwrap()
279 }
280
281 pub fn n_units(&self) -> u16 {
283 let range = self.n_units_byte_range();
284 self.data.read_at(range.start).ok().unwrap()
285 }
286
287 pub fn search_range(&self) -> u16 {
289 let range = self.search_range_byte_range();
290 self.data.read_at(range.start).ok().unwrap()
291 }
292
293 pub fn entry_selector(&self) -> u16 {
295 let range = self.entry_selector_byte_range();
296 self.data.read_at(range.start).ok().unwrap()
297 }
298
299 pub fn range_shift(&self) -> u16 {
301 let range = self.range_shift_byte_range();
302 self.data.read_at(range.start).ok().unwrap()
303 }
304
305 pub fn segments_data(&self) -> &'a [u8] {
307 let range = self.segments_data_byte_range();
308 self.data.read_array(range).ok().unwrap_or_default()
309 }
310
311 pub fn format_byte_range(&self) -> Range<usize> {
312 let start = 0;
313 let end = start + u16::RAW_BYTE_LEN;
314 start..end
315 }
316
317 pub fn unit_size_byte_range(&self) -> Range<usize> {
318 let start = self.format_byte_range().end;
319 let end = start + u16::RAW_BYTE_LEN;
320 start..end
321 }
322
323 pub fn n_units_byte_range(&self) -> Range<usize> {
324 let start = self.unit_size_byte_range().end;
325 let end = start + u16::RAW_BYTE_LEN;
326 start..end
327 }
328
329 pub fn search_range_byte_range(&self) -> Range<usize> {
330 let start = self.n_units_byte_range().end;
331 let end = start + u16::RAW_BYTE_LEN;
332 start..end
333 }
334
335 pub fn entry_selector_byte_range(&self) -> Range<usize> {
336 let start = self.search_range_byte_range().end;
337 let end = start + u16::RAW_BYTE_LEN;
338 start..end
339 }
340
341 pub fn range_shift_byte_range(&self) -> Range<usize> {
342 let start = self.entry_selector_byte_range().end;
343 let end = start + u16::RAW_BYTE_LEN;
344 start..end
345 }
346
347 pub fn segments_data_byte_range(&self) -> Range<usize> {
348 let unit_size = self.unit_size();
349 let n_units = self.n_units();
350 let start = self.range_shift_byte_range().end;
351 let end = start
352 + (transforms::add_multiply(unit_size, 0_usize, n_units))
353 .saturating_mul(u8::RAW_BYTE_LEN);
354 start..end
355 }
356}
357
358#[cfg(feature = "experimental_traverse")]
359impl<'a> SomeTable<'a> for Lookup2<'a> {
360 fn type_name(&self) -> &str {
361 "Lookup2"
362 }
363 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
364 match idx {
365 0usize => Some(Field::new("format", self.format())),
366 1usize => Some(Field::new("unit_size", self.unit_size())),
367 2usize => Some(Field::new("n_units", self.n_units())),
368 3usize => Some(Field::new("search_range", self.search_range())),
369 4usize => Some(Field::new("entry_selector", self.entry_selector())),
370 5usize => Some(Field::new("range_shift", self.range_shift())),
371 6usize => Some(Field::new("segments_data", self.segments_data())),
372 _ => None,
373 }
374 }
375}
376
377#[cfg(feature = "experimental_traverse")]
378#[allow(clippy::needless_lifetimes)]
379impl<'a> std::fmt::Debug for Lookup2<'a> {
380 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
381 (self as &dyn SomeTable<'a>).fmt(f)
382 }
383}
384
385impl Format<u16> for Lookup4<'_> {
386 const FORMAT: u16 = 4;
387}
388
389impl<'a> MinByteRange<'a> for Lookup4<'a> {
390 fn min_byte_range(&self) -> Range<usize> {
391 0..self.segments_byte_range().end
392 }
393 fn min_table_bytes(&self) -> &'a [u8] {
394 let range = self.min_byte_range();
395 self.data.as_bytes().get(range).unwrap_or_default()
396 }
397}
398
399impl ReadArgs for Lookup4<'_> {
400 type Args = ();
401}
402
403impl<'a> FontRead<'a> for Lookup4<'a> {
404 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
405 #[allow(clippy::absurd_extreme_comparisons)]
406 if data.len() < Self::MIN_SIZE {
407 return Err(ReadError::OutOfBounds);
408 }
409 Ok(Self { data })
410 }
411}
412
413#[derive(Clone)]
417pub struct Lookup4<'a> {
418 data: FontData<'a>,
419}
420
421#[allow(clippy::needless_lifetimes)]
422impl<'a> Lookup4<'a> {
423 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
424 + u16::RAW_BYTE_LEN
425 + u16::RAW_BYTE_LEN
426 + u16::RAW_BYTE_LEN
427 + u16::RAW_BYTE_LEN
428 + u16::RAW_BYTE_LEN);
429 basic_table_impls!(impl_the_methods);
430
431 pub fn format(&self) -> u16 {
433 let range = self.format_byte_range();
434 self.data.read_at(range.start).ok().unwrap()
435 }
436
437 pub fn unit_size(&self) -> u16 {
439 let range = self.unit_size_byte_range();
440 self.data.read_at(range.start).ok().unwrap()
441 }
442
443 pub fn n_units(&self) -> u16 {
445 let range = self.n_units_byte_range();
446 self.data.read_at(range.start).ok().unwrap()
447 }
448
449 pub fn search_range(&self) -> u16 {
451 let range = self.search_range_byte_range();
452 self.data.read_at(range.start).ok().unwrap()
453 }
454
455 pub fn entry_selector(&self) -> u16 {
457 let range = self.entry_selector_byte_range();
458 self.data.read_at(range.start).ok().unwrap()
459 }
460
461 pub fn range_shift(&self) -> u16 {
463 let range = self.range_shift_byte_range();
464 self.data.read_at(range.start).ok().unwrap()
465 }
466
467 pub fn segments(&self) -> &'a [LookupSegment4] {
469 let range = self.segments_byte_range();
470 self.data.read_array(range).ok().unwrap_or_default()
471 }
472
473 pub fn format_byte_range(&self) -> Range<usize> {
474 let start = 0;
475 let end = start + u16::RAW_BYTE_LEN;
476 start..end
477 }
478
479 pub fn unit_size_byte_range(&self) -> Range<usize> {
480 let start = self.format_byte_range().end;
481 let end = start + u16::RAW_BYTE_LEN;
482 start..end
483 }
484
485 pub fn n_units_byte_range(&self) -> Range<usize> {
486 let start = self.unit_size_byte_range().end;
487 let end = start + u16::RAW_BYTE_LEN;
488 start..end
489 }
490
491 pub fn search_range_byte_range(&self) -> Range<usize> {
492 let start = self.n_units_byte_range().end;
493 let end = start + u16::RAW_BYTE_LEN;
494 start..end
495 }
496
497 pub fn entry_selector_byte_range(&self) -> Range<usize> {
498 let start = self.search_range_byte_range().end;
499 let end = start + u16::RAW_BYTE_LEN;
500 start..end
501 }
502
503 pub fn range_shift_byte_range(&self) -> Range<usize> {
504 let start = self.entry_selector_byte_range().end;
505 let end = start + u16::RAW_BYTE_LEN;
506 start..end
507 }
508
509 pub fn segments_byte_range(&self) -> Range<usize> {
510 let n_units = self.n_units();
511 let start = self.range_shift_byte_range().end;
512 let end =
513 start + (transforms::to_usize(n_units)).saturating_mul(LookupSegment4::RAW_BYTE_LEN);
514 start..end
515 }
516}
517
518#[cfg(feature = "experimental_traverse")]
519impl<'a> SomeTable<'a> for Lookup4<'a> {
520 fn type_name(&self) -> &str {
521 "Lookup4"
522 }
523 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
524 match idx {
525 0usize => Some(Field::new("format", self.format())),
526 1usize => Some(Field::new("unit_size", self.unit_size())),
527 2usize => Some(Field::new("n_units", self.n_units())),
528 3usize => Some(Field::new("search_range", self.search_range())),
529 4usize => Some(Field::new("entry_selector", self.entry_selector())),
530 5usize => Some(Field::new("range_shift", self.range_shift())),
531 6usize => Some(Field::new(
532 "segments",
533 traversal::FieldType::array_of_records(
534 stringify!(LookupSegment4),
535 self.segments(),
536 self.offset_data(),
537 ),
538 )),
539 _ => None,
540 }
541 }
542}
543
544#[cfg(feature = "experimental_traverse")]
545#[allow(clippy::needless_lifetimes)]
546impl<'a> std::fmt::Debug for Lookup4<'a> {
547 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
548 (self as &dyn SomeTable<'a>).fmt(f)
549 }
550}
551
552#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
554#[repr(C)]
555#[repr(packed)]
556pub struct LookupSegment4 {
557 pub last_glyph: BigEndian<u16>,
559 pub first_glyph: BigEndian<u16>,
561 pub value_offset: BigEndian<u16>,
563}
564
565impl LookupSegment4 {
566 pub fn last_glyph(&self) -> u16 {
568 self.last_glyph.get()
569 }
570
571 pub fn first_glyph(&self) -> u16 {
573 self.first_glyph.get()
574 }
575
576 pub fn value_offset(&self) -> u16 {
578 self.value_offset.get()
579 }
580}
581
582impl FixedSize for LookupSegment4 {
583 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
584}
585
586#[cfg(feature = "experimental_traverse")]
587impl<'a> SomeRecord<'a> for LookupSegment4 {
588 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
589 RecordResolver {
590 name: "LookupSegment4",
591 get_field: Box::new(move |idx, _data| match idx {
592 0usize => Some(Field::new("last_glyph", self.last_glyph())),
593 1usize => Some(Field::new("first_glyph", self.first_glyph())),
594 2usize => Some(Field::new("value_offset", self.value_offset())),
595 _ => None,
596 }),
597 data,
598 }
599 }
600}
601
602impl Format<u16> for Lookup6<'_> {
603 const FORMAT: u16 = 6;
604}
605
606impl<'a> MinByteRange<'a> for Lookup6<'a> {
607 fn min_byte_range(&self) -> Range<usize> {
608 0..self.entries_data_byte_range().end
609 }
610 fn min_table_bytes(&self) -> &'a [u8] {
611 let range = self.min_byte_range();
612 self.data.as_bytes().get(range).unwrap_or_default()
613 }
614}
615
616impl ReadArgs for Lookup6<'_> {
617 type Args = ();
618}
619
620impl<'a> FontRead<'a> for Lookup6<'a> {
621 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
622 #[allow(clippy::absurd_extreme_comparisons)]
623 if data.len() < Self::MIN_SIZE {
624 return Err(ReadError::OutOfBounds);
625 }
626 Ok(Self { data })
627 }
628}
629
630#[derive(Clone)]
633pub struct Lookup6<'a> {
634 data: FontData<'a>,
635}
636
637#[allow(clippy::needless_lifetimes)]
638impl<'a> Lookup6<'a> {
639 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
640 + u16::RAW_BYTE_LEN
641 + u16::RAW_BYTE_LEN
642 + u16::RAW_BYTE_LEN
643 + u16::RAW_BYTE_LEN
644 + u16::RAW_BYTE_LEN);
645 basic_table_impls!(impl_the_methods);
646
647 pub fn format(&self) -> u16 {
649 let range = self.format_byte_range();
650 self.data.read_at(range.start).ok().unwrap()
651 }
652
653 pub fn unit_size(&self) -> u16 {
655 let range = self.unit_size_byte_range();
656 self.data.read_at(range.start).ok().unwrap()
657 }
658
659 pub fn n_units(&self) -> u16 {
661 let range = self.n_units_byte_range();
662 self.data.read_at(range.start).ok().unwrap()
663 }
664
665 pub fn search_range(&self) -> u16 {
667 let range = self.search_range_byte_range();
668 self.data.read_at(range.start).ok().unwrap()
669 }
670
671 pub fn entry_selector(&self) -> u16 {
673 let range = self.entry_selector_byte_range();
674 self.data.read_at(range.start).ok().unwrap()
675 }
676
677 pub fn range_shift(&self) -> u16 {
679 let range = self.range_shift_byte_range();
680 self.data.read_at(range.start).ok().unwrap()
681 }
682
683 pub fn entries_data(&self) -> &'a [u8] {
685 let range = self.entries_data_byte_range();
686 self.data.read_array(range).ok().unwrap_or_default()
687 }
688
689 pub fn format_byte_range(&self) -> Range<usize> {
690 let start = 0;
691 let end = start + u16::RAW_BYTE_LEN;
692 start..end
693 }
694
695 pub fn unit_size_byte_range(&self) -> Range<usize> {
696 let start = self.format_byte_range().end;
697 let end = start + u16::RAW_BYTE_LEN;
698 start..end
699 }
700
701 pub fn n_units_byte_range(&self) -> Range<usize> {
702 let start = self.unit_size_byte_range().end;
703 let end = start + u16::RAW_BYTE_LEN;
704 start..end
705 }
706
707 pub fn search_range_byte_range(&self) -> Range<usize> {
708 let start = self.n_units_byte_range().end;
709 let end = start + u16::RAW_BYTE_LEN;
710 start..end
711 }
712
713 pub fn entry_selector_byte_range(&self) -> Range<usize> {
714 let start = self.search_range_byte_range().end;
715 let end = start + u16::RAW_BYTE_LEN;
716 start..end
717 }
718
719 pub fn range_shift_byte_range(&self) -> Range<usize> {
720 let start = self.entry_selector_byte_range().end;
721 let end = start + u16::RAW_BYTE_LEN;
722 start..end
723 }
724
725 pub fn entries_data_byte_range(&self) -> Range<usize> {
726 let unit_size = self.unit_size();
727 let n_units = self.n_units();
728 let start = self.range_shift_byte_range().end;
729 let end = start
730 + (transforms::add_multiply(unit_size, 0_usize, n_units))
731 .saturating_mul(u8::RAW_BYTE_LEN);
732 start..end
733 }
734}
735
736#[cfg(feature = "experimental_traverse")]
737impl<'a> SomeTable<'a> for Lookup6<'a> {
738 fn type_name(&self) -> &str {
739 "Lookup6"
740 }
741 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
742 match idx {
743 0usize => Some(Field::new("format", self.format())),
744 1usize => Some(Field::new("unit_size", self.unit_size())),
745 2usize => Some(Field::new("n_units", self.n_units())),
746 3usize => Some(Field::new("search_range", self.search_range())),
747 4usize => Some(Field::new("entry_selector", self.entry_selector())),
748 5usize => Some(Field::new("range_shift", self.range_shift())),
749 6usize => Some(Field::new("entries_data", self.entries_data())),
750 _ => None,
751 }
752 }
753}
754
755#[cfg(feature = "experimental_traverse")]
756#[allow(clippy::needless_lifetimes)]
757impl<'a> std::fmt::Debug for Lookup6<'a> {
758 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
759 (self as &dyn SomeTable<'a>).fmt(f)
760 }
761}
762
763impl Format<u16> for Lookup8<'_> {
764 const FORMAT: u16 = 8;
765}
766
767impl<'a> MinByteRange<'a> for Lookup8<'a> {
768 fn min_byte_range(&self) -> Range<usize> {
769 0..self.value_array_byte_range().end
770 }
771 fn min_table_bytes(&self) -> &'a [u8] {
772 let range = self.min_byte_range();
773 self.data.as_bytes().get(range).unwrap_or_default()
774 }
775}
776
777impl ReadArgs for Lookup8<'_> {
778 type Args = ();
779}
780
781impl<'a> FontRead<'a> for Lookup8<'a> {
782 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
783 #[allow(clippy::absurd_extreme_comparisons)]
784 if data.len() < Self::MIN_SIZE {
785 return Err(ReadError::OutOfBounds);
786 }
787 Ok(Self { data })
788 }
789}
790
791#[derive(Clone)]
794pub struct Lookup8<'a> {
795 data: FontData<'a>,
796}
797
798#[allow(clippy::needless_lifetimes)]
799impl<'a> Lookup8<'a> {
800 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
801 basic_table_impls!(impl_the_methods);
802
803 pub fn format(&self) -> u16 {
805 let range = self.format_byte_range();
806 self.data.read_at(range.start).ok().unwrap()
807 }
808
809 pub fn first_glyph(&self) -> u16 {
811 let range = self.first_glyph_byte_range();
812 self.data.read_at(range.start).ok().unwrap()
813 }
814
815 pub fn glyph_count(&self) -> u16 {
818 let range = self.glyph_count_byte_range();
819 self.data.read_at(range.start).ok().unwrap()
820 }
821
822 pub fn value_array(&self) -> &'a [BigEndian<u16>] {
825 let range = self.value_array_byte_range();
826 self.data.read_array(range).ok().unwrap_or_default()
827 }
828
829 pub fn format_byte_range(&self) -> Range<usize> {
830 let start = 0;
831 let end = start + u16::RAW_BYTE_LEN;
832 start..end
833 }
834
835 pub fn first_glyph_byte_range(&self) -> Range<usize> {
836 let start = self.format_byte_range().end;
837 let end = start + u16::RAW_BYTE_LEN;
838 start..end
839 }
840
841 pub fn glyph_count_byte_range(&self) -> Range<usize> {
842 let start = self.first_glyph_byte_range().end;
843 let end = start + u16::RAW_BYTE_LEN;
844 start..end
845 }
846
847 pub fn value_array_byte_range(&self) -> Range<usize> {
848 let glyph_count = self.glyph_count();
849 let start = self.glyph_count_byte_range().end;
850 let end = start + (transforms::to_usize(glyph_count)).saturating_mul(u16::RAW_BYTE_LEN);
851 start..end
852 }
853}
854
855#[cfg(feature = "experimental_traverse")]
856impl<'a> SomeTable<'a> for Lookup8<'a> {
857 fn type_name(&self) -> &str {
858 "Lookup8"
859 }
860 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
861 match idx {
862 0usize => Some(Field::new("format", self.format())),
863 1usize => Some(Field::new("first_glyph", self.first_glyph())),
864 2usize => Some(Field::new("glyph_count", self.glyph_count())),
865 3usize => Some(Field::new("value_array", self.value_array())),
866 _ => None,
867 }
868 }
869}
870
871#[cfg(feature = "experimental_traverse")]
872#[allow(clippy::needless_lifetimes)]
873impl<'a> std::fmt::Debug for Lookup8<'a> {
874 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
875 (self as &dyn SomeTable<'a>).fmt(f)
876 }
877}
878
879impl Format<u16> for Lookup10<'_> {
880 const FORMAT: u16 = 10;
881}
882
883impl<'a> MinByteRange<'a> for Lookup10<'a> {
884 fn min_byte_range(&self) -> Range<usize> {
885 0..self.values_data_byte_range().end
886 }
887 fn min_table_bytes(&self) -> &'a [u8] {
888 let range = self.min_byte_range();
889 self.data.as_bytes().get(range).unwrap_or_default()
890 }
891}
892
893impl ReadArgs for Lookup10<'_> {
894 type Args = ();
895}
896
897impl<'a> FontRead<'a> for Lookup10<'a> {
898 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
899 #[allow(clippy::absurd_extreme_comparisons)]
900 if data.len() < Self::MIN_SIZE {
901 return Err(ReadError::OutOfBounds);
902 }
903 Ok(Self { data })
904 }
905}
906
907#[derive(Clone)]
910pub struct Lookup10<'a> {
911 data: FontData<'a>,
912}
913
914#[allow(clippy::needless_lifetimes)]
915impl<'a> Lookup10<'a> {
916 pub const MIN_SIZE: usize =
917 (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
918 basic_table_impls!(impl_the_methods);
919
920 pub fn format(&self) -> u16 {
922 let range = self.format_byte_range();
923 self.data.read_at(range.start).ok().unwrap()
924 }
925
926 pub fn unit_size(&self) -> u16 {
929 let range = self.unit_size_byte_range();
930 self.data.read_at(range.start).ok().unwrap()
931 }
932
933 pub fn first_glyph(&self) -> u16 {
935 let range = self.first_glyph_byte_range();
936 self.data.read_at(range.start).ok().unwrap()
937 }
938
939 pub fn glyph_count(&self) -> u16 {
942 let range = self.glyph_count_byte_range();
943 self.data.read_at(range.start).ok().unwrap()
944 }
945
946 pub fn values_data(&self) -> &'a [u8] {
949 let range = self.values_data_byte_range();
950 self.data.read_array(range).ok().unwrap_or_default()
951 }
952
953 pub fn format_byte_range(&self) -> Range<usize> {
954 let start = 0;
955 let end = start + u16::RAW_BYTE_LEN;
956 start..end
957 }
958
959 pub fn unit_size_byte_range(&self) -> Range<usize> {
960 let start = self.format_byte_range().end;
961 let end = start + u16::RAW_BYTE_LEN;
962 start..end
963 }
964
965 pub fn first_glyph_byte_range(&self) -> Range<usize> {
966 let start = self.unit_size_byte_range().end;
967 let end = start + u16::RAW_BYTE_LEN;
968 start..end
969 }
970
971 pub fn glyph_count_byte_range(&self) -> Range<usize> {
972 let start = self.first_glyph_byte_range().end;
973 let end = start + u16::RAW_BYTE_LEN;
974 start..end
975 }
976
977 pub fn values_data_byte_range(&self) -> Range<usize> {
978 let glyph_count = self.glyph_count();
979 let unit_size = self.unit_size();
980 let start = self.glyph_count_byte_range().end;
981 let end = start
982 + (transforms::add_multiply(glyph_count, 0_usize, unit_size))
983 .saturating_mul(u8::RAW_BYTE_LEN);
984 start..end
985 }
986}
987
988#[cfg(feature = "experimental_traverse")]
989impl<'a> SomeTable<'a> for Lookup10<'a> {
990 fn type_name(&self) -> &str {
991 "Lookup10"
992 }
993 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
994 match idx {
995 0usize => Some(Field::new("format", self.format())),
996 1usize => Some(Field::new("unit_size", self.unit_size())),
997 2usize => Some(Field::new("first_glyph", self.first_glyph())),
998 3usize => Some(Field::new("glyph_count", self.glyph_count())),
999 4usize => Some(Field::new("values_data", self.values_data())),
1000 _ => None,
1001 }
1002 }
1003}
1004
1005#[cfg(feature = "experimental_traverse")]
1006#[allow(clippy::needless_lifetimes)]
1007impl<'a> std::fmt::Debug for Lookup10<'a> {
1008 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1009 (self as &dyn SomeTable<'a>).fmt(f)
1010 }
1011}
1012
1013impl<'a> MinByteRange<'a> for StateHeader<'a> {
1014 fn min_byte_range(&self) -> Range<usize> {
1015 0..self.entry_table_offset_byte_range().end
1016 }
1017 fn min_table_bytes(&self) -> &'a [u8] {
1018 let range = self.min_byte_range();
1019 self.data.as_bytes().get(range).unwrap_or_default()
1020 }
1021}
1022
1023impl ReadArgs for StateHeader<'_> {
1024 type Args = ();
1025}
1026
1027impl<'a> FontRead<'a> for StateHeader<'a> {
1028 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1029 #[allow(clippy::absurd_extreme_comparisons)]
1030 if data.len() < Self::MIN_SIZE {
1031 return Err(ReadError::OutOfBounds);
1032 }
1033 Ok(Self { data })
1034 }
1035}
1036
1037#[derive(Clone)]
1039pub struct StateHeader<'a> {
1040 data: FontData<'a>,
1041}
1042
1043#[allow(clippy::needless_lifetimes)]
1044impl<'a> StateHeader<'a> {
1045 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1046 + Offset16::RAW_BYTE_LEN
1047 + Offset16::RAW_BYTE_LEN
1048 + Offset16::RAW_BYTE_LEN);
1049 basic_table_impls!(impl_the_methods);
1050
1051 pub fn state_size(&self) -> u16 {
1054 let range = self.state_size_byte_range();
1055 self.data.read_at(range.start).ok().unwrap()
1056 }
1057
1058 pub fn class_table_offset(&self) -> Offset16 {
1060 let range = self.class_table_offset_byte_range();
1061 self.data.read_at(range.start).ok().unwrap()
1062 }
1063
1064 pub fn class_table(&self) -> Result<ClassSubtable<'a>, ReadError> {
1066 let data = self.data;
1067 self.class_table_offset().resolve(data)
1068 }
1069
1070 pub fn state_array_offset(&self) -> Offset16 {
1072 let range = self.state_array_offset_byte_range();
1073 self.data.read_at(range.start).ok().unwrap()
1074 }
1075
1076 pub fn state_array(&self) -> Result<RawBytes<'a>, ReadError> {
1078 let data = self.data;
1079 self.state_array_offset().resolve(data)
1080 }
1081
1082 pub fn entry_table_offset(&self) -> Offset16 {
1084 let range = self.entry_table_offset_byte_range();
1085 self.data.read_at(range.start).ok().unwrap()
1086 }
1087
1088 pub fn entry_table(&self) -> Result<RawBytes<'a>, ReadError> {
1090 let data = self.data;
1091 self.entry_table_offset().resolve(data)
1092 }
1093
1094 pub fn state_size_byte_range(&self) -> Range<usize> {
1095 let start = 0;
1096 let end = start + u16::RAW_BYTE_LEN;
1097 start..end
1098 }
1099
1100 pub fn class_table_offset_byte_range(&self) -> Range<usize> {
1101 let start = self.state_size_byte_range().end;
1102 let end = start + Offset16::RAW_BYTE_LEN;
1103 start..end
1104 }
1105
1106 pub fn state_array_offset_byte_range(&self) -> Range<usize> {
1107 let start = self.class_table_offset_byte_range().end;
1108 let end = start + Offset16::RAW_BYTE_LEN;
1109 start..end
1110 }
1111
1112 pub fn entry_table_offset_byte_range(&self) -> Range<usize> {
1113 let start = self.state_array_offset_byte_range().end;
1114 let end = start + Offset16::RAW_BYTE_LEN;
1115 start..end
1116 }
1117}
1118
1119const _: () = assert!(FontData::default_data_long_enough(StateHeader::MIN_SIZE));
1120
1121impl Default for StateHeader<'_> {
1122 fn default() -> Self {
1123 Self {
1124 data: FontData::default_table_data(),
1125 }
1126 }
1127}
1128
1129#[cfg(feature = "experimental_traverse")]
1130impl<'a> SomeTable<'a> for StateHeader<'a> {
1131 fn type_name(&self) -> &str {
1132 "StateHeader"
1133 }
1134 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1135 match idx {
1136 0usize => Some(Field::new("state_size", self.state_size())),
1137 1usize => Some(Field::new(
1138 "class_table_offset",
1139 FieldType::offset(self.class_table_offset(), self.class_table()),
1140 )),
1141 2usize => Some(Field::new(
1142 "state_array_offset",
1143 FieldType::offset(self.state_array_offset(), self.state_array()),
1144 )),
1145 3usize => Some(Field::new(
1146 "entry_table_offset",
1147 FieldType::offset(self.entry_table_offset(), self.entry_table()),
1148 )),
1149 _ => None,
1150 }
1151 }
1152}
1153
1154#[cfg(feature = "experimental_traverse")]
1155#[allow(clippy::needless_lifetimes)]
1156impl<'a> std::fmt::Debug for StateHeader<'a> {
1157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1158 (self as &dyn SomeTable<'a>).fmt(f)
1159 }
1160}
1161
1162impl<'a> MinByteRange<'a> for ClassSubtable<'a> {
1163 fn min_byte_range(&self) -> Range<usize> {
1164 0..self.class_array_byte_range().end
1165 }
1166 fn min_table_bytes(&self) -> &'a [u8] {
1167 let range = self.min_byte_range();
1168 self.data.as_bytes().get(range).unwrap_or_default()
1169 }
1170}
1171
1172impl ReadArgs for ClassSubtable<'_> {
1173 type Args = ();
1174}
1175
1176impl<'a> FontRead<'a> for ClassSubtable<'a> {
1177 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1178 #[allow(clippy::absurd_extreme_comparisons)]
1179 if data.len() < Self::MIN_SIZE {
1180 return Err(ReadError::OutOfBounds);
1181 }
1182 Ok(Self { data })
1183 }
1184}
1185
1186#[derive(Clone)]
1188pub struct ClassSubtable<'a> {
1189 data: FontData<'a>,
1190}
1191
1192#[allow(clippy::needless_lifetimes)]
1193impl<'a> ClassSubtable<'a> {
1194 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
1195 basic_table_impls!(impl_the_methods);
1196
1197 pub fn first_glyph(&self) -> u16 {
1199 let range = self.first_glyph_byte_range();
1200 self.data.read_at(range.start).ok().unwrap()
1201 }
1202
1203 pub fn n_glyphs(&self) -> u16 {
1205 let range = self.n_glyphs_byte_range();
1206 self.data.read_at(range.start).ok().unwrap()
1207 }
1208
1209 pub fn class_array(&self) -> &'a [u8] {
1212 let range = self.class_array_byte_range();
1213 self.data.read_array(range).ok().unwrap_or_default()
1214 }
1215
1216 pub fn first_glyph_byte_range(&self) -> Range<usize> {
1217 let start = 0;
1218 let end = start + u16::RAW_BYTE_LEN;
1219 start..end
1220 }
1221
1222 pub fn n_glyphs_byte_range(&self) -> Range<usize> {
1223 let start = self.first_glyph_byte_range().end;
1224 let end = start + u16::RAW_BYTE_LEN;
1225 start..end
1226 }
1227
1228 pub fn class_array_byte_range(&self) -> Range<usize> {
1229 let n_glyphs = self.n_glyphs();
1230 let start = self.n_glyphs_byte_range().end;
1231 let end = start + (transforms::to_usize(n_glyphs)).saturating_mul(u8::RAW_BYTE_LEN);
1232 start..end
1233 }
1234}
1235
1236const _: () = assert!(FontData::default_data_long_enough(ClassSubtable::MIN_SIZE));
1237
1238impl Default for ClassSubtable<'_> {
1239 fn default() -> Self {
1240 Self {
1241 data: FontData::default_table_data(),
1242 }
1243 }
1244}
1245
1246#[cfg(feature = "experimental_traverse")]
1247impl<'a> SomeTable<'a> for ClassSubtable<'a> {
1248 fn type_name(&self) -> &str {
1249 "ClassSubtable"
1250 }
1251 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1252 match idx {
1253 0usize => Some(Field::new("first_glyph", self.first_glyph())),
1254 1usize => Some(Field::new("n_glyphs", self.n_glyphs())),
1255 2usize => Some(Field::new("class_array", self.class_array())),
1256 _ => None,
1257 }
1258 }
1259}
1260
1261#[cfg(feature = "experimental_traverse")]
1262#[allow(clippy::needless_lifetimes)]
1263impl<'a> std::fmt::Debug for ClassSubtable<'a> {
1264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1265 (self as &dyn SomeTable<'a>).fmt(f)
1266 }
1267}
1268
1269impl<'a> MinByteRange<'a> for RawBytes<'a> {
1270 fn min_byte_range(&self) -> Range<usize> {
1271 0..self.data_byte_range().end
1272 }
1273 fn min_table_bytes(&self) -> &'a [u8] {
1274 let range = self.min_byte_range();
1275 self.data.as_bytes().get(range).unwrap_or_default()
1276 }
1277}
1278
1279impl ReadArgs for RawBytes<'_> {
1280 type Args = ();
1281}
1282
1283impl<'a> FontRead<'a> for RawBytes<'a> {
1284 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1285 #[allow(clippy::absurd_extreme_comparisons)]
1286 if data.len() < Self::MIN_SIZE {
1287 return Err(ReadError::OutOfBounds);
1288 }
1289 Ok(Self { data })
1290 }
1291}
1292
1293#[derive(Clone)]
1295pub struct RawBytes<'a> {
1296 data: FontData<'a>,
1297}
1298
1299#[allow(clippy::needless_lifetimes)]
1300impl<'a> RawBytes<'a> {
1301 pub const MIN_SIZE: usize = 0;
1302 basic_table_impls!(impl_the_methods);
1303
1304 pub fn data(&self) -> &'a [u8] {
1305 let range = self.data_byte_range();
1306 self.data.read_array(range).ok().unwrap_or_default()
1307 }
1308
1309 pub fn data_byte_range(&self) -> Range<usize> {
1310 let start = 0;
1311 let end =
1312 start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
1313 start..end
1314 }
1315}
1316
1317#[allow(clippy::absurd_extreme_comparisons)]
1318const _: () = assert!(FontData::default_data_long_enough(RawBytes::MIN_SIZE));
1319
1320impl Default for RawBytes<'_> {
1321 fn default() -> Self {
1322 Self {
1323 data: FontData::default_table_data(),
1324 }
1325 }
1326}
1327
1328#[cfg(feature = "experimental_traverse")]
1329impl<'a> SomeTable<'a> for RawBytes<'a> {
1330 fn type_name(&self) -> &str {
1331 "RawBytes"
1332 }
1333 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1334 match idx {
1335 0usize => Some(Field::new("data", self.data())),
1336 _ => None,
1337 }
1338 }
1339}
1340
1341#[cfg(feature = "experimental_traverse")]
1342#[allow(clippy::needless_lifetimes)]
1343impl<'a> std::fmt::Debug for RawBytes<'a> {
1344 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1345 (self as &dyn SomeTable<'a>).fmt(f)
1346 }
1347}
1348
1349impl<'a> MinByteRange<'a> for StxHeader<'a> {
1350 fn min_byte_range(&self) -> Range<usize> {
1351 0..self.entry_table_offset_byte_range().end
1352 }
1353 fn min_table_bytes(&self) -> &'a [u8] {
1354 let range = self.min_byte_range();
1355 self.data.as_bytes().get(range).unwrap_or_default()
1356 }
1357}
1358
1359impl ReadArgs for StxHeader<'_> {
1360 type Args = ();
1361}
1362
1363impl<'a> FontRead<'a> for StxHeader<'a> {
1364 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1365 #[allow(clippy::absurd_extreme_comparisons)]
1366 if data.len() < Self::MIN_SIZE {
1367 return Err(ReadError::OutOfBounds);
1368 }
1369 Ok(Self { data })
1370 }
1371}
1372
1373#[derive(Clone)]
1375pub struct StxHeader<'a> {
1376 data: FontData<'a>,
1377}
1378
1379#[allow(clippy::needless_lifetimes)]
1380impl<'a> StxHeader<'a> {
1381 pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN
1382 + Offset32::RAW_BYTE_LEN
1383 + Offset32::RAW_BYTE_LEN
1384 + Offset32::RAW_BYTE_LEN);
1385 basic_table_impls!(impl_the_methods);
1386
1387 pub fn n_classes(&self) -> u32 {
1389 let range = self.n_classes_byte_range();
1390 self.data.read_at(range.start).ok().unwrap()
1391 }
1392
1393 pub fn class_table_offset(&self) -> Offset32 {
1395 let range = self.class_table_offset_byte_range();
1396 self.data.read_at(range.start).ok().unwrap()
1397 }
1398
1399 pub fn class_table(&self) -> Result<LookupU16<'a>, ReadError> {
1401 let data = self.data;
1402 self.class_table_offset().resolve(data)
1403 }
1404
1405 pub fn state_array_offset(&self) -> Offset32 {
1407 let range = self.state_array_offset_byte_range();
1408 self.data.read_at(range.start).ok().unwrap()
1409 }
1410
1411 pub fn state_array(&self) -> Result<RawWords<'a>, ReadError> {
1413 let data = self.data;
1414 self.state_array_offset().resolve(data)
1415 }
1416
1417 pub fn entry_table_offset(&self) -> Offset32 {
1419 let range = self.entry_table_offset_byte_range();
1420 self.data.read_at(range.start).ok().unwrap()
1421 }
1422
1423 pub fn entry_table(&self) -> Result<RawBytes<'a>, ReadError> {
1425 let data = self.data;
1426 self.entry_table_offset().resolve(data)
1427 }
1428
1429 pub fn n_classes_byte_range(&self) -> Range<usize> {
1430 let start = 0;
1431 let end = start + u32::RAW_BYTE_LEN;
1432 start..end
1433 }
1434
1435 pub fn class_table_offset_byte_range(&self) -> Range<usize> {
1436 let start = self.n_classes_byte_range().end;
1437 let end = start + Offset32::RAW_BYTE_LEN;
1438 start..end
1439 }
1440
1441 pub fn state_array_offset_byte_range(&self) -> Range<usize> {
1442 let start = self.class_table_offset_byte_range().end;
1443 let end = start + Offset32::RAW_BYTE_LEN;
1444 start..end
1445 }
1446
1447 pub fn entry_table_offset_byte_range(&self) -> Range<usize> {
1448 let start = self.state_array_offset_byte_range().end;
1449 let end = start + Offset32::RAW_BYTE_LEN;
1450 start..end
1451 }
1452}
1453
1454const _: () = assert!(FontData::default_data_long_enough(StxHeader::MIN_SIZE));
1455
1456impl Default for StxHeader<'_> {
1457 fn default() -> Self {
1458 Self {
1459 data: FontData::default_table_data(),
1460 }
1461 }
1462}
1463
1464#[cfg(feature = "experimental_traverse")]
1465impl<'a> SomeTable<'a> for StxHeader<'a> {
1466 fn type_name(&self) -> &str {
1467 "StxHeader"
1468 }
1469 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1470 match idx {
1471 0usize => Some(Field::new("n_classes", self.n_classes())),
1472 1usize => Some(Field::new(
1473 "class_table_offset",
1474 FieldType::offset(self.class_table_offset(), self.class_table()),
1475 )),
1476 2usize => Some(Field::new(
1477 "state_array_offset",
1478 FieldType::offset(self.state_array_offset(), self.state_array()),
1479 )),
1480 3usize => Some(Field::new(
1481 "entry_table_offset",
1482 FieldType::offset(self.entry_table_offset(), self.entry_table()),
1483 )),
1484 _ => None,
1485 }
1486 }
1487}
1488
1489#[cfg(feature = "experimental_traverse")]
1490#[allow(clippy::needless_lifetimes)]
1491impl<'a> std::fmt::Debug for StxHeader<'a> {
1492 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1493 (self as &dyn SomeTable<'a>).fmt(f)
1494 }
1495}
1496
1497impl<'a> MinByteRange<'a> for RawWords<'a> {
1498 fn min_byte_range(&self) -> Range<usize> {
1499 0..self.data_byte_range().end
1500 }
1501 fn min_table_bytes(&self) -> &'a [u8] {
1502 let range = self.min_byte_range();
1503 self.data.as_bytes().get(range).unwrap_or_default()
1504 }
1505}
1506
1507impl ReadArgs for RawWords<'_> {
1508 type Args = ();
1509}
1510
1511impl<'a> FontRead<'a> for RawWords<'a> {
1512 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1513 #[allow(clippy::absurd_extreme_comparisons)]
1514 if data.len() < Self::MIN_SIZE {
1515 return Err(ReadError::OutOfBounds);
1516 }
1517 Ok(Self { data })
1518 }
1519}
1520
1521#[derive(Clone)]
1523pub struct RawWords<'a> {
1524 data: FontData<'a>,
1525}
1526
1527#[allow(clippy::needless_lifetimes)]
1528impl<'a> RawWords<'a> {
1529 pub const MIN_SIZE: usize = 0;
1530 basic_table_impls!(impl_the_methods);
1531
1532 pub fn data(&self) -> &'a [BigEndian<u16>] {
1533 let range = self.data_byte_range();
1534 self.data.read_array(range).ok().unwrap_or_default()
1535 }
1536
1537 pub fn data_byte_range(&self) -> Range<usize> {
1538 let start = 0;
1539 let end =
1540 start + self.data.len().saturating_sub(start) / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
1541 start..end
1542 }
1543}
1544
1545#[allow(clippy::absurd_extreme_comparisons)]
1546const _: () = assert!(FontData::default_data_long_enough(RawWords::MIN_SIZE));
1547
1548impl Default for RawWords<'_> {
1549 fn default() -> Self {
1550 Self {
1551 data: FontData::default_table_data(),
1552 }
1553 }
1554}
1555
1556#[cfg(feature = "experimental_traverse")]
1557impl<'a> SomeTable<'a> for RawWords<'a> {
1558 fn type_name(&self) -> &str {
1559 "RawWords"
1560 }
1561 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1562 match idx {
1563 0usize => Some(Field::new("data", self.data())),
1564 _ => None,
1565 }
1566 }
1567}
1568
1569#[cfg(feature = "experimental_traverse")]
1570#[allow(clippy::needless_lifetimes)]
1571impl<'a> std::fmt::Debug for RawWords<'a> {
1572 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1573 (self as &dyn SomeTable<'a>).fmt(f)
1574 }
1575}