Skip to main content

read_fonts/generated/
generated_cmap.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 Cmap<'a> {
9    fn min_byte_range(&self) -> Range<usize> {
10        0..self.encoding_records_byte_range().end
11    }
12    fn min_table_bytes(&self) -> &'a [u8] {
13        let range = self.min_byte_range();
14        self.offset_data().as_bytes().get(range).unwrap_or_default()
15    }
16}
17
18impl TopLevelTable for Cmap<'_> {
19    /// `cmap`
20    const TAG: Tag = Tag::new(b"cmap");
21}
22
23impl ReadArgs for Cmap<'_> {
24    type Args = ();
25}
26
27impl<'a> FontRead<'a> for Cmap<'a> {
28    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
29        #[allow(clippy::absurd_extreme_comparisons)]
30        if data.len() < Self::MIN_SIZE {
31            return Err(ReadError::OutOfBounds);
32        }
33        let Some(data) = TableDataRef::new(data.as_bytes()) else {
34            return Err(ReadError::OutOfBounds);
35        };
36        Ok(Self { data })
37    }
38}
39
40/// The fields at the start of the table, which are read directly.
41#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
42#[repr(C, packed)]
43#[doc(hidden)]
44pub struct CmapFixedHeader {
45    pub version: BigEndian<u16>,
46    pub num_tables: BigEndian<u16>,
47}
48
49#[allow(clippy::absurd_extreme_comparisons)]
50const _: () = assert!(std::mem::size_of::<CmapFixedHeader>() <= Cmap::MIN_SIZE);
51
52/// [cmap](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#overview)
53#[derive(Clone)]
54pub struct Cmap<'a> {
55    data: TableDataRef<'a, CmapFixedHeader>,
56}
57
58#[allow(clippy::needless_lifetimes)]
59impl<'a> Cmap<'a> {
60    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN);
61    basic_table_impls!(impl_the_methods);
62
63    /// Table version number (0).
64    pub fn version(&self) -> u16 {
65        self.data.header().version.get()
66    }
67
68    /// Number of encoding tables that follow.
69    pub fn num_tables(&self) -> u16 {
70        self.data.header().num_tables.get()
71    }
72
73    pub fn encoding_records(&self) -> &'a [EncodingRecord] {
74        let range = self.encoding_records_byte_range();
75        self.offset_data()
76            .read_array(range)
77            .ok()
78            .unwrap_or_default()
79    }
80
81    pub fn version_byte_range(&self) -> Range<usize> {
82        let start = 0;
83        let end = start + u16::RAW_BYTE_LEN;
84        start..end
85    }
86
87    pub fn num_tables_byte_range(&self) -> Range<usize> {
88        let start = self.version_byte_range().end;
89        let end = start + u16::RAW_BYTE_LEN;
90        start..end
91    }
92
93    pub fn encoding_records_byte_range(&self) -> Range<usize> {
94        let num_tables = self.num_tables();
95        let start = self.num_tables_byte_range().end;
96        let end =
97            start + (transforms::to_usize(num_tables)).saturating_mul(EncodingRecord::RAW_BYTE_LEN);
98        start..end
99    }
100}
101
102const _: () = assert!(FontData::default_data_long_enough(Cmap::MIN_SIZE));
103
104impl Default for Cmap<'_> {
105    fn default() -> Self {
106        Self {
107            data: TableDataRef::new(FontData::default_table_data().as_bytes())
108                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
109        }
110    }
111}
112
113/// [Encoding Record](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#encoding-records-and-encodings)
114#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
115#[repr(C)]
116#[repr(packed)]
117pub struct EncodingRecord {
118    /// Platform ID.
119    pub platform_id: BigEndian<PlatformId>,
120    /// Platform-specific encoding ID.
121    pub encoding_id: BigEndian<u16>,
122    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
123    /// encoding.
124    pub subtable_offset: BigEndian<Offset32>,
125}
126
127impl EncodingRecord {
128    /// Platform ID.
129    pub fn platform_id(&self) -> PlatformId {
130        self.platform_id.get()
131    }
132
133    /// Platform-specific encoding ID.
134    pub fn encoding_id(&self) -> u16 {
135        self.encoding_id.get()
136    }
137
138    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
139    /// encoding.
140    pub fn subtable_offset(&self) -> Offset32 {
141        self.subtable_offset.get()
142    }
143
144    /// Byte offset from beginning of the [`Cmap`] table to the subtable for this
145    /// encoding.
146    ///
147    /// The `data` argument should be retrieved from the parent table
148    /// By calling its `offset_data` method.
149    pub fn subtable<'a>(&self, data: FontData<'a>) -> Result<CmapSubtable<'a>, ReadError> {
150        self.subtable_offset().resolve(data)
151    }
152}
153
154impl FixedSize for EncodingRecord {
155    const RAW_BYTE_LEN: usize =
156        PlatformId::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
157}
158
159/// <https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#platform-ids>
160#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
161#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
162#[repr(u16)]
163#[allow(clippy::manual_non_exhaustive)]
164pub enum PlatformId {
165    #[default]
166    Unicode = 0,
167    Macintosh = 1,
168    ISO = 2,
169    Windows = 3,
170    Custom = 4,
171    #[doc(hidden)]
172    /// If font data is malformed we will map unknown values to this variant
173    Unknown,
174}
175
176impl PlatformId {
177    /// Create from a raw scalar.
178    ///
179    /// This will never fail; unknown values will be mapped to the `Unknown` variant
180    pub fn new(raw: u16) -> Self {
181        match raw {
182            0 => Self::Unicode,
183            1 => Self::Macintosh,
184            2 => Self::ISO,
185            3 => Self::Windows,
186            4 => Self::Custom,
187            _ => Self::Unknown,
188        }
189    }
190}
191
192impl font_types::Scalar for PlatformId {
193    type Raw = <u16 as font_types::Scalar>::Raw;
194    fn to_raw(self) -> Self::Raw {
195        (self as u16).to_raw()
196    }
197    fn from_raw(raw: Self::Raw) -> Self {
198        let t = <u16>::from_raw(raw);
199        Self::new(t)
200    }
201}
202
203/// The different cmap subtable formats.
204#[derive(Clone)]
205pub enum CmapSubtable<'a> {
206    Format0(Cmap0<'a>),
207    Format2(Cmap2<'a>),
208    Format4(Cmap4<'a>),
209    Format6(Cmap6<'a>),
210    Format8(Cmap8<'a>),
211    Format10(Cmap10<'a>),
212    Format12(Cmap12<'a>),
213    Format13(Cmap13<'a>),
214    Format14(Cmap14<'a>),
215}
216
217impl Default for CmapSubtable<'_> {
218    fn default() -> Self {
219        Self::Format0(Default::default())
220    }
221}
222
223impl<'a> CmapSubtable<'a> {
224    ///Return the `FontData` used to resolve offsets for this table.
225    pub fn offset_data(&self) -> FontData<'a> {
226        match self {
227            Self::Format0(item) => item.offset_data(),
228            Self::Format2(item) => item.offset_data(),
229            Self::Format4(item) => item.offset_data(),
230            Self::Format6(item) => item.offset_data(),
231            Self::Format8(item) => item.offset_data(),
232            Self::Format10(item) => item.offset_data(),
233            Self::Format12(item) => item.offset_data(),
234            Self::Format13(item) => item.offset_data(),
235            Self::Format14(item) => item.offset_data(),
236        }
237    }
238
239    /// Format number is set to 0.
240    pub fn format(&self) -> u16 {
241        match self {
242            Self::Format0(item) => item.format(),
243            Self::Format2(item) => item.format(),
244            Self::Format4(item) => item.format(),
245            Self::Format6(item) => item.format(),
246            Self::Format8(item) => item.format(),
247            Self::Format10(item) => item.format(),
248            Self::Format12(item) => item.format(),
249            Self::Format13(item) => item.format(),
250            Self::Format14(item) => item.format(),
251        }
252    }
253}
254
255impl ReadArgs for CmapSubtable<'_> {
256    type Args = ();
257}
258
259impl<'a> FontRead<'a> for CmapSubtable<'a> {
260    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
261        let format: u16 = data.read_at(0usize)?;
262        match format {
263            Cmap0::FORMAT => Ok(Self::Format0(FontRead::read(data)?)),
264            Cmap2::FORMAT => Ok(Self::Format2(FontRead::read(data)?)),
265            Cmap4::FORMAT => Ok(Self::Format4(FontRead::read(data)?)),
266            Cmap6::FORMAT => Ok(Self::Format6(FontRead::read(data)?)),
267            Cmap8::FORMAT => Ok(Self::Format8(FontRead::read(data)?)),
268            Cmap10::FORMAT => Ok(Self::Format10(FontRead::read(data)?)),
269            Cmap12::FORMAT => Ok(Self::Format12(FontRead::read(data)?)),
270            Cmap13::FORMAT => Ok(Self::Format13(FontRead::read(data)?)),
271            Cmap14::FORMAT => Ok(Self::Format14(FontRead::read(data)?)),
272            other => Err(ReadError::InvalidFormat(other.into())),
273        }
274    }
275}
276
277impl<'a> MinByteRange<'a> for CmapSubtable<'a> {
278    fn min_byte_range(&self) -> Range<usize> {
279        match self {
280            Self::Format0(item) => item.min_byte_range(),
281            Self::Format2(item) => item.min_byte_range(),
282            Self::Format4(item) => item.min_byte_range(),
283            Self::Format6(item) => item.min_byte_range(),
284            Self::Format8(item) => item.min_byte_range(),
285            Self::Format10(item) => item.min_byte_range(),
286            Self::Format12(item) => item.min_byte_range(),
287            Self::Format13(item) => item.min_byte_range(),
288            Self::Format14(item) => item.min_byte_range(),
289        }
290    }
291    fn min_table_bytes(&self) -> &'a [u8] {
292        match self {
293            Self::Format0(item) => item.min_table_bytes(),
294            Self::Format2(item) => item.min_table_bytes(),
295            Self::Format4(item) => item.min_table_bytes(),
296            Self::Format6(item) => item.min_table_bytes(),
297            Self::Format8(item) => item.min_table_bytes(),
298            Self::Format10(item) => item.min_table_bytes(),
299            Self::Format12(item) => item.min_table_bytes(),
300            Self::Format13(item) => item.min_table_bytes(),
301            Self::Format14(item) => item.min_table_bytes(),
302        }
303    }
304}
305
306impl Format<u16> for Cmap0<'_> {
307    const FORMAT: u16 = 0;
308}
309
310impl<'a> MinByteRange<'a> for Cmap0<'a> {
311    fn min_byte_range(&self) -> Range<usize> {
312        0..self.glyph_id_array_byte_range().end
313    }
314    fn min_table_bytes(&self) -> &'a [u8] {
315        let range = self.min_byte_range();
316        self.offset_data().as_bytes().get(range).unwrap_or_default()
317    }
318}
319
320impl ReadArgs for Cmap0<'_> {
321    type Args = ();
322}
323
324impl<'a> FontRead<'a> for Cmap0<'a> {
325    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
326        #[allow(clippy::absurd_extreme_comparisons)]
327        if data.len() < Self::MIN_SIZE {
328            return Err(ReadError::OutOfBounds);
329        }
330        let Some(data) = TableDataRef::new(data.as_bytes()) else {
331            return Err(ReadError::OutOfBounds);
332        };
333        Ok(Self { data })
334    }
335}
336
337/// The fields at the start of the table, which are read directly.
338#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
339#[repr(C, packed)]
340#[doc(hidden)]
341pub struct Cmap0FixedHeader {
342    pub format: BigEndian<u16>,
343    pub length: BigEndian<u16>,
344    pub language: BigEndian<u16>,
345}
346
347#[allow(clippy::absurd_extreme_comparisons)]
348const _: () = assert!(std::mem::size_of::<Cmap0FixedHeader>() <= Cmap0::MIN_SIZE);
349
350/// [cmap Format 0](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-0-byte-encoding-table): Byte encoding table
351#[derive(Clone)]
352pub struct Cmap0<'a> {
353    data: TableDataRef<'a, Cmap0FixedHeader>,
354}
355
356#[allow(clippy::needless_lifetimes)]
357impl<'a> Cmap0<'a> {
358    pub const MIN_SIZE: usize =
359        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u8::RAW_BYTE_LEN * 256_usize);
360    basic_table_impls!(impl_the_methods);
361
362    /// Format number is set to 0.
363    pub fn format(&self) -> u16 {
364        self.data.header().format.get()
365    }
366
367    /// This is the length in bytes of the subtable.
368    pub fn length(&self) -> u16 {
369        self.data.header().length.get()
370    }
371
372    /// For requirements on use of the language field, see “Use of
373    /// the language field in 'cmap' subtables” in this document.
374    pub fn language(&self) -> u16 {
375        self.data.header().language.get()
376    }
377
378    /// An array that maps character codes to glyph index values.
379    pub fn glyph_id_array(&self) -> &'a [u8] {
380        let range = self.glyph_id_array_byte_range();
381        self.offset_data()
382            .read_array(range)
383            .ok()
384            .unwrap_or_default()
385    }
386
387    pub fn format_byte_range(&self) -> Range<usize> {
388        let start = 0;
389        let end = start + u16::RAW_BYTE_LEN;
390        start..end
391    }
392
393    pub fn length_byte_range(&self) -> Range<usize> {
394        let start = self.format_byte_range().end;
395        let end = start + u16::RAW_BYTE_LEN;
396        start..end
397    }
398
399    pub fn language_byte_range(&self) -> Range<usize> {
400        let start = self.length_byte_range().end;
401        let end = start + u16::RAW_BYTE_LEN;
402        start..end
403    }
404
405    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
406        let start = self.language_byte_range().end;
407        let end = start + (256_usize).saturating_mul(u8::RAW_BYTE_LEN);
408        start..end
409    }
410}
411
412const _: () = assert!(FontData::default_data_long_enough(Cmap0::MIN_SIZE));
413
414impl Default for Cmap0<'_> {
415    fn default() -> Self {
416        Self {
417            data: TableDataRef::new(FontData::default_table_data().as_bytes())
418                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
419        }
420    }
421}
422
423impl Format<u16> for Cmap2<'_> {
424    const FORMAT: u16 = 2;
425}
426
427impl<'a> MinByteRange<'a> for Cmap2<'a> {
428    fn min_byte_range(&self) -> Range<usize> {
429        0..self.sub_header_keys_byte_range().end
430    }
431    fn min_table_bytes(&self) -> &'a [u8] {
432        let range = self.min_byte_range();
433        self.offset_data().as_bytes().get(range).unwrap_or_default()
434    }
435}
436
437impl ReadArgs for Cmap2<'_> {
438    type Args = ();
439}
440
441impl<'a> FontRead<'a> for Cmap2<'a> {
442    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
443        #[allow(clippy::absurd_extreme_comparisons)]
444        if data.len() < Self::MIN_SIZE {
445            return Err(ReadError::OutOfBounds);
446        }
447        let Some(data) = TableDataRef::new(data.as_bytes()) else {
448            return Err(ReadError::OutOfBounds);
449        };
450        Ok(Self { data })
451    }
452}
453
454/// The fields at the start of the table, which are read directly.
455#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
456#[repr(C, packed)]
457#[doc(hidden)]
458pub struct Cmap2FixedHeader {
459    pub format: BigEndian<u16>,
460    pub length: BigEndian<u16>,
461    pub language: BigEndian<u16>,
462}
463
464#[allow(clippy::absurd_extreme_comparisons)]
465const _: () = assert!(std::mem::size_of::<Cmap2FixedHeader>() <= Cmap2::MIN_SIZE);
466
467/// [cmap Format 2](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-2-high-byte-mapping-through-table): High-byte mapping through table
468#[derive(Clone)]
469pub struct Cmap2<'a> {
470    data: TableDataRef<'a, Cmap2FixedHeader>,
471}
472
473#[allow(clippy::needless_lifetimes)]
474impl<'a> Cmap2<'a> {
475    pub const MIN_SIZE: usize =
476        (u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN * 256_usize);
477    basic_table_impls!(impl_the_methods);
478
479    /// Format number is set to 2.
480    pub fn format(&self) -> u16 {
481        self.data.header().format.get()
482    }
483
484    /// This is the length in bytes of the subtable.
485    pub fn length(&self) -> u16 {
486        self.data.header().length.get()
487    }
488
489    /// For requirements on use of the language field, see “Use of
490    /// the language field in 'cmap' subtables” in this document.
491    pub fn language(&self) -> u16 {
492        self.data.header().language.get()
493    }
494
495    /// Array that maps high bytes to subHeaders: value is subHeader
496    /// index × 8.
497    pub fn sub_header_keys(&self) -> &'a [BigEndian<u16>] {
498        let range = self.sub_header_keys_byte_range();
499        self.offset_data()
500            .read_array(range)
501            .ok()
502            .unwrap_or_default()
503    }
504
505    pub fn format_byte_range(&self) -> Range<usize> {
506        let start = 0;
507        let end = start + u16::RAW_BYTE_LEN;
508        start..end
509    }
510
511    pub fn length_byte_range(&self) -> Range<usize> {
512        let start = self.format_byte_range().end;
513        let end = start + u16::RAW_BYTE_LEN;
514        start..end
515    }
516
517    pub fn language_byte_range(&self) -> Range<usize> {
518        let start = self.length_byte_range().end;
519        let end = start + u16::RAW_BYTE_LEN;
520        start..end
521    }
522
523    pub fn sub_header_keys_byte_range(&self) -> Range<usize> {
524        let start = self.language_byte_range().end;
525        let end = start + (256_usize).saturating_mul(u16::RAW_BYTE_LEN);
526        start..end
527    }
528}
529
530/// Part of [Cmap2]
531#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
532#[repr(C)]
533#[repr(packed)]
534pub struct SubHeader {
535    /// First valid low byte for this SubHeader.
536    pub first_code: BigEndian<u16>,
537    /// Number of valid low bytes for this SubHeader.
538    pub entry_count: BigEndian<u16>,
539    /// See text below.
540    pub id_delta: BigEndian<i16>,
541    /// See text below.
542    pub id_range_offset: BigEndian<u16>,
543}
544
545impl SubHeader {
546    /// First valid low byte for this SubHeader.
547    pub fn first_code(&self) -> u16 {
548        self.first_code.get()
549    }
550
551    /// Number of valid low bytes for this SubHeader.
552    pub fn entry_count(&self) -> u16 {
553        self.entry_count.get()
554    }
555
556    /// See text below.
557    pub fn id_delta(&self) -> i16 {
558        self.id_delta.get()
559    }
560
561    /// See text below.
562    pub fn id_range_offset(&self) -> u16 {
563        self.id_range_offset.get()
564    }
565}
566
567impl FixedSize for SubHeader {
568    const RAW_BYTE_LEN: usize =
569        u16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN + i16::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
570}
571
572impl Format<u16> for Cmap4<'_> {
573    const FORMAT: u16 = 4;
574}
575
576impl<'a> MinByteRange<'a> for Cmap4<'a> {
577    fn min_byte_range(&self) -> Range<usize> {
578        0..self.glyph_id_array_byte_range().end
579    }
580    fn min_table_bytes(&self) -> &'a [u8] {
581        let range = self.min_byte_range();
582        self.offset_data().as_bytes().get(range).unwrap_or_default()
583    }
584}
585
586impl ReadArgs for Cmap4<'_> {
587    type Args = ();
588}
589
590impl<'a> FontRead<'a> for Cmap4<'a> {
591    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
592        #[allow(clippy::absurd_extreme_comparisons)]
593        if data.len() < Self::MIN_SIZE {
594            return Err(ReadError::OutOfBounds);
595        }
596        let Some(data) = TableDataRef::new(data.as_bytes()) else {
597            return Err(ReadError::OutOfBounds);
598        };
599        Ok(Self { data })
600    }
601}
602
603/// The fields at the start of the table, which are read directly.
604#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
605#[repr(C, packed)]
606#[doc(hidden)]
607pub struct Cmap4FixedHeader {
608    pub format: BigEndian<u16>,
609    pub length: BigEndian<u16>,
610    pub language: BigEndian<u16>,
611    pub seg_count_x2: BigEndian<u16>,
612    pub search_range: BigEndian<u16>,
613    pub entry_selector: BigEndian<u16>,
614    pub range_shift: BigEndian<u16>,
615}
616
617#[allow(clippy::absurd_extreme_comparisons)]
618const _: () = assert!(std::mem::size_of::<Cmap4FixedHeader>() <= Cmap4::MIN_SIZE);
619
620/// [cmap Format 4](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-4-segment-mapping-to-delta-values): Segment mapping to delta values
621#[derive(Clone)]
622pub struct Cmap4<'a> {
623    data: TableDataRef<'a, Cmap4FixedHeader>,
624}
625
626#[allow(clippy::needless_lifetimes)]
627impl<'a> Cmap4<'a> {
628    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
629        + u16::RAW_BYTE_LEN
630        + u16::RAW_BYTE_LEN
631        + u16::RAW_BYTE_LEN
632        + u16::RAW_BYTE_LEN
633        + u16::RAW_BYTE_LEN
634        + u16::RAW_BYTE_LEN
635        + u16::RAW_BYTE_LEN);
636    basic_table_impls!(impl_the_methods);
637
638    /// Format number is set to 4.
639    pub fn format(&self) -> u16 {
640        self.data.header().format.get()
641    }
642
643    /// This is the length in bytes of the subtable.
644    pub fn length(&self) -> u16 {
645        self.data.header().length.get()
646    }
647
648    /// For requirements on use of the language field, see “Use of
649    /// the language field in 'cmap' subtables” in this document.
650    pub fn language(&self) -> u16 {
651        self.data.header().language.get()
652    }
653
654    /// 2 × segCount.
655    pub fn seg_count_x2(&self) -> u16 {
656        self.data.header().seg_count_x2.get()
657    }
658
659    /// Maximum power of 2 less than or equal to segCount, times 2
660    /// ((2**floor(log2(segCount))) * 2, where “**” is an
661    /// exponentiation operator)
662    pub fn search_range(&self) -> u16 {
663        self.data.header().search_range.get()
664    }
665
666    /// Log2 of the maximum power of 2 less than or equal to numTables
667    /// (log2(searchRange/2), which is equal to floor(log2(segCount)))
668    pub fn entry_selector(&self) -> u16 {
669        self.data.header().entry_selector.get()
670    }
671
672    /// segCount times 2, minus searchRange ((segCount * 2) -
673    /// searchRange)
674    pub fn range_shift(&self) -> u16 {
675        self.data.header().range_shift.get()
676    }
677
678    /// End characterCode for each segment, last=0xFFFF.
679    pub fn end_code(&self) -> &'a [BigEndian<u16>] {
680        let range = self.end_code_byte_range();
681        self.offset_data()
682            .read_array(range)
683            .ok()
684            .unwrap_or_default()
685    }
686
687    /// Start character code for each segment.
688    pub fn start_code(&self) -> &'a [BigEndian<u16>] {
689        let range = self.start_code_byte_range();
690        self.offset_data()
691            .read_array(range)
692            .ok()
693            .unwrap_or_default()
694    }
695
696    /// Delta for all character codes in segment.
697    pub fn id_delta(&self) -> &'a [BigEndian<i16>] {
698        let range = self.id_delta_byte_range();
699        self.offset_data()
700            .read_array(range)
701            .ok()
702            .unwrap_or_default()
703    }
704
705    /// Offsets into glyphIdArray or 0
706    pub fn id_range_offsets(&self) -> &'a [BigEndian<u16>] {
707        let range = self.id_range_offsets_byte_range();
708        self.offset_data()
709            .read_array(range)
710            .ok()
711            .unwrap_or_default()
712    }
713
714    /// Glyph index array (arbitrary length)
715    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
716        let range = self.glyph_id_array_byte_range();
717        self.offset_data()
718            .read_array(range)
719            .ok()
720            .unwrap_or_default()
721    }
722
723    pub fn format_byte_range(&self) -> Range<usize> {
724        let start = 0;
725        let end = start + u16::RAW_BYTE_LEN;
726        start..end
727    }
728
729    pub fn length_byte_range(&self) -> Range<usize> {
730        let start = self.format_byte_range().end;
731        let end = start + u16::RAW_BYTE_LEN;
732        start..end
733    }
734
735    pub fn language_byte_range(&self) -> Range<usize> {
736        let start = self.length_byte_range().end;
737        let end = start + u16::RAW_BYTE_LEN;
738        start..end
739    }
740
741    pub fn seg_count_x2_byte_range(&self) -> Range<usize> {
742        let start = self.language_byte_range().end;
743        let end = start + u16::RAW_BYTE_LEN;
744        start..end
745    }
746
747    pub fn search_range_byte_range(&self) -> Range<usize> {
748        let start = self.seg_count_x2_byte_range().end;
749        let end = start + u16::RAW_BYTE_LEN;
750        start..end
751    }
752
753    pub fn entry_selector_byte_range(&self) -> Range<usize> {
754        let start = self.search_range_byte_range().end;
755        let end = start + u16::RAW_BYTE_LEN;
756        start..end
757    }
758
759    pub fn range_shift_byte_range(&self) -> Range<usize> {
760        let start = self.entry_selector_byte_range().end;
761        let end = start + u16::RAW_BYTE_LEN;
762        start..end
763    }
764
765    pub fn end_code_byte_range(&self) -> Range<usize> {
766        let seg_count_x2 = self.seg_count_x2();
767        let start = self.range_shift_byte_range().end;
768        let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
769        start..end
770    }
771
772    pub fn reserved_pad_byte_range(&self) -> Range<usize> {
773        let start = self.end_code_byte_range().end;
774        let end = start + u16::RAW_BYTE_LEN;
775        start..end
776    }
777
778    pub fn start_code_byte_range(&self) -> Range<usize> {
779        let seg_count_x2 = self.seg_count_x2();
780        let start = self.reserved_pad_byte_range().end;
781        let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
782        start..end
783    }
784
785    pub fn id_delta_byte_range(&self) -> Range<usize> {
786        let seg_count_x2 = self.seg_count_x2();
787        let start = self.start_code_byte_range().end;
788        let end = start + (transforms::half(seg_count_x2)).saturating_mul(i16::RAW_BYTE_LEN);
789        start..end
790    }
791
792    pub fn id_range_offsets_byte_range(&self) -> Range<usize> {
793        let seg_count_x2 = self.seg_count_x2();
794        let start = self.id_delta_byte_range().end;
795        let end = start + (transforms::half(seg_count_x2)).saturating_mul(u16::RAW_BYTE_LEN);
796        start..end
797    }
798
799    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
800        let start = self.id_range_offsets_byte_range().end;
801        let end = start
802            + self.offset_data().len().saturating_sub(start) / u16::RAW_BYTE_LEN
803                * u16::RAW_BYTE_LEN;
804        start..end
805    }
806}
807
808impl Format<u16> for Cmap6<'_> {
809    const FORMAT: u16 = 6;
810}
811
812impl<'a> MinByteRange<'a> for Cmap6<'a> {
813    fn min_byte_range(&self) -> Range<usize> {
814        0..self.glyph_id_array_byte_range().end
815    }
816    fn min_table_bytes(&self) -> &'a [u8] {
817        let range = self.min_byte_range();
818        self.offset_data().as_bytes().get(range).unwrap_or_default()
819    }
820}
821
822impl ReadArgs for Cmap6<'_> {
823    type Args = ();
824}
825
826impl<'a> FontRead<'a> for Cmap6<'a> {
827    fn read_with_args(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        let Some(data) = TableDataRef::new(data.as_bytes()) else {
833            return Err(ReadError::OutOfBounds);
834        };
835        Ok(Self { data })
836    }
837}
838
839/// The fields at the start of the table, which are read directly.
840#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
841#[repr(C, packed)]
842#[doc(hidden)]
843pub struct Cmap6FixedHeader {
844    pub format: BigEndian<u16>,
845    pub length: BigEndian<u16>,
846    pub language: BigEndian<u16>,
847    pub first_code: BigEndian<u16>,
848    pub entry_count: BigEndian<u16>,
849}
850
851#[allow(clippy::absurd_extreme_comparisons)]
852const _: () = assert!(std::mem::size_of::<Cmap6FixedHeader>() <= Cmap6::MIN_SIZE);
853
854/// [cmap Format 6](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-6-trimmed-table-mapping): Trimmed table mapping
855#[derive(Clone)]
856pub struct Cmap6<'a> {
857    data: TableDataRef<'a, Cmap6FixedHeader>,
858}
859
860#[allow(clippy::needless_lifetimes)]
861impl<'a> Cmap6<'a> {
862    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
863        + u16::RAW_BYTE_LEN
864        + u16::RAW_BYTE_LEN
865        + u16::RAW_BYTE_LEN
866        + u16::RAW_BYTE_LEN);
867    basic_table_impls!(impl_the_methods);
868
869    /// Format number is set to 6.
870    pub fn format(&self) -> u16 {
871        self.data.header().format.get()
872    }
873
874    /// This is the length in bytes of the subtable.
875    pub fn length(&self) -> u16 {
876        self.data.header().length.get()
877    }
878
879    /// For requirements on use of the language field, see “Use of
880    /// the language field in 'cmap' subtables” in this document.
881    pub fn language(&self) -> u16 {
882        self.data.header().language.get()
883    }
884
885    /// First character code of subrange.
886    pub fn first_code(&self) -> u16 {
887        self.data.header().first_code.get()
888    }
889
890    /// Number of character codes in subrange.
891    pub fn entry_count(&self) -> u16 {
892        self.data.header().entry_count.get()
893    }
894
895    /// Array of glyph index values for character codes in the range.
896    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
897        let range = self.glyph_id_array_byte_range();
898        self.offset_data()
899            .read_array(range)
900            .ok()
901            .unwrap_or_default()
902    }
903
904    pub fn format_byte_range(&self) -> Range<usize> {
905        let start = 0;
906        let end = start + u16::RAW_BYTE_LEN;
907        start..end
908    }
909
910    pub fn length_byte_range(&self) -> Range<usize> {
911        let start = self.format_byte_range().end;
912        let end = start + u16::RAW_BYTE_LEN;
913        start..end
914    }
915
916    pub fn language_byte_range(&self) -> Range<usize> {
917        let start = self.length_byte_range().end;
918        let end = start + u16::RAW_BYTE_LEN;
919        start..end
920    }
921
922    pub fn first_code_byte_range(&self) -> Range<usize> {
923        let start = self.language_byte_range().end;
924        let end = start + u16::RAW_BYTE_LEN;
925        start..end
926    }
927
928    pub fn entry_count_byte_range(&self) -> Range<usize> {
929        let start = self.first_code_byte_range().end;
930        let end = start + u16::RAW_BYTE_LEN;
931        start..end
932    }
933
934    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
935        let entry_count = self.entry_count();
936        let start = self.entry_count_byte_range().end;
937        let end = start + (transforms::to_usize(entry_count)).saturating_mul(u16::RAW_BYTE_LEN);
938        start..end
939    }
940}
941
942impl Format<u16> for Cmap8<'_> {
943    const FORMAT: u16 = 8;
944}
945
946impl<'a> MinByteRange<'a> for Cmap8<'a> {
947    fn min_byte_range(&self) -> Range<usize> {
948        0..self.groups_byte_range().end
949    }
950    fn min_table_bytes(&self) -> &'a [u8] {
951        let range = self.min_byte_range();
952        self.offset_data().as_bytes().get(range).unwrap_or_default()
953    }
954}
955
956impl ReadArgs for Cmap8<'_> {
957    type Args = ();
958}
959
960impl<'a> FontRead<'a> for Cmap8<'a> {
961    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
962        #[allow(clippy::absurd_extreme_comparisons)]
963        if data.len() < Self::MIN_SIZE {
964            return Err(ReadError::OutOfBounds);
965        }
966        let Some(data) = TableDataRef::new(data.as_bytes()) else {
967            return Err(ReadError::OutOfBounds);
968        };
969        Ok(Self { data })
970    }
971}
972
973/// The fields at the start of the table, which are read directly.
974#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
975#[repr(C, packed)]
976#[doc(hidden)]
977pub struct Cmap8FixedHeader {
978    pub format: BigEndian<u16>,
979    pub reserved: BigEndian<u16>,
980    pub length: BigEndian<u32>,
981    pub language: BigEndian<u32>,
982}
983
984#[allow(clippy::absurd_extreme_comparisons)]
985const _: () = assert!(std::mem::size_of::<Cmap8FixedHeader>() <= Cmap8::MIN_SIZE);
986
987/// [cmap Format 8](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-8-mixed-16-bit-and-32-bit-coverage): mixed 16-bit and 32-bit coverage
988#[derive(Clone)]
989pub struct Cmap8<'a> {
990    data: TableDataRef<'a, Cmap8FixedHeader>,
991}
992
993#[allow(clippy::needless_lifetimes)]
994impl<'a> Cmap8<'a> {
995    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
996        + u16::RAW_BYTE_LEN
997        + u32::RAW_BYTE_LEN
998        + u32::RAW_BYTE_LEN
999        + u8::RAW_BYTE_LEN * 8192_usize
1000        + u32::RAW_BYTE_LEN);
1001    basic_table_impls!(impl_the_methods);
1002
1003    /// Subtable format; set to 8.
1004    pub fn format(&self) -> u16 {
1005        self.data.header().format.get()
1006    }
1007
1008    /// Byte length of this subtable (including the header)
1009    pub fn length(&self) -> u32 {
1010        self.data.header().length.get()
1011    }
1012
1013    /// For requirements on use of the language field, see “Use of
1014    /// the language field in 'cmap' subtables” in this document.
1015    pub fn language(&self) -> u32 {
1016        self.data.header().language.get()
1017    }
1018
1019    /// Tightly packed array of bits (8K bytes total) indicating
1020    /// whether the particular 16-bit (index) value is the start of a
1021    /// 32-bit character code
1022    pub fn is32(&self) -> &'a [u8] {
1023        let range = self.is32_byte_range();
1024        self.offset_data()
1025            .read_array(range)
1026            .ok()
1027            .unwrap_or_default()
1028    }
1029
1030    /// Number of groupings which follow
1031    pub fn num_groups(&self) -> u32 {
1032        let range = self.num_groups_byte_range();
1033        self.offset_data()
1034            .read_at(range.start)
1035            .ok()
1036            .unwrap_or_default()
1037    }
1038
1039    /// Array of SequentialMapGroup records.
1040    pub fn groups(&self) -> &'a [SequentialMapGroup] {
1041        let range = self.groups_byte_range();
1042        self.offset_data()
1043            .read_array(range)
1044            .ok()
1045            .unwrap_or_default()
1046    }
1047
1048    pub fn format_byte_range(&self) -> Range<usize> {
1049        let start = 0;
1050        let end = start + u16::RAW_BYTE_LEN;
1051        start..end
1052    }
1053
1054    pub fn reserved_byte_range(&self) -> Range<usize> {
1055        let start = self.format_byte_range().end;
1056        let end = start + u16::RAW_BYTE_LEN;
1057        start..end
1058    }
1059
1060    pub fn length_byte_range(&self) -> Range<usize> {
1061        let start = self.reserved_byte_range().end;
1062        let end = start + u32::RAW_BYTE_LEN;
1063        start..end
1064    }
1065
1066    pub fn language_byte_range(&self) -> Range<usize> {
1067        let start = self.length_byte_range().end;
1068        let end = start + u32::RAW_BYTE_LEN;
1069        start..end
1070    }
1071
1072    pub fn is32_byte_range(&self) -> Range<usize> {
1073        let start = self.language_byte_range().end;
1074        let end = start + (8192_usize).saturating_mul(u8::RAW_BYTE_LEN);
1075        start..end
1076    }
1077
1078    pub fn num_groups_byte_range(&self) -> Range<usize> {
1079        let start = self.is32_byte_range().end;
1080        let end = start + u32::RAW_BYTE_LEN;
1081        start..end
1082    }
1083
1084    pub fn groups_byte_range(&self) -> Range<usize> {
1085        let num_groups = self.num_groups();
1086        let start = self.num_groups_byte_range().end;
1087        let end = start
1088            + (transforms::to_usize(num_groups)).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN);
1089        start..end
1090    }
1091}
1092
1093/// Used in [Cmap8] and [Cmap12]
1094#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1095#[repr(C)]
1096#[repr(packed)]
1097pub struct SequentialMapGroup {
1098    /// First character code in this group; note that if this group is
1099    /// for one or more 16-bit character codes (which is determined
1100    /// from the is32 array), this 32-bit value will have the high
1101    /// 16-bits set to zero
1102    pub start_char_code: BigEndian<u32>,
1103    /// Last character code in this group; same condition as listed
1104    /// above for the startCharCode
1105    pub end_char_code: BigEndian<u32>,
1106    /// Glyph index corresponding to the starting character code
1107    pub start_glyph_id: BigEndian<u32>,
1108}
1109
1110impl SequentialMapGroup {
1111    /// First character code in this group; note that if this group is
1112    /// for one or more 16-bit character codes (which is determined
1113    /// from the is32 array), this 32-bit value will have the high
1114    /// 16-bits set to zero
1115    pub fn start_char_code(&self) -> u32 {
1116        self.start_char_code.get()
1117    }
1118
1119    /// Last character code in this group; same condition as listed
1120    /// above for the startCharCode
1121    pub fn end_char_code(&self) -> u32 {
1122        self.end_char_code.get()
1123    }
1124
1125    /// Glyph index corresponding to the starting character code
1126    pub fn start_glyph_id(&self) -> u32 {
1127        self.start_glyph_id.get()
1128    }
1129}
1130
1131impl FixedSize for SequentialMapGroup {
1132    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1133}
1134
1135impl Format<u16> for Cmap10<'_> {
1136    const FORMAT: u16 = 10;
1137}
1138
1139impl<'a> MinByteRange<'a> for Cmap10<'a> {
1140    fn min_byte_range(&self) -> Range<usize> {
1141        0..self.glyph_id_array_byte_range().end
1142    }
1143    fn min_table_bytes(&self) -> &'a [u8] {
1144        let range = self.min_byte_range();
1145        self.offset_data().as_bytes().get(range).unwrap_or_default()
1146    }
1147}
1148
1149impl ReadArgs for Cmap10<'_> {
1150    type Args = ();
1151}
1152
1153impl<'a> FontRead<'a> for Cmap10<'a> {
1154    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1155        #[allow(clippy::absurd_extreme_comparisons)]
1156        if data.len() < Self::MIN_SIZE {
1157            return Err(ReadError::OutOfBounds);
1158        }
1159        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1160            return Err(ReadError::OutOfBounds);
1161        };
1162        Ok(Self { data })
1163    }
1164}
1165
1166/// The fields at the start of the table, which are read directly.
1167#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1168#[repr(C, packed)]
1169#[doc(hidden)]
1170pub struct Cmap10FixedHeader {
1171    pub format: BigEndian<u16>,
1172    pub reserved: BigEndian<u16>,
1173    pub length: BigEndian<u32>,
1174    pub language: BigEndian<u32>,
1175    pub start_char_code: BigEndian<u32>,
1176    pub num_chars: BigEndian<u32>,
1177}
1178
1179#[allow(clippy::absurd_extreme_comparisons)]
1180const _: () = assert!(std::mem::size_of::<Cmap10FixedHeader>() <= Cmap10::MIN_SIZE);
1181
1182/// [cmap Format 10](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-10-trimmed-array): Tr
1183#[derive(Clone)]
1184pub struct Cmap10<'a> {
1185    data: TableDataRef<'a, Cmap10FixedHeader>,
1186}
1187
1188#[allow(clippy::needless_lifetimes)]
1189impl<'a> Cmap10<'a> {
1190    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1191        + u16::RAW_BYTE_LEN
1192        + u32::RAW_BYTE_LEN
1193        + u32::RAW_BYTE_LEN
1194        + u32::RAW_BYTE_LEN
1195        + u32::RAW_BYTE_LEN);
1196    basic_table_impls!(impl_the_methods);
1197
1198    /// Subtable format; set to 10.
1199    pub fn format(&self) -> u16 {
1200        self.data.header().format.get()
1201    }
1202
1203    /// Byte length of this subtable (including the header)
1204    pub fn length(&self) -> u32 {
1205        self.data.header().length.get()
1206    }
1207
1208    /// For requirements on use of the language field, see “Use of
1209    /// the language field in 'cmap' subtables” in this document.
1210    pub fn language(&self) -> u32 {
1211        self.data.header().language.get()
1212    }
1213
1214    /// First character code covered
1215    pub fn start_char_code(&self) -> u32 {
1216        self.data.header().start_char_code.get()
1217    }
1218
1219    /// Number of character codes covered
1220    pub fn num_chars(&self) -> u32 {
1221        self.data.header().num_chars.get()
1222    }
1223
1224    /// Array of glyph indices for the character codes covered
1225    pub fn glyph_id_array(&self) -> &'a [BigEndian<u16>] {
1226        let range = self.glyph_id_array_byte_range();
1227        self.offset_data()
1228            .read_array(range)
1229            .ok()
1230            .unwrap_or_default()
1231    }
1232
1233    pub fn format_byte_range(&self) -> Range<usize> {
1234        let start = 0;
1235        let end = start + u16::RAW_BYTE_LEN;
1236        start..end
1237    }
1238
1239    pub fn reserved_byte_range(&self) -> Range<usize> {
1240        let start = self.format_byte_range().end;
1241        let end = start + u16::RAW_BYTE_LEN;
1242        start..end
1243    }
1244
1245    pub fn length_byte_range(&self) -> Range<usize> {
1246        let start = self.reserved_byte_range().end;
1247        let end = start + u32::RAW_BYTE_LEN;
1248        start..end
1249    }
1250
1251    pub fn language_byte_range(&self) -> Range<usize> {
1252        let start = self.length_byte_range().end;
1253        let end = start + u32::RAW_BYTE_LEN;
1254        start..end
1255    }
1256
1257    pub fn start_char_code_byte_range(&self) -> Range<usize> {
1258        let start = self.language_byte_range().end;
1259        let end = start + u32::RAW_BYTE_LEN;
1260        start..end
1261    }
1262
1263    pub fn num_chars_byte_range(&self) -> Range<usize> {
1264        let start = self.start_char_code_byte_range().end;
1265        let end = start + u32::RAW_BYTE_LEN;
1266        start..end
1267    }
1268
1269    pub fn glyph_id_array_byte_range(&self) -> Range<usize> {
1270        let num_chars = self.num_chars();
1271        let start = self.num_chars_byte_range().end;
1272        let end = start + (transforms::to_usize(num_chars)).saturating_mul(u16::RAW_BYTE_LEN);
1273        start..end
1274    }
1275}
1276
1277impl Format<u16> for Cmap12<'_> {
1278    const FORMAT: u16 = 12;
1279}
1280
1281impl<'a> MinByteRange<'a> for Cmap12<'a> {
1282    fn min_byte_range(&self) -> Range<usize> {
1283        0..self.groups_byte_range().end
1284    }
1285    fn min_table_bytes(&self) -> &'a [u8] {
1286        let range = self.min_byte_range();
1287        self.offset_data().as_bytes().get(range).unwrap_or_default()
1288    }
1289}
1290
1291impl ReadArgs for Cmap12<'_> {
1292    type Args = ();
1293}
1294
1295impl<'a> FontRead<'a> for Cmap12<'a> {
1296    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1297        #[allow(clippy::absurd_extreme_comparisons)]
1298        if data.len() < Self::MIN_SIZE {
1299            return Err(ReadError::OutOfBounds);
1300        }
1301        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1302            return Err(ReadError::OutOfBounds);
1303        };
1304        Ok(Self { data })
1305    }
1306}
1307
1308/// The fields at the start of the table, which are read directly.
1309#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1310#[repr(C, packed)]
1311#[doc(hidden)]
1312pub struct Cmap12FixedHeader {
1313    pub format: BigEndian<u16>,
1314    pub reserved: BigEndian<u16>,
1315    pub length: BigEndian<u32>,
1316    pub language: BigEndian<u32>,
1317    pub num_groups: BigEndian<u32>,
1318}
1319
1320#[allow(clippy::absurd_extreme_comparisons)]
1321const _: () = assert!(std::mem::size_of::<Cmap12FixedHeader>() <= Cmap12::MIN_SIZE);
1322
1323/// [cmap Format 12](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-12-segmented-coverage): Segmented coverage
1324#[derive(Clone)]
1325pub struct Cmap12<'a> {
1326    data: TableDataRef<'a, Cmap12FixedHeader>,
1327}
1328
1329#[allow(clippy::needless_lifetimes)]
1330impl<'a> Cmap12<'a> {
1331    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1332        + u16::RAW_BYTE_LEN
1333        + u32::RAW_BYTE_LEN
1334        + u32::RAW_BYTE_LEN
1335        + u32::RAW_BYTE_LEN);
1336    basic_table_impls!(impl_the_methods);
1337
1338    /// Subtable format; set to 12.
1339    pub fn format(&self) -> u16 {
1340        self.data.header().format.get()
1341    }
1342
1343    /// Byte length of this subtable (including the header)
1344    pub fn length(&self) -> u32 {
1345        self.data.header().length.get()
1346    }
1347
1348    /// For requirements on use of the language field, see “Use of
1349    /// the language field in 'cmap' subtables” in this document.
1350    pub fn language(&self) -> u32 {
1351        self.data.header().language.get()
1352    }
1353
1354    /// Number of groupings which follow
1355    pub fn num_groups(&self) -> u32 {
1356        self.data.header().num_groups.get()
1357    }
1358
1359    /// Array of SequentialMapGroup records.
1360    pub fn groups(&self) -> &'a [SequentialMapGroup] {
1361        let range = self.groups_byte_range();
1362        self.offset_data()
1363            .read_array(range)
1364            .ok()
1365            .unwrap_or_default()
1366    }
1367
1368    pub fn format_byte_range(&self) -> Range<usize> {
1369        let start = 0;
1370        let end = start + u16::RAW_BYTE_LEN;
1371        start..end
1372    }
1373
1374    pub fn reserved_byte_range(&self) -> Range<usize> {
1375        let start = self.format_byte_range().end;
1376        let end = start + u16::RAW_BYTE_LEN;
1377        start..end
1378    }
1379
1380    pub fn length_byte_range(&self) -> Range<usize> {
1381        let start = self.reserved_byte_range().end;
1382        let end = start + u32::RAW_BYTE_LEN;
1383        start..end
1384    }
1385
1386    pub fn language_byte_range(&self) -> Range<usize> {
1387        let start = self.length_byte_range().end;
1388        let end = start + u32::RAW_BYTE_LEN;
1389        start..end
1390    }
1391
1392    pub fn num_groups_byte_range(&self) -> Range<usize> {
1393        let start = self.language_byte_range().end;
1394        let end = start + u32::RAW_BYTE_LEN;
1395        start..end
1396    }
1397
1398    pub fn groups_byte_range(&self) -> Range<usize> {
1399        let num_groups = self.num_groups();
1400        let start = self.num_groups_byte_range().end;
1401        let end = start
1402            + (transforms::to_usize(num_groups)).saturating_mul(SequentialMapGroup::RAW_BYTE_LEN);
1403        start..end
1404    }
1405}
1406
1407impl Format<u16> for Cmap13<'_> {
1408    const FORMAT: u16 = 13;
1409}
1410
1411impl<'a> MinByteRange<'a> for Cmap13<'a> {
1412    fn min_byte_range(&self) -> Range<usize> {
1413        0..self.groups_byte_range().end
1414    }
1415    fn min_table_bytes(&self) -> &'a [u8] {
1416        let range = self.min_byte_range();
1417        self.offset_data().as_bytes().get(range).unwrap_or_default()
1418    }
1419}
1420
1421impl ReadArgs for Cmap13<'_> {
1422    type Args = ();
1423}
1424
1425impl<'a> FontRead<'a> for Cmap13<'a> {
1426    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1427        #[allow(clippy::absurd_extreme_comparisons)]
1428        if data.len() < Self::MIN_SIZE {
1429            return Err(ReadError::OutOfBounds);
1430        }
1431        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1432            return Err(ReadError::OutOfBounds);
1433        };
1434        Ok(Self { data })
1435    }
1436}
1437
1438/// The fields at the start of the table, which are read directly.
1439#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1440#[repr(C, packed)]
1441#[doc(hidden)]
1442pub struct Cmap13FixedHeader {
1443    pub format: BigEndian<u16>,
1444    pub reserved: BigEndian<u16>,
1445    pub length: BigEndian<u32>,
1446    pub language: BigEndian<u32>,
1447    pub num_groups: BigEndian<u32>,
1448}
1449
1450#[allow(clippy::absurd_extreme_comparisons)]
1451const _: () = assert!(std::mem::size_of::<Cmap13FixedHeader>() <= Cmap13::MIN_SIZE);
1452
1453/// [cmap Format 13](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-13-many-to-one-range-mappings): Many-to-one range mappings
1454#[derive(Clone)]
1455pub struct Cmap13<'a> {
1456    data: TableDataRef<'a, Cmap13FixedHeader>,
1457}
1458
1459#[allow(clippy::needless_lifetimes)]
1460impl<'a> Cmap13<'a> {
1461    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN
1462        + u16::RAW_BYTE_LEN
1463        + u32::RAW_BYTE_LEN
1464        + u32::RAW_BYTE_LEN
1465        + u32::RAW_BYTE_LEN);
1466    basic_table_impls!(impl_the_methods);
1467
1468    /// Subtable format; set to 13.
1469    pub fn format(&self) -> u16 {
1470        self.data.header().format.get()
1471    }
1472
1473    /// Byte length of this subtable (including the header)
1474    pub fn length(&self) -> u32 {
1475        self.data.header().length.get()
1476    }
1477
1478    /// For requirements on use of the language field, see “Use of
1479    /// the language field in 'cmap' subtables” in this document.
1480    pub fn language(&self) -> u32 {
1481        self.data.header().language.get()
1482    }
1483
1484    /// Number of groupings which follow
1485    pub fn num_groups(&self) -> u32 {
1486        self.data.header().num_groups.get()
1487    }
1488
1489    /// Array of ConstantMapGroup records.
1490    pub fn groups(&self) -> &'a [ConstantMapGroup] {
1491        let range = self.groups_byte_range();
1492        self.offset_data()
1493            .read_array(range)
1494            .ok()
1495            .unwrap_or_default()
1496    }
1497
1498    pub fn format_byte_range(&self) -> Range<usize> {
1499        let start = 0;
1500        let end = start + u16::RAW_BYTE_LEN;
1501        start..end
1502    }
1503
1504    pub fn reserved_byte_range(&self) -> Range<usize> {
1505        let start = self.format_byte_range().end;
1506        let end = start + u16::RAW_BYTE_LEN;
1507        start..end
1508    }
1509
1510    pub fn length_byte_range(&self) -> Range<usize> {
1511        let start = self.reserved_byte_range().end;
1512        let end = start + u32::RAW_BYTE_LEN;
1513        start..end
1514    }
1515
1516    pub fn language_byte_range(&self) -> Range<usize> {
1517        let start = self.length_byte_range().end;
1518        let end = start + u32::RAW_BYTE_LEN;
1519        start..end
1520    }
1521
1522    pub fn num_groups_byte_range(&self) -> Range<usize> {
1523        let start = self.language_byte_range().end;
1524        let end = start + u32::RAW_BYTE_LEN;
1525        start..end
1526    }
1527
1528    pub fn groups_byte_range(&self) -> Range<usize> {
1529        let num_groups = self.num_groups();
1530        let start = self.num_groups_byte_range().end;
1531        let end = start
1532            + (transforms::to_usize(num_groups)).saturating_mul(ConstantMapGroup::RAW_BYTE_LEN);
1533        start..end
1534    }
1535}
1536
1537/// Part of [Cmap13]
1538#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1539#[repr(C)]
1540#[repr(packed)]
1541pub struct ConstantMapGroup {
1542    /// First character code in this group
1543    pub start_char_code: BigEndian<u32>,
1544    /// Last character code in this group
1545    pub end_char_code: BigEndian<u32>,
1546    /// Glyph index to be used for all the characters in the group’s
1547    /// range.
1548    pub glyph_id: BigEndian<u32>,
1549}
1550
1551impl ConstantMapGroup {
1552    /// First character code in this group
1553    pub fn start_char_code(&self) -> u32 {
1554        self.start_char_code.get()
1555    }
1556
1557    /// Last character code in this group
1558    pub fn end_char_code(&self) -> u32 {
1559        self.end_char_code.get()
1560    }
1561
1562    /// Glyph index to be used for all the characters in the group’s
1563    /// range.
1564    pub fn glyph_id(&self) -> u32 {
1565        self.glyph_id.get()
1566    }
1567}
1568
1569impl FixedSize for ConstantMapGroup {
1570    const RAW_BYTE_LEN: usize = u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN;
1571}
1572
1573impl Format<u16> for Cmap14<'_> {
1574    const FORMAT: u16 = 14;
1575}
1576
1577impl<'a> MinByteRange<'a> for Cmap14<'a> {
1578    fn min_byte_range(&self) -> Range<usize> {
1579        0..self.var_selector_byte_range().end
1580    }
1581    fn min_table_bytes(&self) -> &'a [u8] {
1582        let range = self.min_byte_range();
1583        self.offset_data().as_bytes().get(range).unwrap_or_default()
1584    }
1585}
1586
1587impl ReadArgs for Cmap14<'_> {
1588    type Args = ();
1589}
1590
1591impl<'a> FontRead<'a> for Cmap14<'a> {
1592    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1593        #[allow(clippy::absurd_extreme_comparisons)]
1594        if data.len() < Self::MIN_SIZE {
1595            return Err(ReadError::OutOfBounds);
1596        }
1597        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1598            return Err(ReadError::OutOfBounds);
1599        };
1600        Ok(Self { data })
1601    }
1602}
1603
1604/// The fields at the start of the table, which are read directly.
1605#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1606#[repr(C, packed)]
1607#[doc(hidden)]
1608pub struct Cmap14FixedHeader {
1609    pub format: BigEndian<u16>,
1610    pub length: BigEndian<u32>,
1611    pub num_var_selector_records: BigEndian<u32>,
1612}
1613
1614#[allow(clippy::absurd_extreme_comparisons)]
1615const _: () = assert!(std::mem::size_of::<Cmap14FixedHeader>() <= Cmap14::MIN_SIZE);
1616
1617/// [cmap Format 14](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#format-14-unicode-variation-sequences): Unicode Variation Sequences
1618#[derive(Clone)]
1619pub struct Cmap14<'a> {
1620    data: TableDataRef<'a, Cmap14FixedHeader>,
1621}
1622
1623#[allow(clippy::needless_lifetimes)]
1624impl<'a> Cmap14<'a> {
1625    pub const MIN_SIZE: usize = (u16::RAW_BYTE_LEN + u32::RAW_BYTE_LEN + u32::RAW_BYTE_LEN);
1626    basic_table_impls!(impl_the_methods);
1627
1628    /// Subtable format. Set to 14.
1629    pub fn format(&self) -> u16 {
1630        self.data.header().format.get()
1631    }
1632
1633    /// Byte length of this subtable (including this header)
1634    pub fn length(&self) -> u32 {
1635        self.data.header().length.get()
1636    }
1637
1638    /// Number of variation Selector Records
1639    pub fn num_var_selector_records(&self) -> u32 {
1640        self.data.header().num_var_selector_records.get()
1641    }
1642
1643    /// Array of VariationSelector records.
1644    pub fn var_selector(&self) -> &'a [VariationSelector] {
1645        let range = self.var_selector_byte_range();
1646        self.offset_data()
1647            .read_array(range)
1648            .ok()
1649            .unwrap_or_default()
1650    }
1651
1652    pub fn format_byte_range(&self) -> Range<usize> {
1653        let start = 0;
1654        let end = start + u16::RAW_BYTE_LEN;
1655        start..end
1656    }
1657
1658    pub fn length_byte_range(&self) -> Range<usize> {
1659        let start = self.format_byte_range().end;
1660        let end = start + u32::RAW_BYTE_LEN;
1661        start..end
1662    }
1663
1664    pub fn num_var_selector_records_byte_range(&self) -> Range<usize> {
1665        let start = self.length_byte_range().end;
1666        let end = start + u32::RAW_BYTE_LEN;
1667        start..end
1668    }
1669
1670    pub fn var_selector_byte_range(&self) -> Range<usize> {
1671        let num_var_selector_records = self.num_var_selector_records();
1672        let start = self.num_var_selector_records_byte_range().end;
1673        let end = start
1674            + (transforms::to_usize(num_var_selector_records))
1675                .saturating_mul(VariationSelector::RAW_BYTE_LEN);
1676        start..end
1677    }
1678}
1679
1680/// Part of [Cmap14]
1681#[derive(Clone, Debug, Copy, bytemuck :: AnyBitPattern)]
1682#[repr(C)]
1683#[repr(packed)]
1684pub struct VariationSelector {
1685    /// Variation selector
1686    pub var_selector: BigEndian<Uint24>,
1687    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
1688    /// Table. May be NULL.
1689    pub default_uvs_offset: BigEndian<Nullable<Offset32>>,
1690    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
1691    /// UVS Table. May be NULL.
1692    pub non_default_uvs_offset: BigEndian<Nullable<Offset32>>,
1693}
1694
1695impl VariationSelector {
1696    /// Variation selector
1697    pub fn var_selector(&self) -> Uint24 {
1698        self.var_selector.get()
1699    }
1700
1701    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
1702    /// Table. May be NULL.
1703    pub fn default_uvs_offset(&self) -> Nullable<Offset32> {
1704        self.default_uvs_offset.get()
1705    }
1706
1707    /// Offset from the start of the [`Cmap14`] subtable to Default UVS
1708    /// Table. May be NULL.
1709    ///
1710    /// The `data` argument should be retrieved from the parent table
1711    /// By calling its `offset_data` method.
1712    pub fn default_uvs<'a>(&self, data: FontData<'a>) -> Option<Result<DefaultUvs<'a>, ReadError>> {
1713        self.default_uvs_offset().resolve(data)
1714    }
1715
1716    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
1717    /// UVS Table. May be NULL.
1718    pub fn non_default_uvs_offset(&self) -> Nullable<Offset32> {
1719        self.non_default_uvs_offset.get()
1720    }
1721
1722    /// Offset from the start of the [`Cmap14`] subtable to Non-Default
1723    /// UVS Table. May be NULL.
1724    ///
1725    /// The `data` argument should be retrieved from the parent table
1726    /// By calling its `offset_data` method.
1727    pub fn non_default_uvs<'a>(
1728        &self,
1729        data: FontData<'a>,
1730    ) -> Option<Result<NonDefaultUvs<'a>, ReadError>> {
1731        self.non_default_uvs_offset().resolve(data)
1732    }
1733}
1734
1735impl FixedSize for VariationSelector {
1736    const RAW_BYTE_LEN: usize =
1737        Uint24::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN + Offset32::RAW_BYTE_LEN;
1738}
1739
1740impl<'a> MinByteRange<'a> for DefaultUvs<'a> {
1741    fn min_byte_range(&self) -> Range<usize> {
1742        0..self.ranges_byte_range().end
1743    }
1744    fn min_table_bytes(&self) -> &'a [u8] {
1745        let range = self.min_byte_range();
1746        self.offset_data().as_bytes().get(range).unwrap_or_default()
1747    }
1748}
1749
1750impl ReadArgs for DefaultUvs<'_> {
1751    type Args = ();
1752}
1753
1754impl<'a> FontRead<'a> for DefaultUvs<'a> {
1755    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1756        #[allow(clippy::absurd_extreme_comparisons)]
1757        if data.len() < Self::MIN_SIZE {
1758            return Err(ReadError::OutOfBounds);
1759        }
1760        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1761            return Err(ReadError::OutOfBounds);
1762        };
1763        Ok(Self { data })
1764    }
1765}
1766
1767/// The fields at the start of the table, which are read directly.
1768#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1769#[repr(C, packed)]
1770#[doc(hidden)]
1771pub struct DefaultUvsFixedHeader {
1772    pub num_unicode_value_ranges: BigEndian<u32>,
1773}
1774
1775#[allow(clippy::absurd_extreme_comparisons)]
1776const _: () = assert!(std::mem::size_of::<DefaultUvsFixedHeader>() <= DefaultUvs::MIN_SIZE);
1777
1778/// [Default UVS table](https://docs.microsoft.com/en-us/typography/opentype/spec/cmap#default-uvs-table)
1779#[derive(Clone)]
1780pub struct DefaultUvs<'a> {
1781    data: TableDataRef<'a, DefaultUvsFixedHeader>,
1782}
1783
1784#[allow(clippy::needless_lifetimes)]
1785impl<'a> DefaultUvs<'a> {
1786    pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
1787    basic_table_impls!(impl_the_methods);
1788
1789    /// Number of Unicode character ranges.
1790    pub fn num_unicode_value_ranges(&self) -> u32 {
1791        self.data.header().num_unicode_value_ranges.get()
1792    }
1793
1794    /// Array of UnicodeRange records.
1795    pub fn ranges(&self) -> &'a [UnicodeRange] {
1796        let range = self.ranges_byte_range();
1797        self.offset_data()
1798            .read_array(range)
1799            .ok()
1800            .unwrap_or_default()
1801    }
1802
1803    pub fn num_unicode_value_ranges_byte_range(&self) -> Range<usize> {
1804        let start = 0;
1805        let end = start + u32::RAW_BYTE_LEN;
1806        start..end
1807    }
1808
1809    pub fn ranges_byte_range(&self) -> Range<usize> {
1810        let num_unicode_value_ranges = self.num_unicode_value_ranges();
1811        let start = self.num_unicode_value_ranges_byte_range().end;
1812        let end = start
1813            + (transforms::to_usize(num_unicode_value_ranges))
1814                .saturating_mul(UnicodeRange::RAW_BYTE_LEN);
1815        start..end
1816    }
1817}
1818
1819const _: () = assert!(FontData::default_data_long_enough(DefaultUvs::MIN_SIZE));
1820
1821impl Default for DefaultUvs<'_> {
1822    fn default() -> Self {
1823        Self {
1824            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1825                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1826        }
1827    }
1828}
1829
1830impl<'a> MinByteRange<'a> for NonDefaultUvs<'a> {
1831    fn min_byte_range(&self) -> Range<usize> {
1832        0..self.uvs_mapping_byte_range().end
1833    }
1834    fn min_table_bytes(&self) -> &'a [u8] {
1835        let range = self.min_byte_range();
1836        self.offset_data().as_bytes().get(range).unwrap_or_default()
1837    }
1838}
1839
1840impl ReadArgs for NonDefaultUvs<'_> {
1841    type Args = ();
1842}
1843
1844impl<'a> FontRead<'a> for NonDefaultUvs<'a> {
1845    fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
1846        #[allow(clippy::absurd_extreme_comparisons)]
1847        if data.len() < Self::MIN_SIZE {
1848            return Err(ReadError::OutOfBounds);
1849        }
1850        let Some(data) = TableDataRef::new(data.as_bytes()) else {
1851            return Err(ReadError::OutOfBounds);
1852        };
1853        Ok(Self { data })
1854    }
1855}
1856
1857/// The fields at the start of the table, which are read directly.
1858#[derive(Clone, Copy, bytemuck :: AnyBitPattern)]
1859#[repr(C, packed)]
1860#[doc(hidden)]
1861pub struct NonDefaultUvsFixedHeader {
1862    pub num_uvs_mappings: BigEndian<u32>,
1863}
1864
1865#[allow(clippy::absurd_extreme_comparisons)]
1866const _: () = assert!(std::mem::size_of::<NonDefaultUvsFixedHeader>() <= NonDefaultUvs::MIN_SIZE);
1867
1868/// [Non-Default UVS table](https://learn.microsoft.com/en-us/typography/opentype/spec/cmap#non-default-uvs-table)
1869#[derive(Clone)]
1870pub struct NonDefaultUvs<'a> {
1871    data: TableDataRef<'a, NonDefaultUvsFixedHeader>,
1872}
1873
1874#[allow(clippy::needless_lifetimes)]
1875impl<'a> NonDefaultUvs<'a> {
1876    pub const MIN_SIZE: usize = u32::RAW_BYTE_LEN;
1877    basic_table_impls!(impl_the_methods);
1878
1879    pub fn num_uvs_mappings(&self) -> u32 {
1880        self.data.header().num_uvs_mappings.get()
1881    }
1882
1883    pub fn uvs_mapping(&self) -> &'a [UvsMapping] {
1884        let range = self.uvs_mapping_byte_range();
1885        self.offset_data()
1886            .read_array(range)
1887            .ok()
1888            .unwrap_or_default()
1889    }
1890
1891    pub fn num_uvs_mappings_byte_range(&self) -> Range<usize> {
1892        let start = 0;
1893        let end = start + u32::RAW_BYTE_LEN;
1894        start..end
1895    }
1896
1897    pub fn uvs_mapping_byte_range(&self) -> Range<usize> {
1898        let num_uvs_mappings = self.num_uvs_mappings();
1899        let start = self.num_uvs_mappings_byte_range().end;
1900        let end = start
1901            + (transforms::to_usize(num_uvs_mappings)).saturating_mul(UvsMapping::RAW_BYTE_LEN);
1902        start..end
1903    }
1904}
1905
1906const _: () = assert!(FontData::default_data_long_enough(NonDefaultUvs::MIN_SIZE));
1907
1908impl Default for NonDefaultUvs<'_> {
1909    fn default() -> Self {
1910        Self {
1911            data: TableDataRef::new(FontData::default_table_data().as_bytes())
1912                .unwrap_or_else(|| unreachable!("the default data covers MIN_SIZE")),
1913        }
1914    }
1915}
1916
1917/// Part of [Cmap14]
1918#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1919#[repr(C)]
1920#[repr(packed)]
1921pub struct UvsMapping {
1922    /// Base Unicode value of the UVS
1923    pub unicode_value: BigEndian<Uint24>,
1924    /// Glyph ID of the UVS
1925    pub glyph_id: BigEndian<u16>,
1926}
1927
1928impl UvsMapping {
1929    /// Base Unicode value of the UVS
1930    pub fn unicode_value(&self) -> Uint24 {
1931        self.unicode_value.get()
1932    }
1933
1934    /// Glyph ID of the UVS
1935    pub fn glyph_id(&self) -> u16 {
1936        self.glyph_id.get()
1937    }
1938}
1939
1940impl FixedSize for UvsMapping {
1941    const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u16::RAW_BYTE_LEN;
1942}
1943
1944/// Part of [Cmap14]
1945#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, bytemuck :: AnyBitPattern)]
1946#[repr(C)]
1947#[repr(packed)]
1948pub struct UnicodeRange {
1949    /// First value in this range
1950    pub start_unicode_value: BigEndian<Uint24>,
1951    /// Number of additional values in this range
1952    pub additional_count: u8,
1953}
1954
1955impl UnicodeRange {
1956    /// First value in this range
1957    pub fn start_unicode_value(&self) -> Uint24 {
1958        self.start_unicode_value.get()
1959    }
1960
1961    /// Number of additional values in this range
1962    pub fn additional_count(&self) -> u8 {
1963        self.additional_count
1964    }
1965}
1966
1967impl FixedSize for UnicodeRange {
1968    const RAW_BYTE_LEN: usize = Uint24::RAW_BYTE_LEN + u8::RAW_BYTE_LEN;
1969}