Skip to main content

ttf_view/types/
big_endian.rs

1use crate::types::{
2    Affine2x2, F2Dot14, Fixed, LongDateTime, Version16Dot16, int16, int32, int64, u24, uint16,
3    uint32, uint64,
4};
5
6mod private {
7    pub trait Sealed {}
8}
9
10pub const trait Primitive: private::Sealed + Copy {
11    type BigEndian: Copy;
12    fn from_big_endian(be: Self::BigEndian) -> Self;
13    fn to_big_endian(ne: Self) -> Self::BigEndian;
14}
15
16macro_rules! impl_primitives {
17    ($( $ne_ty:ty, $be_ty:ty, |$be:ident| $from_be:expr, |$ne:ident| $to_be:expr ; )*) => ($(
18        impl private::Sealed for $ne_ty {}
19        const impl Primitive for $ne_ty {
20            type BigEndian = $be_ty;
21            fn from_big_endian($be: Self::BigEndian) -> Self { $from_be }
22            fn to_big_endian($ne: Self) -> Self::BigEndian { $to_be }
23        }
24        const impl From<BigEndian<$ne_ty>> for $ne_ty {
25            fn from(value: BigEndian<$ne_ty>) -> Self {
26                value.get()
27            }
28        }
29    )*);
30}
31impl_primitives! {
32    // TODO: Maybe we shouldn't be wrapping zerocopy's types here?
33    i16, int16, |x| x.get(), |x| int16::new(x);
34    i32, int32, |x| x.get(), |x| int32::new(x);
35    i64, int64, |x| x.get(), |x| int64::new(x);
36    u16, uint16, |x| x.get(), |x| uint16::new(x);
37    u32, uint32, |x| x.get(), |x| uint32::new(x);
38    u64, uint64, |x| x.get(), |x| uint64::new(x);
39
40    Fixed, [u8; 4], |x| Fixed::from_be_bytes(x), |x| x.to_be_bytes();
41    F2Dot14, [u8; 2], |x| F2Dot14::from_be_bytes(x), |x| x.to_be_bytes();
42    LongDateTime, [u8; 8], |x| LongDateTime::from_be_bytes(x), |x| x.to_be_bytes();
43    u24, [u8; 3], |x| u24::from_be_bytes(x), |x| x.to_be_bytes();
44    Version16Dot16, [u8; 4], |x| unsafe { Version16Dot16::from_be_bytes_unchecked(x) },
45    |x| x.to_be_bytes();
46    Affine2x2, [u8; 8], |x| Affine2x2::from_be_bytes(x), |x| x.to_be_bytes();
47}
48
49#[derive(Copy)]
50#[derive_const(Clone, Default, PartialEq, Eq)]
51#[repr(transparent)]
52pub struct BigEndian<T: Primitive>(T::BigEndian);
53
54impl<T: Primitive> BigEndian<T> {
55    pub const fn new(value: T) -> Self
56    where T: [const] Primitive {
57        Self(T::to_big_endian(value))
58    }
59    pub const fn get(self) -> T
60    where T: [const] Primitive {
61        T::from_big_endian(self.0)
62    }
63}
64
65const impl<T: [const] Primitive> From<T> for BigEndian<T> {
66    fn from(value: T) -> Self {
67        Self::new(value)
68    }
69}
70
71// Extra impls for user-friendly big-endian types (zerocopy's, for example)
72macro_rules! impl_extra_traits_for_big_endian {
73    ($($ty:ty),* $(,)?) => ($(
74        impl std::ops::Deref for BigEndian<$ty> {
75            type Target = <$ty as Primitive>::BigEndian;
76            fn deref(&self) -> &Self::Target {
77                &self.0
78            }
79        }
80        const impl From<BigEndian<$ty>> for <$ty as Primitive>::BigEndian {
81            fn from(value: BigEndian<$ty>) -> Self {
82                value.0
83            }
84        }
85        const impl From<<$ty as Primitive>::BigEndian> for BigEndian<$ty> {
86            fn from(value: <$ty as Primitive>::BigEndian) -> Self {
87                Self(value)
88            }
89        }
90    )*);
91}
92impl_extra_traits_for_big_endian! {
93    i16, i32, i64, u16, u32, u64,
94}
95
96macro_rules! impl_fmt_for_big_endian {
97    ($($Trait:ident),* $(,)?) => ($(
98        impl<T: Primitive + std::fmt::$Trait> std::fmt::$Trait for BigEndian<T> {
99            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
100                self.get().fmt(f)
101            }
102        }
103    )*);
104}
105impl_fmt_for_big_endian! { Debug, Display, Binary, Octal, LowerHex, UpperHex, LowerExp, UpperExp }