1use super::read::{FontRead, ReadError};
4use crate::{font_data::FontData, read::FontReadWithArgs};
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<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Result<T, ReadError>;
37
38 fn resolve_with_args<'a, T: FontReadWithArgs<'a>>(
39 &self,
40 data: FontData<'a>,
41 args: &T::Args,
42 ) -> Result<T, ReadError>;
43}
44
45pub trait ResolveNullableOffset {
47 fn resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Option<Result<T, ReadError>>;
48
49 fn resolve_with_args<'a, T: FontReadWithArgs<'a>>(
50 &self,
51 data: FontData<'a>,
52 args: &T::Args,
53 ) -> Option<Result<T, ReadError>>;
54}
55
56impl<O: Offset> ResolveNullableOffset for Nullable<O> {
57 fn resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Option<Result<T, ReadError>> {
58 match self.offset().resolve(data) {
59 Ok(thing) => Some(Ok(thing)),
60 Err(ReadError::NullOffset) => None,
61 Err(e) => Some(Err(e)),
62 }
63 }
64
65 fn resolve_with_args<'a, T: FontReadWithArgs<'a>>(
66 &self,
67 data: FontData<'a>,
68 args: &T::Args,
69 ) -> Option<Result<T, ReadError>> {
70 match self.offset().resolve_with_args(data, args) {
71 Ok(thing) => Some(Ok(thing)),
72 Err(ReadError::NullOffset) => None,
73 Err(e) => Some(Err(e)),
74 }
75 }
76}
77
78impl<O: Offset> ResolveOffset for O {
79 fn resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Result<T, ReadError> {
80 self.non_null()
81 .ok_or(ReadError::NullOffset)
82 .and_then(|off| data.split_off(off).ok_or(ReadError::OutOfBounds))
83 .and_then(T::read)
84 }
85
86 fn resolve_with_args<'a, T: FontReadWithArgs<'a>>(
87 &self,
88 data: FontData<'a>,
89 args: &T::Args,
90 ) -> Result<T, ReadError> {
91 self.non_null()
92 .ok_or(ReadError::NullOffset)
93 .and_then(|off| data.split_off(off).ok_or(ReadError::OutOfBounds))
94 .and_then(|data| T::read_with_args(data, args))
95 }
96}