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