1 //! Handling offsets 2 3 use super::read::{FontRead, ReadError}; 4 use crate::{font_data::FontData, read::FontReadWithArgs}; 5 use types::{Nullable, Offset16, Offset24, Offset32}; 6 7 /// Any offset type. 8 pub trait Offset: Copy { to_usize(self) -> usize9 fn to_usize(self) -> usize; 10 non_null(self) -> Option<usize>11 fn non_null(self) -> Option<usize> { 12 match self.to_usize() { 13 0 => None, 14 other => Some(other), 15 } 16 } 17 } 18 19 macro_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 30 impl_offset!(Offset16, 2); 31 impl_offset!(Offset24, 3); 32 impl_offset!(Offset32, 4); 33 34 /// A helper trait providing a 'resolve' method for offset types 35 pub trait ResolveOffset { resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Result<T, ReadError>36 fn resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Result<T, ReadError>; 37 resolve_with_args<'a, T: FontReadWithArgs<'a>>( &self, data: FontData<'a>, args: &T::Args, ) -> Result<T, ReadError>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 46 pub trait ResolveNullableOffset { resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Option<Result<T, ReadError>>47 fn resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Option<Result<T, ReadError>>; 48 resolve_with_args<'a, T: FontReadWithArgs<'a>>( &self, data: FontData<'a>, args: &T::Args, ) -> Option<Result<T, ReadError>>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 56 impl<O: Offset> ResolveNullableOffset for Nullable<O> { resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Option<Result<T, ReadError>>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 resolve_with_args<'a, T: FontReadWithArgs<'a>>( &self, data: FontData<'a>, args: &T::Args, ) -> Option<Result<T, ReadError>>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 78 impl<O: Offset> ResolveOffset for O { resolve<'a, T: FontRead<'a>>(&self, data: FontData<'a>) -> Result<T, ReadError>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 resolve_with_args<'a, T: FontReadWithArgs<'a>>( &self, data: FontData<'a>, args: &T::Args, ) -> Result<T, ReadError>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 } 97