font_types/
offset.rs

1//! Offsets to tables
2
3use crate::{Scalar, Uint24};
4
5/// An offset of a given width for which NULL (zero) is a valid value.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8#[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern))]
9#[repr(transparent)]
10pub struct Nullable<T>(T);
11
12// internal implementation detail; lets us implement Default for nullable offsets.
13trait NullValue {
14    const NULL: Self;
15}
16
17impl<T: Scalar> Scalar for Nullable<T> {
18    type Raw = T::Raw;
19
20    #[inline]
21    fn from_raw(raw: Self::Raw) -> Self {
22        Self(T::from_raw(raw))
23    }
24
25    #[inline]
26    fn to_raw(self) -> Self::Raw {
27        self.0.to_raw()
28    }
29}
30
31impl<T> Nullable<T> {
32    /// Return a reference to the inner offset
33    #[inline]
34    pub fn offset(&self) -> &T {
35        &self.0
36    }
37}
38
39impl<T: PartialEq<u32>> Nullable<T> {
40    #[inline]
41    pub fn is_null(&self) -> bool {
42        self.0 == 0
43    }
44}
45
46impl<T: PartialEq<u32>> PartialEq<u32> for Nullable<T> {
47    #[inline]
48    fn eq(&self, other: &u32) -> bool {
49        self.0 == *other
50    }
51}
52
53impl<T: NullValue> Default for Nullable<T> {
54    fn default() -> Self {
55        Self(T::NULL)
56    }
57}
58
59macro_rules! impl_offset {
60    ($name:ident, $bits:literal, $rawty:ty) => {
61        #[doc = concat!("A", stringify!($bits), "-bit offset to a table.")]
62        ///
63        /// Specific offset fields may or may not permit NULL values; however we
64        /// assume that errors are possible, and expect the caller to handle
65        /// the `None` case.
66        #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
67        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
68        #[cfg_attr(feature = "bytemuck", derive(bytemuck::AnyBitPattern))]
69        #[repr(transparent)]
70        pub struct $name($rawty);
71
72        impl $name {
73            /// Create a new offset.
74            #[inline]
75            pub const fn new(raw: $rawty) -> Self {
76                Self(raw)
77            }
78
79            /// Return `true` if this offset is null.
80            #[inline]
81            pub fn is_null(self) -> bool {
82                self.to_u32() == 0
83            }
84
85            #[inline]
86            pub fn to_u32(self) -> u32 {
87                self.0.into()
88            }
89        }
90
91        impl crate::raw::Scalar for $name {
92            type Raw = <$rawty as crate::raw::Scalar>::Raw;
93            fn from_raw(raw: Self::Raw) -> Self {
94                let raw = <$rawty>::from_raw(raw);
95                $name::new(raw)
96            }
97
98            fn to_raw(self) -> Self::Raw {
99                self.0.to_raw()
100            }
101        }
102
103        // useful for debugging
104        impl PartialEq<u32> for $name {
105            fn eq(&self, other: &u32) -> bool {
106                self.to_u32() == *other
107            }
108        }
109
110        impl NullValue for $name {
111            const NULL: $name = $name(<$rawty>::MIN);
112        }
113    };
114}
115
116impl_offset!(Offset16, 16, u16);
117impl_offset!(Offset24, 24, Uint24);
118impl_offset!(Offset32, 32, u32);