read_fonts/
offset.rs

1//! Handling offsets
2
3use super::read::{FontRead, ReadError};
4use crate::{font_data::FontData, read::FontReadWithArgs};
5use types::{Nullable, Offset16, Offset24, Offset32};
6
7/// Any offset type.
8pub 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
34/// A helper trait providing a 'resolve' method for offset types
35pub 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
45/// A helper trait providing a 'resolve' method for nullable offset types
46pub 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}