Skip to main content

read_fonts/generated/
generated_postscript.rs

1// THIS FILE IS AUTOGENERATED.
2// Any changes to this file will be overwritten.
3// For more information about how codegen works, see font-codegen/README.md
4
5#[allow(unused_imports)]
6use crate::codegen_prelude::*;
7
8impl<'a> MinByteRange<'a> for Index1<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.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 Index1<'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/// An array of variable-sized objects in a `CFF` table.
29#[derive(Clone)]
30pub struct Index1<'a> {
31    data: FontData<'a>,
32}
33
34#[allow(clippy::needless_lifetimes)]
35impl<'a> Index1<'a> {
36    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
37    basic_table_impls!(impl_the_methods);
38
39    /// Number of objects stored in INDEX.
40    pub fn count(&self) -> u16 {
41        let range = self.count_byte_range();
42        self.data.read_at(range.start).ok().unwrap()
43    }
44
45    /// Object array element size.
46    pub fn off_size(&self) -> u8 {
47        let range = self.off_size_byte_range();
48        self.data.read_at(range.start).ok().unwrap()
49    }
50
51    /// Bytes containing `count + 1` offsets each of `off_size`.
52    pub fn offsets(&self) -> &'a [u8] {
53        let range = self.offsets_byte_range();
54        self.data.read_array(range).ok().unwrap_or_default()
55    }
56
57    /// Array containing the object data.
58    pub fn data(&self) -> &'a [u8] {
59        let range = self.data_byte_range();
60        self.data.read_array(range).ok().unwrap_or_default()
61    }
62
63    pub fn count_byte_range(&self) -> Range<usize> {
64        let start = 0;
65        start..start + u16::RAW_BYTE_LEN
66    }
67
68    pub fn off_size_byte_range(&self) -> Range<usize> {
69        let start = self.count_byte_range().end;
70        start..start + u8::RAW_BYTE_LEN
71    }
72
73    pub fn offsets_byte_range(&self) -> Range<usize> {
74        let count = self.count();
75        let off_size = self.off_size();
76        let start = self.off_size_byte_range().end;
77        start
78            ..start
79                + (transforms::add_multiply(count, 1_usize, off_size))
80                    .saturating_mul(u8::RAW_BYTE_LEN)
81    }
82
83    pub fn data_byte_range(&self) -> Range<usize> {
84        let start = self.offsets_byte_range().end;
85        start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
86    }
87}
88
89#[cfg(feature = "experimental_traverse")]
90impl<'a> SomeTable<'a> for Index1<'a> {
91    fn type_name(&self) -> &str {
92        "Index1"
93    }
94    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
95        match idx {
96            0usize => Some(Field::new("count", self.count())),
97            1usize => Some(Field::new("off_size", self.off_size())),
98            2usize => Some(Field::new("offsets", self.offsets())),
99            3usize => Some(Field::new("data", self.data())),
100            _ => None,
101        }
102    }
103}
104
105#[cfg(feature = "experimental_traverse")]
106#[allow(clippy::needless_lifetimes)]
107impl<'a> std::fmt::Debug for Index1<'a> {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        (self as &dyn SomeTable<'a>).fmt(f)
110    }
111}
112
113impl<'a> MinByteRange<'a> for Index2<'a> {
114    fn min_byte_range(&self) -> Range<usize> {
115        0..self.data_byte_range().end
116    }
117    fn min_table_bytes(&self) -> &'a [u8] {
118        let range = self.min_byte_range();
119        self.data.as_bytes().get(range).unwrap_or_default()
120    }
121}
122
123impl<'a> FontRead<'a> for Index2<'a> {
124    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
125        #[allow(clippy::absurd_extreme_comparisons)]
126        if data.len() < Self::MIN_SIZE {
127            return Err(ReadError::OutOfBounds);
128        }
129        Ok(Self { data })
130    }
131}
132
133/// An array of variable-sized objects in a `CFF2` table.
134#[derive(Clone)]
135pub struct Index2<'a> {
136    data: FontData<'a>,
137}
138
139#[allow(clippy::needless_lifetimes)]
140impl<'a> Index2<'a> {
141    pub const MIN_SIZE: usize = (u32::RAW_BYTE_LEN + u8::RAW_BYTE_LEN);
142    basic_table_impls!(impl_the_methods);
143
144    /// Number of objects stored in INDEX.
145    pub fn count(&self) -> u32 {
146        let range = self.count_byte_range();
147        self.data.read_at(range.start).ok().unwrap()
148    }
149
150    /// Object array element size.
151    pub fn off_size(&self) -> u8 {
152        let range = self.off_size_byte_range();
153        self.data.read_at(range.start).ok().unwrap()
154    }
155
156    /// Bytes containing `count + 1` offsets each of `off_size`.
157    pub fn offsets(&self) -> &'a [u8] {
158        let range = self.offsets_byte_range();
159        self.data.read_array(range).ok().unwrap_or_default()
160    }
161
162    /// Array containing the object data.
163    pub fn data(&self) -> &'a [u8] {
164        let range = self.data_byte_range();
165        self.data.read_array(range).ok().unwrap_or_default()
166    }
167
168    pub fn count_byte_range(&self) -> Range<usize> {
169        let start = 0;
170        start..start + u32::RAW_BYTE_LEN
171    }
172
173    pub fn off_size_byte_range(&self) -> Range<usize> {
174        let start = self.count_byte_range().end;
175        start..start + u8::RAW_BYTE_LEN
176    }
177
178    pub fn offsets_byte_range(&self) -> Range<usize> {
179        let count = self.count();
180        let off_size = self.off_size();
181        let start = self.off_size_byte_range().end;
182        start
183            ..start
184                + (transforms::add_multiply(count, 1_usize, off_size))
185                    .saturating_mul(u8::RAW_BYTE_LEN)
186    }
187
188    pub fn data_byte_range(&self) -> Range<usize> {
189        let start = self.offsets_byte_range().end;
190        start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
191    }
192}
193
194#[cfg(feature = "experimental_traverse")]
195impl<'a> SomeTable<'a> for Index2<'a> {
196    fn type_name(&self) -> &str {
197        "Index2"
198    }
199    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
200        match idx {
201            0usize => Some(Field::new("count", self.count())),
202            1usize => Some(Field::new("off_size", self.off_size())),
203            2usize => Some(Field::new("offsets", self.offsets())),
204            3usize => Some(Field::new("data", self.data())),
205            _ => None,
206        }
207    }
208}
209
210#[cfg(feature = "experimental_traverse")]
211#[allow(clippy::needless_lifetimes)]
212impl<'a> std::fmt::Debug for Index2<'a> {
213    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214        (self as &dyn SomeTable<'a>).fmt(f)
215    }
216}
217
218/// Associates a glyph identifier with a Font DICT.
219#[derive(Clone)]
220pub enum FdSelect<'a> {
221    Format0(FdSelectFormat0<'a>),
222    Format3(FdSelectFormat3<'a>),
223    Format4(FdSelectFormat4<'a>),
224}
225
226impl<'a> FdSelect<'a> {
227    ///Return the `FontData` used to resolve offsets for this table.
228    pub fn offset_data(&self) -> FontData<'a> {
229        match self {
230            Self::Format0(item) => item.offset_data(),
231            Self::Format3(item) => item.offset_data(),
232            Self::Format4(item) => item.offset_data(),
233        }
234    }
235
236    /// Format = 0.
237    pub fn format(&self) -> u8 {
238        match self {
239            Self::Format0(item) => item.format(),
240            Self::Format3(item) => item.format(),
241            Self::Format4(item) => item.format(),
242        }
243    }
244}
245
246impl<'a> FontRead<'a> for FdSelect<'a> {
247    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
248        let format: u8 = data.read_at(0usize)?;
249        match format {
250            FdSelectFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
251            FdSelectFormat3::FORMAT => Ok(Self::Format3(FontRead::read(data)?)),
252            FdSelectFormat4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
253            other => Err(ReadError::InvalidFormat(other.into())),
254        }
255    }
256}
257
258impl<'a> MinByteRange<'a> for FdSelect<'a> {
259    fn min_byte_range(&self) -> Range<usize> {
260        match self {
261            Self::Format0(item) => item.min_byte_range(),
262            Self::Format3(item) => item.min_byte_range(),
263            Self::Format4(item) => item.min_byte_range(),
264        }
265    }
266    fn min_table_bytes(&self) -> &'a [u8] {
267        match self {
268            Self::Format0(item) => item.min_table_bytes(),
269            Self::Format3(item) => item.min_table_bytes(),
270            Self::Format4(item) => item.min_table_bytes(),
271        }
272    }
273}
274
275#[cfg(feature = "experimental_traverse")]
276impl<'a> FdSelect<'a> {
277    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
278        match self {
279            Self::Format0(table) => table,
280            Self::Format3(table) => table,
281            Self::Format4(table) => table,
282        }
283    }
284}
285
286#[cfg(feature = "experimental_traverse")]
287impl std::fmt::Debug for FdSelect<'_> {
288    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
289        self.dyn_inner().fmt(f)
290    }
291}
292
293#[cfg(feature = "experimental_traverse")]
294impl<'a> SomeTable<'a> for FdSelect<'a> {
295    fn type_name(&self) -> &str {
296        self.dyn_inner().type_name()
297    }
298    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
299        self.dyn_inner().get_field(idx)
300    }
301}
302
303impl Format<u8> for FdSelectFormat0<'_> {
304    const FORMAT: u8 = 0;
305}
306
307impl<'a> MinByteRange<'a> for FdSelectFormat0<'a> {
308    fn min_byte_range(&self) -> Range<usize> {
309        0..self.fds_byte_range().end
310    }
311    fn min_table_bytes(&self) -> &'a [u8] {
312        let range = self.min_byte_range();
313        self.data.as_bytes().get(range).unwrap_or_default()
314    }
315}
316
317impl<'a> FontRead<'a> for FdSelectFormat0<'a> {
318    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
319        #[allow(clippy::absurd_extreme_comparisons)]
320        if data.len() < Self::MIN_SIZE {
321            return Err(ReadError::OutOfBounds);
322        }
323        Ok(Self { data })
324    }
325}
326
327/// FdSelect format 0.
328#[derive(Clone)]
329pub struct FdSelectFormat0<'a> {
330    data: FontData<'a>,
331}
332
333#[allow(clippy::needless_lifetimes)]
334impl<'a> FdSelectFormat0<'a> {
335    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
336    basic_table_impls!(impl_the_methods);
337
338    /// Format = 0.
339    pub fn format(&self) -> u8 {
340        let range = self.format_byte_range();
341        self.data.read_at(range.start).ok().unwrap()
342    }
343
344    /// FD selector array (one entry for each glyph).
345    pub fn fds(&self) -> &'a [u8] {
346        let range = self.fds_byte_range();
347        self.data.read_array(range).ok().unwrap_or_default()
348    }
349
350    pub fn format_byte_range(&self) -> Range<usize> {
351        let start = 0;
352        start..start + u8::RAW_BYTE_LEN
353    }
354
355    pub fn fds_byte_range(&self) -> Range<usize> {
356        let start = self.format_byte_range().end;
357        start..start + self.data.len().saturating_sub(start) / u8::RAW_BYTE_LEN * u8::RAW_BYTE_LEN
358    }
359}
360
361#[cfg(feature = "experimental_traverse")]
362impl<'a> SomeTable<'a> for FdSelectFormat0<'a> {
363    fn type_name(&self) -> &str {
364        "FdSelectFormat0"
365    }
366    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
367        match idx {
368            0usize => Some(Field::new("format", self.format())),
369            1usize => Some(Field::new("fds", self.fds())),
370            _ => None,
371        }
372    }
373}
374
375#[cfg(feature = "experimental_traverse")]
376#[allow(clippy::needless_lifetimes)]
377impl<'a> std::fmt::Debug for FdSelectFormat0<'a> {
378    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
379        (self as &dyn SomeTable<'a>).fmt(f)
380    }
381}
382
383impl Format<u8> for FdSelectFormat3<'_> {
384    const FORMAT: u8 = 3;
385}
386
387impl<'a> MinByteRange<'a> for FdSelectFormat3<'a> {
388    fn min_byte_range(&self) -> Range<usize> {
389        0..self.sentinel_byte_range().end
390    }
391    fn min_table_bytes(&self) -> &'a [u8] {
392        let range = self.min_byte_range();
393        self.data.as_bytes().get(range).unwrap_or_default()
394    }
395}
396
397impl<'a> FontRead<'a> for FdSelectFormat3<'a> {
398    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
399        #[allow(clippy::absurd_extreme_comparisons)]
400        if data.len() < Self::MIN_SIZE {
401            return Err(ReadError::OutOfBounds);
402        }
403        Ok(Self { data })
404    }
405}
406
407/// FdSelect format 3.
408#[derive(Clone)]
409pub struct FdSelectFormat3<'a> {
410    data: FontData<'a>,
411}
412
413#[allow(clippy::needless_lifetimes)]
414impl<'a> FdSelectFormat3<'a> {
415    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
416    basic_table_impls!(impl_the_methods);
417
418    /// Format = 3.
419    pub fn format(&self) -> u8 {
420        let range = self.format_byte_range();
421        self.data.read_at(range.start).ok().unwrap()
422    }
423
424    /// Number of ranges.
425    pub fn n_ranges(&self) -> u16 {
426        let range = self.n_ranges_byte_range();
427        self.data.read_at(range.start).ok().unwrap()
428    }
429
430    /// Range3 array.
431    pub fn ranges(&self) -> &'a [FdSelectRange3] {
432        let range = self.ranges_byte_range();
433        self.data.read_array(range).ok().unwrap_or_default()
434    }
435
436    /// Sentinel GID. Set equal to the number of glyphs in the font.
437    pub fn sentinel(&self) -> u16 {
438        let range = self.sentinel_byte_range();
439        self.data.read_at(range.start).ok().unwrap_or_default()
440    }
441
442    pub fn format_byte_range(&self) -> Range<usize> {
443        let start = 0;
444        start..start + u8::RAW_BYTE_LEN
445    }
446
447    pub fn n_ranges_byte_range(&self) -> Range<usize> {
448        let start = self.format_byte_range().end;
449        start..start + u16::RAW_BYTE_LEN
450    }
451
452    pub fn ranges_byte_range(&self) -> Range<usize> {
453        let n_ranges = self.n_ranges();
454        let start = self.n_ranges_byte_range().end;
455        start..start + (n_ranges as usize).saturating_mul(FdSelectRange3::RAW_BYTE_LEN)
456    }
457
458    pub fn sentinel_byte_range(&self) -> Range<usize> {
459        let start = self.ranges_byte_range().end;
460        start..start + u16::RAW_BYTE_LEN
461    }
462}
463
464#[cfg(feature = "experimental_traverse")]
465impl<'a> SomeTable<'a> for FdSelectFormat3<'a> {
466    fn type_name(&self) -> &str {
467        "FdSelectFormat3"
468    }
469    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
470        match idx {
471            0usize => Some(Field::new("format", self.format())),
472            1usize => Some(Field::new("n_ranges", self.n_ranges())),
473            2usize => Some(Field::new(
474                "ranges",
475                traversal::FieldType::array_of_records(
476                    stringify!(FdSelectRange3),
477                    self.ranges(),
478                    self.offset_data(),
479                ),
480            )),
481            3usize => Some(Field::new("sentinel", self.sentinel())),
482            _ => None,
483        }
484    }
485}
486
487#[cfg(feature = "experimental_traverse")]
488#[allow(clippy::needless_lifetimes)]
489impl<'a> std::fmt::Debug for FdSelectFormat3<'a> {
490    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
491        (self as &dyn SomeTable<'a>).fmt(f)
492    }
493}
494
495/// Range struct for FdSelect format 3.
496#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
497#[repr(C)]
498#[repr(packed)]
499pub struct FdSelectRange3 {
500    /// First glyph index in range.
501    pub first: BigEndian<u16>,
502    /// FD index for all glyphs in range.
503    pub fd: u8,
504}
505
506impl FdSelectRange3 {
507    /// First glyph index in range.
508    pub fn first(&self) -> u16 {
509        self.first.get()
510    }
511
512    /// FD index for all glyphs in range.
513    pub fn fd(&self) -> u8 {
514        self.fd
515    }
516}
517
518impl FixedSize for FdSelectRange3 {
519    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
520}
521
522#[cfg(feature = "experimental_traverse")]
523impl<'a> SomeRecord<'a> for FdSelectRange3 {
524    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
525        RecordResolver {
526            name: "FdSelectRange3",
527            get_field: Box::new(move |idx, _data| match idx {
528                0usize => Some(Field::new("first", self.first())),
529                1usize => Some(Field::new("fd", self.fd())),
530                _ => None,
531            }),
532            data,
533        }
534    }
535}
536
537impl Format<u8> for FdSelectFormat4<'_> {
538    const FORMAT: u8 = 4;
539}
540
541impl<'a> MinByteRange<'a> for FdSelectFormat4<'a> {
542    fn min_byte_range(&self) -> Range<usize> {
543        0..self.sentinel_byte_range().end
544    }
545    fn min_table_bytes(&self) -> &'a [u8] {
546        let range = self.min_byte_range();
547        self.data.as_bytes().get(range).unwrap_or_default()
548    }
549}
550
551impl<'a> FontRead<'a> for FdSelectFormat4<'a> {
552    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
553        #[allow(clippy::absurd_extreme_comparisons)]
554        if data.len() < Self::MIN_SIZE {
555            return Err(ReadError::OutOfBounds);
556        }
557        Ok(Self { data })
558    }
559}
560
561/// FdSelect format 4.
562#[derive(Clone)]
563pub struct FdSelectFormat4<'a> {
564    data: FontData<'a>,
565}
566
567#[allow(clippy::needless_lifetimes)]
568impl<'a> FdSelectFormat4<'a> {
569    pub const MIN_SIZE: usize = (u8::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
570    basic_table_impls!(impl_the_methods);
571
572    /// Format = 4.
573    pub fn format(&self) -> u8 {
574        let range = self.format_byte_range();
575        self.data.read_at(range.start).ok().unwrap()
576    }
577
578    /// Number of ranges.
579    pub fn n_ranges(&self) -> u32 {
580        let range = self.n_ranges_byte_range();
581        self.data.read_at(range.start).ok().unwrap()
582    }
583
584    /// Range4 array.
585    pub fn ranges(&self) -> &'a [FdSelectRange4] {
586        let range = self.ranges_byte_range();
587        self.data.read_array(range).ok().unwrap_or_default()
588    }
589
590    /// Sentinel GID. Set equal to the number of glyphs in the font.
591    pub fn sentinel(&self) -> u32 {
592        let range = self.sentinel_byte_range();
593        self.data.read_at(range.start).ok().unwrap_or_default()
594    }
595
596    pub fn format_byte_range(&self) -> Range<usize> {
597        let start = 0;
598        start..start + u8::RAW_BYTE_LEN
599    }
600
601    pub fn n_ranges_byte_range(&self) -> Range<usize> {
602        let start = self.format_byte_range().end;
603        start..start + u32::RAW_BYTE_LEN
604    }
605
606    pub fn ranges_byte_range(&self) -> Range<usize> {
607        let n_ranges = self.n_ranges();
608        let start = self.n_ranges_byte_range().end;
609        start..start + (n_ranges as usize).saturating_mul(FdSelectRange4::RAW_BYTE_LEN)
610    }
611
612    pub fn sentinel_byte_range(&self) -> Range<usize> {
613        let start = self.ranges_byte_range().end;
614        start..start + u32::RAW_BYTE_LEN
615    }
616}
617
618#[cfg(feature = "experimental_traverse")]
619impl<'a> SomeTable<'a> for FdSelectFormat4<'a> {
620    fn type_name(&self) -> &str {
621        "FdSelectFormat4"
622    }
623    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
624        match idx {
625            0usize => Some(Field::new("format", self.format())),
626            1usize => Some(Field::new("n_ranges", self.n_ranges())),
627            2usize => Some(Field::new(
628                "ranges",
629                traversal::FieldType::array_of_records(
630                    stringify!(FdSelectRange4),
631                    self.ranges(),
632                    self.offset_data(),
633                ),
634            )),
635            3usize => Some(Field::new("sentinel", self.sentinel())),
636            _ => None,
637        }
638    }
639}
640
641#[cfg(feature = "experimental_traverse")]
642#[allow(clippy::needless_lifetimes)]
643impl<'a> std::fmt::Debug for FdSelectFormat4<'a> {
644    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
645        (self as &dyn SomeTable<'a>).fmt(f)
646    }
647}
648
649/// Range struct for FdSelect format 4.
650#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
651#[repr(C)]
652#[repr(packed)]
653pub struct FdSelectRange4 {
654    /// First glyph index in range.
655    pub first: BigEndian<u32>,
656    /// FD index for all glyphs in range.
657    pub fd: BigEndian<u16>,
658}
659
660impl FdSelectRange4 {
661    /// First glyph index in range.
662    pub fn first(&self) -> u32 {
663        self.first.get()
664    }
665
666    /// FD index for all glyphs in range.
667    pub fn fd(&self) -> u16 {
668        self.fd.get()
669    }
670}
671
672impl FixedSize for FdSelectRange4 {
673    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
674}
675
676#[cfg(feature = "experimental_traverse")]
677impl<'a> SomeRecord<'a> for FdSelectRange4 {
678    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
679        RecordResolver {
680            name: "FdSelectRange4",
681            get_field: Box::new(move |idx, _data| match idx {
682                0usize => Some(Field::new("first", self.first())),
683                1usize => Some(Field::new("fd", self.fd())),
684                _ => None,
685            }),
686            data,
687        }
688    }
689}
690
691/// Charset with custom glyph id to string id mappings.
692#[derive(Clone)]
693pub enum CustomCharset<'a> {
694    Format0(CharsetFormat0<'a>),
695    Format1(CharsetFormat1<'a>),
696    Format2(CharsetFormat2<'a>),
697}
698
699impl<'a> CustomCharset<'a> {
700    ///Return the `FontData` used to resolve offsets for this table.
701    pub fn offset_data(&self) -> FontData<'a> {
702        match self {
703            Self::Format0(item) => item.offset_data(),
704            Self::Format1(item) => item.offset_data(),
705            Self::Format2(item) => item.offset_data(),
706        }
707    }
708
709    /// Format; =0
710    pub fn format(&self) -> u8 {
711        match self {
712            Self::Format0(item) => item.format(),
713            Self::Format1(item) => item.format(),
714            Self::Format2(item) => item.format(),
715        }
716    }
717}
718
719impl<'a> FontRead<'a> for CustomCharset<'a> {
720    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
721        let format: u8 = data.read_at(0usize)?;
722        match format {
723            CharsetFormat0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
724            CharsetFormat1::FORMAT => Ok(Self::Format1(FontRead::read(data)?)),
725            CharsetFormat2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
726            other => Err(ReadError::InvalidFormat(other.into())),
727        }
728    }
729}
730
731impl<'a> MinByteRange<'a> for CustomCharset<'a> {
732    fn min_byte_range(&self) -> Range<usize> {
733        match self {
734            Self::Format0(item) => item.min_byte_range(),
735            Self::Format1(item) => item.min_byte_range(),
736            Self::Format2(item) => item.min_byte_range(),
737        }
738    }
739    fn min_table_bytes(&self) -> &'a [u8] {
740        match self {
741            Self::Format0(item) => item.min_table_bytes(),
742            Self::Format1(item) => item.min_table_bytes(),
743            Self::Format2(item) => item.min_table_bytes(),
744        }
745    }
746}
747
748#[cfg(feature = "experimental_traverse")]
749impl<'a> CustomCharset<'a> {
750    fn dyn_inner<'b>(&'b self) -> &'b dyn SomeTable<'a> {
751        match self {
752            Self::Format0(table) => table,
753            Self::Format1(table) => table,
754            Self::Format2(table) => table,
755        }
756    }
757}
758
759#[cfg(feature = "experimental_traverse")]
760impl std::fmt::Debug for CustomCharset<'_> {
761    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
762        self.dyn_inner().fmt(f)
763    }
764}
765
766#[cfg(feature = "experimental_traverse")]
767impl<'a> SomeTable<'a> for CustomCharset<'a> {
768    fn type_name(&self) -> &str {
769        self.dyn_inner().type_name()
770    }
771    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
772        self.dyn_inner().get_field(idx)
773    }
774}
775
776impl Format<u8> for CharsetFormat0<'_> {
777    const FORMAT: u8 = 0;
778}
779
780impl<'a> MinByteRange<'a> for CharsetFormat0<'a> {
781    fn min_byte_range(&self) -> Range<usize> {
782        0..self.glyph_byte_range().end
783    }
784    fn min_table_bytes(&self) -> &'a [u8] {
785        let range = self.min_byte_range();
786        self.data.as_bytes().get(range).unwrap_or_default()
787    }
788}
789
790impl<'a> FontRead<'a> for CharsetFormat0<'a> {
791    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
792        #[allow(clippy::absurd_extreme_comparisons)]
793        if data.len() < Self::MIN_SIZE {
794            return Err(ReadError::OutOfBounds);
795        }
796        Ok(Self { data })
797    }
798}
799
800/// Charset format 0.
801#[derive(Clone)]
802pub struct CharsetFormat0<'a> {
803    data: FontData<'a>,
804}
805
806#[allow(clippy::needless_lifetimes)]
807impl<'a> CharsetFormat0<'a> {
808    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
809    basic_table_impls!(impl_the_methods);
810
811    /// Format; =0
812    pub fn format(&self) -> u8 {
813        let range = self.format_byte_range();
814        self.data.read_at(range.start).ok().unwrap()
815    }
816
817    /// Glyph name array.
818    pub fn glyph(&self) -> &'a [BigEndian<u16>] {
819        let range = self.glyph_byte_range();
820        self.data.read_array(range).ok().unwrap_or_default()
821    }
822
823    pub fn format_byte_range(&self) -> Range<usize> {
824        let start = 0;
825        start..start + u8::RAW_BYTE_LEN
826    }
827
828    pub fn glyph_byte_range(&self) -> Range<usize> {
829        let start = self.format_byte_range().end;
830        start..start + self.data.len().saturating_sub(start) / u16::RAW_BYTE_LEN * u16::RAW_BYTE_LEN
831    }
832}
833
834#[cfg(feature = "experimental_traverse")]
835impl<'a> SomeTable<'a> for CharsetFormat0<'a> {
836    fn type_name(&self) -> &str {
837        "CharsetFormat0"
838    }
839    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
840        match idx {
841            0usize => Some(Field::new("format", self.format())),
842            1usize => Some(Field::new("glyph", self.glyph())),
843            _ => None,
844        }
845    }
846}
847
848#[cfg(feature = "experimental_traverse")]
849#[allow(clippy::needless_lifetimes)]
850impl<'a> std::fmt::Debug for CharsetFormat0<'a> {
851    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
852        (self as &dyn SomeTable<'a>).fmt(f)
853    }
854}
855
856impl Format<u8> for CharsetFormat1<'_> {
857    const FORMAT: u8 = 1;
858}
859
860impl<'a> MinByteRange<'a> for CharsetFormat1<'a> {
861    fn min_byte_range(&self) -> Range<usize> {
862        0..self.ranges_byte_range().end
863    }
864    fn min_table_bytes(&self) -> &'a [u8] {
865        let range = self.min_byte_range();
866        self.data.as_bytes().get(range).unwrap_or_default()
867    }
868}
869
870impl<'a> FontRead<'a> for CharsetFormat1<'a> {
871    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
872        #[allow(clippy::absurd_extreme_comparisons)]
873        if data.len() < Self::MIN_SIZE {
874            return Err(ReadError::OutOfBounds);
875        }
876        Ok(Self { data })
877    }
878}
879
880/// Charset format 1.
881#[derive(Clone)]
882pub struct CharsetFormat1<'a> {
883    data: FontData<'a>,
884}
885
886#[allow(clippy::needless_lifetimes)]
887impl<'a> CharsetFormat1<'a> {
888    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
889    basic_table_impls!(impl_the_methods);
890
891    /// Format; =1
892    pub fn format(&self) -> u8 {
893        let range = self.format_byte_range();
894        self.data.read_at(range.start).ok().unwrap()
895    }
896
897    /// Range1 array.
898    pub fn ranges(&self) -> &'a [CharsetRange1] {
899        let range = self.ranges_byte_range();
900        self.data.read_array(range).ok().unwrap_or_default()
901    }
902
903    pub fn format_byte_range(&self) -> Range<usize> {
904        let start = 0;
905        start..start + u8::RAW_BYTE_LEN
906    }
907
908    pub fn ranges_byte_range(&self) -> Range<usize> {
909        let start = self.format_byte_range().end;
910        start
911            ..start
912                + self.data.len().saturating_sub(start) / CharsetRange1::RAW_BYTE_LEN
913                    * CharsetRange1::RAW_BYTE_LEN
914    }
915}
916
917#[cfg(feature = "experimental_traverse")]
918impl<'a> SomeTable<'a> for CharsetFormat1<'a> {
919    fn type_name(&self) -> &str {
920        "CharsetFormat1"
921    }
922    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
923        match idx {
924            0usize => Some(Field::new("format", self.format())),
925            1usize => Some(Field::new(
926                "ranges",
927                traversal::FieldType::array_of_records(
928                    stringify!(CharsetRange1),
929                    self.ranges(),
930                    self.offset_data(),
931                ),
932            )),
933            _ => None,
934        }
935    }
936}
937
938#[cfg(feature = "experimental_traverse")]
939#[allow(clippy::needless_lifetimes)]
940impl<'a> std::fmt::Debug for CharsetFormat1<'a> {
941    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
942        (self as &dyn SomeTable<'a>).fmt(f)
943    }
944}
945
946/// Range struct for Charset format 1.
947#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
948#[repr(C)]
949#[repr(packed)]
950pub struct CharsetRange1 {
951    /// First glyph in range.
952    pub first: BigEndian<u16>,
953    /// Glyphs left in range (excluding first).
954    pub n_left: u8,
955}
956
957impl CharsetRange1 {
958    /// First glyph in range.
959    pub fn first(&self) -> u16 {
960        self.first.get()
961    }
962
963    /// Glyphs left in range (excluding first).
964    pub fn n_left(&self) -> u8 {
965        self.n_left
966    }
967}
968
969impl FixedSize for CharsetRange1 {
970    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
971}
972
973#[cfg(feature = "experimental_traverse")]
974impl<'a> SomeRecord<'a> for CharsetRange1 {
975    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
976        RecordResolver {
977            name: "CharsetRange1",
978            get_field: Box::new(move |idx, _data| match idx {
979                0usize => Some(Field::new("first", self.first())),
980                1usize => Some(Field::new("n_left", self.n_left())),
981                _ => None,
982            }),
983            data,
984        }
985    }
986}
987
988impl Format<u8> for CharsetFormat2<'_> {
989    const FORMAT: u8 = 2;
990}
991
992impl<'a> MinByteRange<'a> for CharsetFormat2<'a> {
993    fn min_byte_range(&self) -> Range<usize> {
994        0..self.ranges_byte_range().end
995    }
996    fn min_table_bytes(&self) -> &'a [u8] {
997        let range = self.min_byte_range();
998        self.data.as_bytes().get(range).unwrap_or_default()
999    }
1000}
1001
1002impl<'a> FontRead<'a> for CharsetFormat2<'a> {
1003    fn read(data: FontData<'a>) -> Result<Self, ReadError> {
1004        #[allow(clippy::absurd_extreme_comparisons)]
1005        if data.len() < Self::MIN_SIZE {
1006            return Err(ReadError::OutOfBounds);
1007        }
1008        Ok(Self { data })
1009    }
1010}
1011
1012/// Charset format 2.
1013#[derive(Clone)]
1014pub struct CharsetFormat2<'a> {
1015    data: FontData<'a>,
1016}
1017
1018#[allow(clippy::needless_lifetimes)]
1019impl<'a> CharsetFormat2<'a> {
1020    pub const MIN_SIZE: usize = u8::RAW_BYTE_LEN;
1021    basic_table_impls!(impl_the_methods);
1022
1023    /// Format; =2
1024    pub fn format(&self) -> u8 {
1025        let range = self.format_byte_range();
1026        self.data.read_at(range.start).ok().unwrap()
1027    }
1028
1029    /// Range2 array.
1030    pub fn ranges(&self) -> &'a [CharsetRange2] {
1031        let range = self.ranges_byte_range();
1032        self.data.read_array(range).ok().unwrap_or_default()
1033    }
1034
1035    pub fn format_byte_range(&self) -> Range<usize> {
1036        let start = 0;
1037        start..start + u8::RAW_BYTE_LEN
1038    }
1039
1040    pub fn ranges_byte_range(&self) -> Range<usize> {
1041        let start = self.format_byte_range().end;
1042        start
1043            ..start
1044                + self.data.len().saturating_sub(start) / CharsetRange2::RAW_BYTE_LEN
1045                    * CharsetRange2::RAW_BYTE_LEN
1046    }
1047}
1048
1049#[cfg(feature = "experimental_traverse")]
1050impl<'a> SomeTable<'a> for CharsetFormat2<'a> {
1051    fn type_name(&self) -> &str {
1052        "CharsetFormat2"
1053    }
1054    fn get_field(&self, idx: usize) -> Option<Field<'a>> {
1055        match idx {
1056            0usize => Some(Field::new("format", self.format())),
1057            1usize => Some(Field::new(
1058                "ranges",
1059                traversal::FieldType::array_of_records(
1060                    stringify!(CharsetRange2),
1061                    self.ranges(),
1062                    self.offset_data(),
1063                ),
1064            )),
1065            _ => None,
1066        }
1067    }
1068}
1069
1070#[cfg(feature = "experimental_traverse")]
1071#[allow(clippy::needless_lifetimes)]
1072impl<'a> std::fmt::Debug for CharsetFormat2<'a> {
1073    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1074        (self as &dyn SomeTable<'a>).fmt(f)
1075    }
1076}
1077
1078/// Range struct for Charset format 2.
1079#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1080#[repr(C)]
1081#[repr(packed)]
1082pub struct CharsetRange2 {
1083    /// First glyph in range.
1084    pub first: BigEndian<u16>,
1085    /// Glyphs left in range (excluding first).
1086    pub n_left: BigEndian<u16>,
1087}
1088
1089impl CharsetRange2 {
1090    /// First glyph in range.
1091    pub fn first(&self) -> u16 {
1092        self.first.get()
1093    }
1094
1095    /// Glyphs left in range (excluding first).
1096    pub fn n_left(&self) -> u16 {
1097        self.n_left.get()
1098    }
1099}
1100
1101impl FixedSize for CharsetRange2 {
1102    const RAW_BYTE_LEN: usize = u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1103}
1104
1105#[cfg(feature = "experimental_traverse")]
1106impl<'a> SomeRecord<'a> for CharsetRange2 {
1107    fn traverse(self, data: FontData<'a>) -> RecordResolver<'a> {
1108        RecordResolver {
1109            name: "CharsetRange2",
1110            get_field: Box::new(move |idx, _data| match idx {
1111                0usize => Some(Field::new("first", self.first())),
1112                1usize => Some(Field::new("n_left", self.n_left())),
1113                _ => None,
1114            }),
1115            data,
1116        }
1117    }
1118}