1use super::read::{FontRead, ReadError};
4use crate::font_data::FontData;
5use types::{Nullable, Offset16, Offset24, Offset32};
6
7pub trait Offset: Copy {
9 fn to_usize(self) -> usize;
10
11 fn non_null(self) -> Option<usize> {
12 match self.to_usize() {
13 0 => None,
14 other => Some(other),
15 }
16 }
17}
18
19macro_rules! impl_offset {
20 ($name:ident, $width:literal) => {
21 impl Offset for $name {
22 #[inline]
23 fn to_usize(self) -> usize {
24 self.to_u32() as _
25 }
26 }
27 };
28}
29
30impl_offset!(Offset16, 2);
31impl_offset!(Offset24, 3);
32impl_offset!(Offset32, 4);
33
34pub trait ResolveOffset {
36 fn resolve_with_args<'a, T: FontRead<'a>>(
37 &self,
38 data: FontData<'a>,
39 args: T::Args,
40 ) -> Result<T, ReadError>;
41
42 fn resolve<'a, T: FontRead<'a, Args = ()>>(&self, data: FontData<'a>) -> Result<T, ReadError> {
44 self.resolve_with_args(data, ())
45 }
46}
47
48pub trait ResolveNullableOffset {
50 fn resolve_with_args<'a, T: FontRead<'a>>(
51 &self,
52 data: FontData<'a>,
53 args: T::Args,
54 ) -> Option<Result<T, ReadError>>;
55
56 fn resolve<'a, T: FontRead<'a, Args = ()>>(
58 &self,
59 data: FontData<'a>,
60 ) -> Option<Result<T, ReadError>> {
61 self.resolve_with_args(data, ())
62 }
63}
64
65impl<O: Offset> ResolveNullableOffset for Nullable<O> {
66 fn resolve_with_args<'a, T: FontRead<'a>>(
67 &self,
68 data: FontData<'a>,
69 args: T::Args,
70 ) -> Option<Result<T, ReadError>> {
71 match self.offset().resolve_with_args(data, args) {
72 Ok(thing) => Some(Ok(thing)),
73 Err(ReadError::NullOffset) => None,
74 Err(e) => Some(Err(e)),
75 }
76 }
77}
78
79impl<O: Offset> ResolveOffset for O {
80 fn resolve_with_args<'a, T: FontRead<'a>>(
81 &self,
82 data: FontData<'a>,
83 args: T::Args,
84 ) -> Result<T, ReadError> {
85 self.non_null()
86 .ok_or(ReadError::NullOffset)
87 .and_then(|off| data.split_off(off).ok_or(ReadError::OutOfBounds))
88 .and_then(|data| T::read_with_args(data, args))
89 }
90}
91
92#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
95#[repr(transparent)]
96pub(crate) struct CheckedOffset(Option<usize>);
97
98impl CheckedOffset {
99 pub(crate) fn new(offset: usize) -> Self {
100 Self(Some(offset))
101 }
102
103 #[must_use]
104 pub(crate) fn add(self, x: usize) -> Self {
105 Self(self.0.and_then(|o| o.checked_add(x)))
106 }
107
108 #[must_use]
109 pub(crate) fn mul(self, x: usize) -> Self {
110 Self(self.0.and_then(|o| o.checked_mul(x)))
111 }
112
113 pub(crate) fn get(&self) -> Option<usize> {
114 self.0
115 }
116
117 pub(crate) fn ok_or<E>(&self, err: E) -> Result<usize, E> {
118 self.get().ok_or(err)
119 }
120
121 pub(crate) fn ok_or_oob(&self) -> Result<usize, ReadError> {
122 self.ok_or(ReadError::OutOfBounds)
123 }
124}