1#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for CffHeader<'a> {
9 fn min_byte_range(&self) -> Range<usize> {
10 0..self.trailing_data_byte_range().end
11 }
12 fn min_table_bytes(&self) -> &'a [u8] {
13 let range = self.min_byte_range();
14 self.data.as_bytes().get(range).unwrap_or_default()
15 }
16}
17
18impl<'a> FontRead<'a> for CffHeader<'a> {
19 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
20 #[allow(clippy::absurd_extreme_comparisons)]
21 if data.len() < Self::MIN_SIZE {
22 return Err(ReadError::OutOfBounds);
23 }
24 Ok(Self { data })
25 }
26}
27
28#[derive(Clone)]
30pub struct CffHeader<'a> {
31 data: FontData<'a>,
32}
33
34#[allow(clippy::needless_lifetimes)]
35impl<'a> CffHeader<'a> {
36 pub const MIN_SIZE: usize =
37 (u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
38 basic_table_impls!(impl_the_methods);
39
40 pub fn major(&self) -> u8 {
42 let range = self.major_byte_range();
43 self.data.read_at(range.start).ok().unwrap()
44 }
45
46 pub fn minor(&self) -> u8 {
48 let range = self.minor_byte_range();
49 self.data.read_at(range.start).ok().unwrap()
50 }
51
52 pub fn hdr_size(&self) -> u8 {
54 let range = self.hdr_size_byte_range();
55 self.data.read_at(range.start).ok().unwrap()
56 }
57
58 pub fn off_size(&self) -> u8 {
60 let range = self.off_size_byte_range();
61 self.data.read_at(range.start).ok().unwrap()
62 }
63
64 pub fn _padding(&self) -> &'a [u8] {
66 let range = self._padding_byte_range();
67 self.data.read_array(range).ok().unwrap_or_default()
68 }
69
70 pub fn trailing_data(&self) -> &'a [u8] {
72 let range = self.trailing_data_byte_range();
73 self.data.read_array(range).ok().unwrap_or_default()
74 }
75
76 pub fn major_byte_range(&self) -> Range<usize> {
77 let start = 0;
78 let end = start + u8::RAW_BYTE_LEN;
79 start..end
80 }
81
82 pub fn minor_byte_range(&self) -> Range<usize> {
83 let start = self.major_byte_range().end;
84 let end = start + u8::RAW_BYTE_LEN;
85 start..end
86 }
87
88 pub fn hdr_size_byte_range(&self) -> Range<usize> {
89 let start = self.minor_byte_range().end;
90 let end = start + u8::RAW_BYTE_LEN;
91 start..end
92 }
93
94 pub fn off_size_byte_range(&self) -> Range<usize> {
95 let start = self.hdr_size_byte_range().end;
96 let end = start + u8::RAW_BYTE_LEN;
97 start..end
98 }
99
100 pub fn _padding_byte_range(&self) -> Range<usize> {
101 let hdr_size = self.hdr_size();
102 let start = self.off_size_byte_range().end;
103 let end =
104 start + (transforms::subtract(hdr_size, 4_usize)).saturating_mul(u8::RAW_BYTE_LEN);
105 start..end
106 }
107
108 pub fn trailing_data_byte_range(&self) -> Range<usize> {
109 let start = self._padding_byte_range().end;
110 let end =
111 start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
112 start..end
113 }
114}
115
116const _: () = assert!(FontData::default_data_long_enough(CffHeader::MIN_SIZE));
117
118impl Default for CffHeader<'_> {
119 fn default() -> Self {
120 Self {
121 data: FontData::default_table_data(),
122 }
123 }
124}
125
126#[cfg(feature = "experimental_traverse")]
127impl<'a> SomeTable<'a> for CffHeader<'a> {
128 fn type_name(&self) -> &str {
129 "CffHeader"
130 }
131 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
132 match idx {
133 0usize => Some(Field::new("major", self.major())),
134 1usize => Some(Field::new("minor", self.minor())),
135 2usize => Some(Field::new("hdr_size", self.hdr_size())),
136 3usize => Some(Field::new("off_size", self.off_size())),
137 4usize => Some(Field::new("_padding", self._padding())),
138 5usize => Some(Field::new("trailing_data", self.trailing_data())),
139 _ => None,
140 }
141 }
142}
143
144#[cfg(feature = "experimental_traverse")]
145#[allow(clippy::needless_lifetimes)]
146impl<'a> std::fmt::Debug for CffHeader<'a> {
147 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 (self as &dyn SomeTable<'a>).fmt(f)
149 }
150}
151
152impl<'a> MinByteRange<'a> for Index<'a> {
153 fn min_byte_range(&self) -> Range<usize> {
154 0..self.data_byte_range().end
155 }
156 fn min_table_bytes(&self) -> &'a [u8] {
157 let range = self.min_byte_range();
158 self.data.as_bytes().get(range).unwrap_or_default()
159 }
160}
161
162impl<'a> FontRead<'a> for Index<'a> {
163 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
164 #[allow(clippy::absurd_extreme_comparisons)]
165 if data.len() < Self::MIN_SIZE {
166 return Err(ReadError::OutOfBounds);
167 }
168 Ok(Self { data })
169 }
170}
171
172#[derive(Clone)]
174pub struct Index<'a> {
175 data: FontData<'a>,
176}
177
178#[allow(clippy::needless_lifetimes)]
179impl<'a> Index<'a> {
180 pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
181 basic_table_impls!(impl_the_methods);
182
183 pub fn count(&self) -> u16 {
185 let range = self.count_byte_range();
186 self.data.read_at(range.start).ok().unwrap()
187 }
188
189 pub fn off_size(&self) -> u8 {
191 let range = self.off_size_byte_range();
192 self.data.read_at(range.start).ok().unwrap()
193 }
194
195 pub fn offsets(&self) -> &'a [u8] {
197 let range = self.offsets_byte_range();
198 self.data.read_array(range).ok().unwrap_or_default()
199 }
200
201 pub fn data(&self) -> &'a [u8] {
203 let range = self.data_byte_range();
204 self.data.read_array(range).ok().unwrap_or_default()
205 }
206
207 pub fn count_byte_range(&self) -> Range<usize> {
208 let start = 0;
209 let end = start + u16::RAW_BYTE_LEN;
210 start..end
211 }
212
213 pub fn off_size_byte_range(&self) -> Range<usize> {
214 let start = self.count_byte_range().end;
215 let end = start + u8::RAW_BYTE_LEN;
216 start..end
217 }
218
219 pub fn offsets_byte_range(&self) -> Range<usize> {
220 let count = self.count();
221 let off_size = self.off_size();
222 let start = self.off_size_byte_range().end;
223 let end = start
224 + (transforms::add_multiply(count, 1_usize, off_size)).saturating_mul(u8::RAW_BYTE_LEN);
225 start..end
226 }
227
228 pub fn data_byte_range(&self) -> Range<usize> {
229 let start = self.offsets_byte_range().end;
230 let end =
231 start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
232 start..end
233 }
234}
235
236const _: () = assert!(FontData::default_data_long_enough(Index::MIN_SIZE));
237
238impl Default for Index<'_> {
239 fn default() -> Self {
240 Self {
241 data: FontData::default_table_data(),
242 }
243 }
244}
245
246#[cfg(feature = "experimental_traverse")]
247impl<'a> SomeTable<'a> for Index<'a> {
248 fn type_name(&self) -> &str {
249 "Index"
250 }
251 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
252 match idx {
253 0usize => Some(Field::new("count", self.count())),
254 1usize => Some(Field::new("off_size", self.off_size())),
255 2usize => Some(Field::new("offsets", self.offsets())),
256 3usize => Some(Field::new("data", self.data())),
257 _ => None,
258 }
259 }
260}
261
262#[cfg(feature = "experimental_traverse")]
263#[allow(clippy::needless_lifetimes)]
264impl<'a> std::fmt::Debug for Index<'a> {
265 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
266 (self as &dyn SomeTable<'a>).fmt(f)
267 }
268}
269
270#[derive(Clone)]
272pub enum FdSelect<'a> {
273 Format0(FdSelectFormat0<'a>),
274 Format3(FdSelectFormat3<'a>),
275 Format4(FdSelectFormat4<'a>),
276}
277
278impl Default for FdSelect<'_> {
279 fn default() -> Self {
280 Self::Format0(Default::default())
281 }
282}
283
284impl<'a> FdSelect<'a> {
285 pub fn offset_data(&self) -> FontData<'a> {
287 match self {
288 Self::Format0(item) => item.offset_data(),
289 Self::Format3(item) => item.offset_data(),
290 Self::Format4(item) => item.offset_data(),
291 }
292 }
293
294 pub fn format(&self) -> u8 {
296 match self {
297 Self::Format0(item) => item.format(),
298 Self::Format3(item) => item.format(),
299 Self::Format4(item) => item.format(),
300 }
301 }
302}
303
304impl<'a> FontRead<'a> for FdSelect<'a> {
305 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
306 let format: u8 = data.read_at(0usize)?;
307 match format {
308 FdSelectFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
309 FdSelectFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
310 FdSelectFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
311 other => Err(ReadError::InvalidFormat(other.into())),
312 }
313 }
314}
315
316impl<'a> MinByteRange<'a> for FdSelect<'a> {
317 fn min_byte_range(&self) -> Range<usize> {
318 match self {
319 Self::Format0(item) => item.min_byte_range(),
320 Self::Format3(item) => item.min_byte_range(),
321 Self::Format4(item) => item.min_byte_range(),
322 }
323 }
324 fn min_table_bytes(&self) -> &'a [u8] {
325 match self {
326 Self::Format0(item) => item.min_table_bytes(),
327 Self::Format3(item) => item.min_table_bytes(),
328 Self::Format4(item) => item.min_table_bytes(),
329 }
330 }
331}
332
333#[cfg(feature = "experimental_traverse")]
334impl<'a> FdSelect<'a> {
335 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
336 match self {
337 Self::Format0(table) => table,
338 Self::Format3(table) => table,
339 Self::Format4(table) => table,
340 }
341 }
342}
343
344#[cfg(feature = "experimental_traverse")]
345impl std::fmt::Debug for FdSelect<'_> {
346 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
347 self.dyn_inner().fmt(f)
348 }
349}
350
351#[cfg(feature = "experimental_traverse")]
352impl<'a> SomeTable<'a> for FdSelect<'a> {
353 fn type_name(&self) -> &str {
354 self.dyn_inner().type_name()
355 }
356 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
357 self.dyn_inner().get_field(idx)
358 }
359}
360
361impl Format<u8> for FdSelectFormat0<'_> {
362 const FORMAT: u8 = 0;
363}
364
365impl<'a> MinByteRange<'a> for FdSelectFormat0<'a> {
366 fn min_byte_range(&self) -> Range<usize> {
367 0..self.fds_byte_range().end
368 }
369 fn min_table_bytes(&self) -> &'a [u8] {
370 let range = self.min_byte_range();
371 self.data.as_bytes().get(range).unwrap_or_default()
372 }
373}
374
375impl<'a> FontRead<'a> for FdSelectFormat0<'a> {
376 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
377 #[allow(clippy::absurd_extreme_comparisons)]
378 if data.len() < Self::MIN_SIZE {
379 return Err(ReadError::OutOfBounds);
380 }
381 Ok(Self { data })
382 }
383}
384
385#[derive(Clone)]
387pub struct FdSelectFormat0<'a> {
388 data: FontData<'a>,
389}
390
391#[allow(clippy::needless_lifetimes)]
392impl<'a> FdSelectFormat0<'a> {
393 pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
394 basic_table_impls!(impl_the_methods);
395
396 pub fn format(&self) -> u8 {
398 let range = self.format_byte_range();
399 self.data.read_at(range.start).ok().unwrap()
400 }
401
402 pub fn fds(&self) -> &'a [u8] {
404 let range = self.fds_byte_range();
405 self.data.read_array(range).ok().unwrap_or_default()
406 }
407
408 pub fn format_byte_range(&self) -> Range<usize> {
409 let start = 0;
410 let end = start + u8::RAW_BYTE_LEN;
411 start..end
412 }
413
414 pub fn fds_byte_range(&self) -> Range<usize> {
415 let start = self.format_byte_range().end;
416 let end =
417 start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN;
418 start..end
419 }
420}
421
422const _: () = assert!(FontData::default_data_long_enough(
423 FdSelectFormat0::MIN_SIZE
424));
425
426impl Default for FdSelectFormat0<'_> {
427 fn default() -> Self {
428 Self {
429 data: FontData::default_table_data(),
430 }
431 }
432}
433
434#[cfg(feature = "experimental_traverse")]
435impl<'a> SomeTable<'a> for FdSelectFormat0<'a> {
436 fn type_name(&self) -> &str {
437 "FdSelectFormat0"
438 }
439 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
440 match idx {
441 0usize => Some(Field::new("format", self.format())),
442 1usize => Some(Field::new("fds", self.fds())),
443 _ => None,
444 }
445 }
446}
447
448#[cfg(feature = "experimental_traverse")]
449#[allow(clippy::needless_lifetimes)]
450impl<'a> std::fmt::Debug for FdSelectFormat0<'a> {
451 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452 (self as &dyn SomeTable<'a>).fmt(f)
453 }
454}
455
456impl Format<u8> for FdSelectFormat3<'_> {
457 const FORMAT: u8 = 3;
458}
459
460impl<'a> MinByteRange<'a> for FdSelectFormat3<'a> {
461 fn min_byte_range(&self) -> Range<usize> {
462 0..self.sentinel_byte_range().end
463 }
464 fn min_table_bytes(&self) -> &'a [u8] {
465 let range = self.min_byte_range();
466 self.data.as_bytes().get(range).unwrap_or_default()
467 }
468}
469
470impl<'a> FontRead<'a> for FdSelectFormat3<'a> {
471 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
472 #[allow(clippy::absurd_extreme_comparisons)]
473 if data.len() < Self::MIN_SIZE {
474 return Err(ReadError::OutOfBounds);
475 }
476 Ok(Self { data })
477 }
478}
479
480#[derive(Clone)]
482pub struct FdSelectFormat3<'a> {
483 data: FontData<'a>,
484}
485
486#[allow(clippy::needless_lifetimes)]
487impl<'a> FdSelectFormat3<'a> {
488 pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
489 basic_table_impls!(impl_the_methods);
490
491 pub fn format(&self) -> u8 {
493 let range = self.format_byte_range();
494 self.data.read_at(range.start).ok().unwrap()
495 }
496
497 pub fn n_ranges(&self) -> u16 {
499 let range = self.n_ranges_byte_range();
500 self.data.read_at(range.start).ok().unwrap()
501 }
502
503 pub fn ranges(&self) -> &'a [FdSelectRange3] {
505 let range = self.ranges_byte_range();
506 self.data.read_array(range).ok().unwrap_or_default()
507 }
508
509 pub fn sentinel(&self) -> u16 {
511 let range = self.sentinel_byte_range();
512 self.data.read_at(range.start).ok().unwrap_or_default()
513 }
514
515 pub fn format_byte_range(&self) -> Range<usize> {
516 let start = 0;
517 let end = start + u8::RAW_BYTE_LEN;
518 start..end
519 }
520
521 pub fn n_ranges_byte_range(&self) -> Range<usize> {
522 let start = self.format_byte_range().end;
523 let end = start + u16::RAW_BYTE_LEN;
524 start..end
525 }
526
527 pub fn ranges_byte_range(&self) -> Range<usize> {
528 let n_ranges = self.n_ranges();
529 let start = self.n_ranges_byte_range().end;
530 let end =
531 start + (transforms::to_usize(n_ranges)).saturating_mul(FdSelectRange3::RAW_BYTE_LEN);
532 start..end
533 }
534
535 pub fn sentinel_byte_range(&self) -> Range<usize> {
536 let start = self.ranges_byte_range().end;
537 let end = start + u16::RAW_BYTE_LEN;
538 start..end
539 }
540}
541
542#[cfg(feature = "experimental_traverse")]
543impl<'a> SomeTable<'a> for FdSelectFormat3<'a> {
544 fn type_name(&self) -> &str {
545 "FdSelectFormat3"
546 }
547 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
548 match idx {
549 0usize => Some(Field::new("format", self.format())),
550 1usize => Some(Field::new("n_ranges", self.n_ranges())),
551 2usize => Some(Field::new(
552 "ranges",
553 traversal::FieldType::array_of_records(
554 stringify!(FdSelectRange3),
555 self.ranges(),
556 self.offset_data(),
557 ),
558 )),
559 3usize => Some(Field::new("sentinel", self.sentinel())),
560 _ => None,
561 }
562 }
563}
564
565#[cfg(feature = "experimental_traverse")]
566#[allow(clippy::needless_lifetimes)]
567impl<'a> std::fmt::Debug for FdSelectFormat3<'a> {
568 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
569 (self as &dyn SomeTable<'a>).fmt(f)
570 }
571}
572
573#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
575#[repr(C)]
576#[repr(packed)]
577pub struct FdSelectRange3 {
578 pub first: BigEndian<u16>,
580 pub fd: u8,
582}
583
584impl FdSelectRange3 {
585 pub fn first(&self) -> u16 {
587 self.first.get()
588 }
589
590 pub fn fd(&self) -> u8 {
592 self.fd
593 }
594}
595
596impl FixedSize for FdSelectRange3 {
597 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
598}
599
600#[cfg(feature = "experimental_traverse")]
601impl<'a> SomeRecord<'a> for FdSelectRange3 {
602 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
603 RecordResolver {
604 name: "FdSelectRange3",
605 get_field: Box::new(move |idx, _data| match idx {
606 0usize => Some(Field::new("first", self.first())),
607 1usize => Some(Field::new("fd", self.fd())),
608 _ => None,
609 }),
610 data,
611 }
612 }
613}
614
615impl Format<u8> for FdSelectFormat4<'_> {
616 const FORMAT: u8 = 4;
617}
618
619impl<'a> MinByteRange<'a> for FdSelectFormat4<'a> {
620 fn min_byte_range(&self) -> Range<usize> {
621 0..self.sentinel_byte_range().end
622 }
623 fn min_table_bytes(&self) -> &'a [u8] {
624 let range = self.min_byte_range();
625 self.data.as_bytes().get(range).unwrap_or_default()
626 }
627}
628
629impl<'a> FontRead<'a> for FdSelectFormat4<'a> {
630 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
631 #[allow(clippy::absurd_extreme_comparisons)]
632 if data.len() < Self::MIN_SIZE {
633 return Err(ReadError::OutOfBounds);
634 }
635 Ok(Self { data })
636 }
637}
638
639#[derive(Clone)]
641pub struct FdSelectFormat4<'a> {
642 data: FontData<'a>,
643}
644
645#[allow(clippy::needless_lifetimes)]
646impl<'a> FdSelectFormat4<'a> {
647 pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
648 basic_table_impls!(impl_the_methods);
649
650 pub fn format(&self) -> u8 {
652 let range = self.format_byte_range();
653 self.data.read_at(range.start).ok().unwrap()
654 }
655
656 pub fn n_ranges(&self) -> u32 {
658 let range = self.n_ranges_byte_range();
659 self.data.read_at(range.start).ok().unwrap()
660 }
661
662 pub fn ranges(&self) -> &'a [FdSelectRange4] {
664 let range = self.ranges_byte_range();
665 self.data.read_array(range).ok().unwrap_or_default()
666 }
667
668 pub fn sentinel(&self) -> u32 {
670 let range = self.sentinel_byte_range();
671 self.data.read_at(range.start).ok().unwrap_or_default()
672 }
673
674 pub fn format_byte_range(&self) -> Range<usize> {
675 let start = 0;
676 let end = start + u8::RAW_BYTE_LEN;
677 start..end
678 }
679
680 pub fn n_ranges_byte_range(&self) -> Range<usize> {
681 let start = self.format_byte_range().end;
682 let end = start + u32::RAW_BYTE_LEN;
683 start..end
684 }
685
686 pub fn ranges_byte_range(&self) -> Range<usize> {
687 let n_ranges = self.n_ranges();
688 let start = self.n_ranges_byte_range().end;
689 let end =
690 start + (transforms::to_usize(n_ranges)).saturating_mul(FdSelectRange4::RAW_BYTE_LEN);
691 start..end
692 }
693
694 pub fn sentinel_byte_range(&self) -> Range<usize> {
695 let start = self.ranges_byte_range().end;
696 let end = start + u32::RAW_BYTE_LEN;
697 start..end
698 }
699}
700
701#[cfg(feature = "experimental_traverse")]
702impl<'a> SomeTable<'a> for FdSelectFormat4<'a> {
703 fn type_name(&self) -> &str {
704 "FdSelectFormat4"
705 }
706 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
707 match idx {
708 0usize => Some(Field::new("format", self.format())),
709 1usize => Some(Field::new("n_ranges", self.n_ranges())),
710 2usize => Some(Field::new(
711 "ranges",
712 traversal::FieldType::array_of_records(
713 stringify!(FdSelectRange4),
714 self.ranges(),
715 self.offset_data(),
716 ),
717 )),
718 3usize => Some(Field::new("sentinel", self.sentinel())),
719 _ => None,
720 }
721 }
722}
723
724#[cfg(feature = "experimental_traverse")]
725#[allow(clippy::needless_lifetimes)]
726impl<'a> std::fmt::Debug for FdSelectFormat4<'a> {
727 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
728 (self as &dyn SomeTable<'a>).fmt(f)
729 }
730}
731
732#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
734#[repr(C)]
735#[repr(packed)]
736pub struct FdSelectRange4 {
737 pub first: BigEndian<u32>,
739 pub fd: BigEndian<u16>,
741}
742
743impl FdSelectRange4 {
744 pub fn first(&self) -> u32 {
746 self.first.get()
747 }
748
749 pub fn fd(&self) -> u16 {
751 self.fd.get()
752 }
753}
754
755impl FixedSize for FdSelectRange4 {
756 const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
757}
758
759#[cfg(feature = "experimental_traverse")]
760impl<'a> SomeRecord<'a> for FdSelectRange4 {
761 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
762 RecordResolver {
763 name: "FdSelectRange4",
764 get_field: Box::new(move |idx, _data| match idx {
765 0usize => Some(Field::new("first", self.first())),
766 1usize => Some(Field::new("fd", self.fd())),
767 _ => None,
768 }),
769 data,
770 }
771 }
772}
773
774#[derive(Clone)]
776pub enum CustomCharset<'a> {
777 Format0(CharsetFormat0<'a>),
778 Format1(CharsetFormat1<'a>),
779 Format2(CharsetFormat2<'a>),
780}
781
782impl Default for CustomCharset<'_> {
783 fn default() -> Self {
784 Self::Format0(Default::default())
785 }
786}
787
788impl<'a> CustomCharset<'a> {
789 pub fn offset_data(&self) -> FontData<'a> {
791 match self {
792 Self::Format0(item) => item.offset_data(),
793 Self::Format1(item) => item.offset_data(),
794 Self::Format2(item) => item.offset_data(),
795 }
796 }
797
798 pub fn format(&self) -> u8 {
800 match self {
801 Self::Format0(item) => item.format(),
802 Self::Format1(item) => item.format(),
803 Self::Format2(item) => item.format(),
804 }
805 }
806}
807
808impl<'a> FontRead<'a> for CustomCharset<'a> {
809 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
810 let format: u8 = data.read_at(0usize)?;
811 match format {
812 CharsetFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
813 CharsetFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
814 CharsetFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
815 other => Err(ReadError::InvalidFormat(other.into())),
816 }
817 }
818}
819
820impl<'a> MinByteRange<'a> for CustomCharset<'a> {
821 fn min_byte_range(&self) -> Range<usize> {
822 match self {
823 Self::Format0(item) => item.min_byte_range(),
824 Self::Format1(item) => item.min_byte_range(),
825 Self::Format2(item) => item.min_byte_range(),
826 }
827 }
828 fn min_table_bytes(&self) -> &'a [u8] {
829 match self {
830 Self::Format0(item) => item.min_table_bytes(),
831 Self::Format1(item) => item.min_table_bytes(),
832 Self::Format2(item) => item.min_table_bytes(),
833 }
834 }
835}
836
837#[cfg(feature = "experimental_traverse")]
838impl<'a> CustomCharset<'a> {
839 fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
840 match self {
841 Self::Format0(table) => table,
842 Self::Format1(table) => table,
843 Self::Format2(table) => table,
844 }
845 }
846}
847
848#[cfg(feature = "experimental_traverse")]
849impl std::fmt::Debug for CustomCharset<'_> {
850 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
851 self.dyn_inner().fmt(f)
852 }
853}
854
855#[cfg(feature = "experimental_traverse")]
856impl<'a> SomeTable<'a> for CustomCharset<'a> {
857 fn type_name(&self) -> &str {
858 self.dyn_inner().type_name()
859 }
860 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
861 self.dyn_inner().get_field(idx)
862 }
863}
864
865impl Format<u8> for CharsetFormat0<'_> {
866 const FORMAT: u8 = 0;
867}
868
869impl<'a> MinByteRange<'a> for CharsetFormat0<'a> {
870 fn min_byte_range(&self) -> Range<usize> {
871 0..self.glyph_byte_range().end
872 }
873 fn min_table_bytes(&self) -> &'a [u8] {
874 let range = self.min_byte_range();
875 self.data.as_bytes().get(range).unwrap_or_default()
876 }
877}
878
879impl<'a> FontRead<'a> for CharsetFormat0<'a> {
880 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
881 #[allow(clippy::absurd_extreme_comparisons)]
882 if data.len() < Self::MIN_SIZE {
883 return Err(ReadError::OutOfBounds);
884 }
885 Ok(Self { data })
886 }
887}
888
889#[derive(Clone)]
891pub struct CharsetFormat0<'a> {
892 data: FontData<'a>,
893}
894
895#[allow(clippy::needless_lifetimes)]
896impl<'a> CharsetFormat0<'a> {
897 pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
898 basic_table_impls!(impl_the_methods);
899
900 pub fn format(&self) -> u8 {
902 let range = self.format_byte_range();
903 self.data.read_at(range.start).ok().unwrap()
904 }
905
906 pub fn glyph(&self) -> &'a [BigEndian<u16>] {
908 let range = self.glyph_byte_range();
909 self.data.read_array(range).ok().unwrap_or_default()
910 }
911
912 pub fn format_byte_range(&self) -> Range<usize> {
913 let start = 0;
914 let end = start + u8::RAW_BYTE_LEN;
915 start..end
916 }
917
918 pub fn glyph_byte_range(&self) -> Range<usize> {
919 let start = self.format_byte_range().end;
920 let end =
921 start + self.data.len().saturating_sub(start) / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN;
922 start..end
923 }
924}
925
926const _: () = assert!(FontData::default_data_long_enough(CharsetFormat0::MIN_SIZE));
927
928impl Default for CharsetFormat0<'_> {
929 fn default() -> Self {
930 Self {
931 data: FontData::default_table_data(),
932 }
933 }
934}
935
936#[cfg(feature = "experimental_traverse")]
937impl<'a> SomeTable<'a> for CharsetFormat0<'a> {
938 fn type_name(&self) -> &str {
939 "CharsetFormat0"
940 }
941 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
942 match idx {
943 0usize => Some(Field::new("format", self.format())),
944 1usize => Some(Field::new("glyph", self.glyph())),
945 _ => None,
946 }
947 }
948}
949
950#[cfg(feature = "experimental_traverse")]
951#[allow(clippy::needless_lifetimes)]
952impl<'a> std::fmt::Debug for CharsetFormat0<'a> {
953 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
954 (self as &dyn SomeTable<'a>).fmt(f)
955 }
956}
957
958impl Format<u8> for CharsetFormat1<'_> {
959 const FORMAT: u8 = 1;
960}
961
962impl<'a> MinByteRange<'a> for CharsetFormat1<'a> {
963 fn min_byte_range(&self) -> Range<usize> {
964 0..self.ranges_byte_range().end
965 }
966 fn min_table_bytes(&self) -> &'a [u8] {
967 let range = self.min_byte_range();
968 self.data.as_bytes().get(range).unwrap_or_default()
969 }
970}
971
972impl<'a> FontRead<'a> for CharsetFormat1<'a> {
973 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
974 #[allow(clippy::absurd_extreme_comparisons)]
975 if data.len() < Self::MIN_SIZE {
976 return Err(ReadError::OutOfBounds);
977 }
978 Ok(Self { data })
979 }
980}
981
982#[derive(Clone)]
984pub struct CharsetFormat1<'a> {
985 data: FontData<'a>,
986}
987
988#[allow(clippy::needless_lifetimes)]
989impl<'a> CharsetFormat1<'a> {
990 pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
991 basic_table_impls!(impl_the_methods);
992
993 pub fn format(&self) -> u8 {
995 let range = self.format_byte_range();
996 self.data.read_at(range.start).ok().unwrap()
997 }
998
999 pub fn ranges(&self) -> &'a [CharsetRange1] {
1001 let range = self.ranges_byte_range();
1002 self.data.read_array(range).ok().unwrap_or_default()
1003 }
1004
1005 pub fn format_byte_range(&self) -> Range<usize> {
1006 let start = 0;
1007 let end = start + u8::RAW_BYTE_LEN;
1008 start..end
1009 }
1010
1011 pub fn ranges_byte_range(&self) -> Range<usize> {
1012 let start = self.format_byte_range().end;
1013 let end = start
1014 + self.data.len().saturating_sub(start) / CharsetRange1::RAW_BYTE_LEN
1015 * CharsetRange1::RAW_BYTE_LEN;
1016 start..end
1017 }
1018}
1019
1020const _: () = assert!(FontData::default_data_long_enough(CharsetFormat1::MIN_SIZE));
1021
1022impl Default for CharsetFormat1<'_> {
1023 fn default() -> Self {
1024 Self {
1025 data: FontData::default_format_1_u8_table_data(),
1026 }
1027 }
1028}
1029
1030#[cfg(feature = "experimental_traverse")]
1031impl<'a> SomeTable<'a> for CharsetFormat1<'a> {
1032 fn type_name(&self) -> &str {
1033 "CharsetFormat1"
1034 }
1035 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1036 match idx {
1037 0usize => Some(Field::new("format", self.format())),
1038 1usize => Some(Field::new(
1039 "ranges",
1040 traversal::FieldType::array_of_records(
1041 stringify!(CharsetRange1),
1042 self.ranges(),
1043 self.offset_data(),
1044 ),
1045 )),
1046 _ => None,
1047 }
1048 }
1049}
1050
1051#[cfg(feature = "experimental_traverse")]
1052#[allow(clippy::needless_lifetimes)]
1053impl<'a> std::fmt::Debug for CharsetFormat1<'a> {
1054 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1055 (self as &dyn SomeTable<'a>).fmt(f)
1056 }
1057}
1058
1059#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1061#[repr(C)]
1062#[repr(packed)]
1063pub struct CharsetRange1 {
1064 pub first: BigEndian<u16>,
1066 pub n_left: u8,
1068}
1069
1070impl CharsetRange1 {
1071 pub fn first(&self) -> u16 {
1073 self.first.get()
1074 }
1075
1076 pub fn n_left(&self) -> u8 {
1078 self.n_left
1079 }
1080}
1081
1082impl FixedSize for CharsetRange1 {
1083 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
1084}
1085
1086#[cfg(feature = "experimental_traverse")]
1087impl<'a> SomeRecord<'a> for CharsetRange1 {
1088 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1089 RecordResolver {
1090 name: "CharsetRange1",
1091 get_field: Box::new(move |idx, _data| match idx {
1092 0usize => Some(Field::new("first", self.first())),
1093 1usize => Some(Field::new("n_left", self.n_left())),
1094 _ => None,
1095 }),
1096 data,
1097 }
1098 }
1099}
1100
1101impl Format<u8> for CharsetFormat2<'_> {
1102 const FORMAT: u8 = 2;
1103}
1104
1105impl<'a> MinByteRange<'a> for CharsetFormat2<'a> {
1106 fn min_byte_range(&self) -> Range<usize> {
1107 0..self.ranges_byte_range().end
1108 }
1109 fn min_table_bytes(&self) -> &'a [u8] {
1110 let range = self.min_byte_range();
1111 self.data.as_bytes().get(range).unwrap_or_default()
1112 }
1113}
1114
1115impl<'a> FontRead<'a> for CharsetFormat2<'a> {
1116 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1117 #[allow(clippy::absurd_extreme_comparisons)]
1118 if data.len() < Self::MIN_SIZE {
1119 return Err(ReadError::OutOfBounds);
1120 }
1121 Ok(Self { data })
1122 }
1123}
1124
1125#[derive(Clone)]
1127pub struct CharsetFormat2<'a> {
1128 data: FontData<'a>,
1129}
1130
1131#[allow(clippy::needless_lifetimes)]
1132impl<'a> CharsetFormat2<'a> {
1133 pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
1134 basic_table_impls!(impl_the_methods);
1135
1136 pub fn format(&self) -> u8 {
1138 let range = self.format_byte_range();
1139 self.data.read_at(range.start).ok().unwrap()
1140 }
1141
1142 pub fn ranges(&self) -> &'a [CharsetRange2] {
1144 let range = self.ranges_byte_range();
1145 self.data.read_array(range).ok().unwrap_or_default()
1146 }
1147
1148 pub fn format_byte_range(&self) -> Range<usize> {
1149 let start = 0;
1150 let end = start + u8::RAW_BYTE_LEN;
1151 start..end
1152 }
1153
1154 pub fn ranges_byte_range(&self) -> Range<usize> {
1155 let start = self.format_byte_range().end;
1156 let end = start
1157 + self.data.len().saturating_sub(start) / CharsetRange2::RAW_BYTE_LEN
1158 * CharsetRange2::RAW_BYTE_LEN;
1159 start..end
1160 }
1161}
1162
1163#[cfg(feature = "experimental_traverse")]
1164impl<'a> SomeTable<'a> for CharsetFormat2<'a> {
1165 fn type_name(&self) -> &str {
1166 "CharsetFormat2"
1167 }
1168 fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1169 match idx {
1170 0usize => Some(Field::new("format", self.format())),
1171 1usize => Some(Field::new(
1172 "ranges",
1173 traversal::FieldType::array_of_records(
1174 stringify!(CharsetRange2),
1175 self.ranges(),
1176 self.offset_data(),
1177 ),
1178 )),
1179 _ => None,
1180 }
1181 }
1182}
1183
1184#[cfg(feature = "experimental_traverse")]
1185#[allow(clippy::needless_lifetimes)]
1186impl<'a> std::fmt::Debug for CharsetFormat2<'a> {
1187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1188 (self as &dyn SomeTable<'a>).fmt(f)
1189 }
1190}
1191
1192#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1194#[repr(C)]
1195#[repr(packed)]
1196pub struct CharsetRange2 {
1197 pub first: BigEndian<u16>,
1199 pub n_left: BigEndian<u16>,
1201}
1202
1203impl CharsetRange2 {
1204 pub fn first(&self) -> u16 {
1206 self.first.get()
1207 }
1208
1209 pub fn n_left(&self) -> u16 {
1211 self.n_left.get()
1212 }
1213}
1214
1215impl FixedSize for CharsetRange2 {
1216 const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1217}
1218
1219#[cfg(feature = "experimental_traverse")]
1220impl<'a> SomeRecord<'a> for CharsetRange2 {
1221 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1222 RecordResolver {
1223 name: "CharsetRange2",
1224 get_field: Box::new(move |idx, _data| match idx {
1225 0usize => Some(Field::new("first", self.first())),
1226 1usize => Some(Field::new("n_left", self.n_left())),
1227 _ => None,
1228 }),
1229 data,
1230 }
1231 }
1232}
1233
1234#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1236#[repr(C)]
1237#[repr(packed)]
1238pub struct EncodingRange1 {
1239 pub first: u8,
1241 pub n_left: u8,
1243}
1244
1245impl EncodingRange1 {
1246 pub fn first(&self) -> u8 {
1248 self.first
1249 }
1250
1251 pub fn n_left(&self) -> u8 {
1253 self.n_left
1254 }
1255}
1256
1257impl FixedSize for EncodingRange1 {
1258 const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
1259}
1260
1261#[cfg(feature = "experimental_traverse")]
1262impl<'a> SomeRecord<'a> for EncodingRange1 {
1263 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1264 RecordResolver {
1265 name: "EncodingRange1",
1266 get_field: Box::new(move |idx, _data| match idx {
1267 0usize => Some(Field::new("first", self.first())),
1268 1usize => Some(Field::new("n_left", self.n_left())),
1269 _ => None,
1270 }),
1271 data,
1272 }
1273 }
1274}
1275
1276#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1278#[repr(C)]
1279#[repr(packed)]
1280pub struct EncodingSupplement {
1281 pub code: u8,
1283 pub glyph: BigEndian<u16>,
1285}
1286
1287impl EncodingSupplement {
1288 pub fn code(&self) -> u8 {
1290 self.code
1291 }
1292
1293 pub fn glyph(&self) -> u16 {
1295 self.glyph.get()
1296 }
1297}
1298
1299impl FixedSize for EncodingSupplement {
1300 const RAW_BYTE_LEN: usize = u8::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1301}
1302
1303#[cfg(feature = "experimental_traverse")]
1304impl<'a> SomeRecord<'a> for EncodingSupplement {
1305 fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1306 RecordResolver {
1307 name: "EncodingSupplement",
1308 get_field: Box::new(move |idx, _data| match idx {
1309 0usize => Some(Field::new("code", self.code())),
1310 1usize => Some(Field::new("glyph", self.glyph())),
1311 _ => None,
1312 }),
1313 data,
1314 }
1315 }
1316}