Skip to main content

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