write_fonts/
from_obj.rs

1//! Traits for converting from parsed font data to their compile equivalents
2
3use std::collections::BTreeSet;
4
5use read_fonts::{
6    ArrayOfNullableOffsets, ArrayOfOffsets, FontData, FontReadWithArgs, Offset, ReadArgs, ReadError,
7};
8use types::{BigEndian, Scalar};
9
10use crate::{NullableOffsetMarker, OffsetMarker};
11
12/// A trait for types that can fully resolve themselves.
13///
14/// This means that any offsets held in this type are resolved relative to the
15/// start of the table itself (and not some parent table)
16pub trait FromTableRef<T>: FromObjRef<T> {
17    fn from_table_ref(from: &T) -> Self {
18        let data = FontData::new(&[]);
19        Self::from_obj_ref(from, data)
20    }
21}
22
23/// A trait for types that can resolve themselves when provided data to resolve offsets.
24///
25/// It is possible that the generated object is malformed; for instance offsets
26/// may be null where it is not allowed. This can be checked by calling [`validate`][]
27/// on the generated object.
28///
29/// This is implemented for the majority of parse types. Those that are the base
30/// for offset data ignore the provided data and use their own.
31///
32/// [`validate`]: [crate::Validate::validate]
33pub trait FromObjRef<T: ?Sized>: Sized {
34    /// Convert `from` to an instance of `Self`, using the provided data to resolve offsets.
35    fn from_obj_ref(from: &T, data: FontData) -> Self;
36}
37
38/// A conversion from a parsed font object type to an owned version, resolving
39/// offsets.
40///
41/// You should avoid implementing this trait manually. Like [`std::convert::Into`],
42/// it is provided as a blanket impl when you implement [`FromObjRef<T>`].
43pub trait ToOwnedObj<T> {
44    /// Convert this type into `T`, using the provided data to resolve any offsets.
45    fn to_owned_obj(&self, data: FontData) -> T;
46}
47
48/// A conversion from a fully resolvable parsed font table to its owned equivalent.
49///
50/// As with [`ToOwnedObj`], you should not need to implement this manually.
51pub trait ToOwnedTable<T>: ToOwnedObj<T> {
52    fn to_owned_table(&self) -> T;
53}
54
55impl<U, T> ToOwnedObj<U> for T
56where
57    U: FromObjRef<T>,
58{
59    fn to_owned_obj(&self, data: FontData) -> U {
60        U::from_obj_ref(self, data)
61    }
62}
63
64impl<U, T> ToOwnedTable<U> for T
65where
66    U: FromTableRef<T>,
67{
68    fn to_owned_table(&self) -> U {
69        U::from_table_ref(self)
70    }
71}
72
73impl<T> FromObjRef<BigEndian<T>> for T
74where
75    T: Scalar,
76    BigEndian<T>: Copy,
77{
78    fn from_obj_ref(from: &BigEndian<T>, _: FontData) -> Self {
79        from.get()
80    }
81}
82
83// we need this because we special case &[u8], eliding the BigEndian wrapper.
84impl FromObjRef<u8> for u8 {
85    fn from_obj_ref(from: &u8, _data: FontData) -> Self {
86        *from
87    }
88}
89
90impl<T, U> FromObjRef<&[U]> for Vec<T>
91where
92    T: FromObjRef<U>,
93{
94    fn from_obj_ref(from: &&[U], data: FontData) -> Self {
95        from.iter().map(|item| item.to_owned_obj(data)).collect()
96    }
97}
98
99impl<T, U> FromObjRef<&[U]> for BTreeSet<T>
100where
101    T: FromObjRef<U> + std::cmp::Ord,
102{
103    fn from_obj_ref(from: &&[U], data: FontData) -> Self {
104        from.iter().map(|item| item.to_owned_obj(data)).collect()
105    }
106}
107
108// A blanket impl to cover converting any Option<T> if T is convertible
109impl<T: FromObjRef<U>, U> FromObjRef<Option<U>> for Option<T> {
110    fn from_obj_ref(from: &Option<U>, data: FontData) -> Self {
111        from.as_ref().map(|inner| T::from_obj_ref(inner, data))
112    }
113}
114
115// A blanket impl to cover converting any Option<T> if T is convertible
116impl<T: FromTableRef<U>, U> FromTableRef<Option<U>> for Option<T> {
117    fn from_table_ref(from: &Option<U>) -> Self {
118        from.as_ref().map(ToOwnedTable::to_owned_table)
119    }
120}
121
122/* blanket impls converting resolved offsets to offsetmarkers */
123
124impl<T: FromObjRef<U> + Default, U, const N: usize> FromObjRef<Result<U, ReadError>>
125    for OffsetMarker<T, N>
126{
127    fn from_obj_ref(from: &Result<U, ReadError>, data: FontData) -> Self {
128        match from {
129            Err(_) => OffsetMarker::default(),
130            Ok(table) => OffsetMarker::new(table.to_owned_obj(data)),
131        }
132    }
133}
134
135impl<T: FromObjRef<U>, U, const N: usize> FromObjRef<Option<Result<U, ReadError>>>
136    for NullableOffsetMarker<T, N>
137{
138    fn from_obj_ref(from: &Option<Result<U, ReadError>>, data: FontData) -> Self {
139        match from {
140            Some(Ok(table)) => NullableOffsetMarker::new(Some(table.to_owned_obj(data))),
141            _ => NullableOffsetMarker::new(None),
142        }
143    }
144}
145
146// used for bare offsets
147impl<T: FromTableRef<U> + Default, U, const N: usize> FromTableRef<Result<U, ReadError>>
148    for OffsetMarker<T, N>
149{
150    fn from_table_ref(from: &Result<U, ReadError>) -> Self {
151        match from {
152            Err(_) => OffsetMarker::default(),
153            Ok(table) => OffsetMarker::new(table.to_owned_table()),
154        }
155    }
156}
157
158// convert bare nullable/versioned offsets to NullableOffsetMarker
159impl<T: FromTableRef<U>, U, const N: usize> FromTableRef<Option<Result<U, ReadError>>>
160    for NullableOffsetMarker<T, N>
161{
162    fn from_table_ref(from: &Option<Result<U, ReadError>>) -> Self {
163        match from {
164            Some(Ok(table)) => NullableOffsetMarker::new(Some(table.to_owned_table())),
165            _ => NullableOffsetMarker::new(None),
166        }
167    }
168}
169
170// impls for converting arrays:
171impl<'a, T, U, O, const N: usize> FromObjRef<ArrayOfOffsets<'a, U, O>> for Vec<OffsetMarker<T, N>>
172where
173    T: FromObjRef<U> + Default,
174    U: ReadArgs + FontReadWithArgs<'a>,
175    U::Args: 'static,
176    O: Scalar + Offset,
177{
178    fn from_obj_ref(from: &ArrayOfOffsets<'a, U, O>, data: FontData) -> Self {
179        from.iter()
180            .map(|x| OffsetMarker::from_obj_ref(&x, data))
181            .collect()
182    }
183}
184
185impl<'a, T, U, O, const N: usize> FromObjRef<ArrayOfNullableOffsets<'a, U, O>>
186    for Vec<NullableOffsetMarker<T, N>>
187where
188    T: FromObjRef<U> + Default,
189    U: ReadArgs + FontReadWithArgs<'a>,
190    U::Args: 'static,
191    O: Scalar + Offset,
192{
193    fn from_obj_ref(from: &ArrayOfNullableOffsets<'a, U, O>, data: FontData) -> Self {
194        from.iter()
195            .map(|x| NullableOffsetMarker::from_obj_ref(&x, data))
196            .collect()
197    }
198}
199
200impl<'a, T, U, O, const N: usize> FromTableRef<ArrayOfOffsets<'a, U, O>> for Vec<OffsetMarker<T, N>>
201where
202    T: FromTableRef<U> + Default,
203    U: ReadArgs + FontReadWithArgs<'a>,
204    U::Args: 'static,
205    O: Scalar + Offset,
206{
207}
208
209impl<'a, T, U, O, const N: usize> FromTableRef<ArrayOfNullableOffsets<'a, U, O>>
210    for Vec<NullableOffsetMarker<T, N>>
211where
212    T: FromObjRef<U> + Default,
213    U: ReadArgs + FontReadWithArgs<'a>,
214    U::Args: 'static,
215    O: Scalar + Offset,
216{
217}