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