1#![deny(clippy::arithmetic_side_effects)]
4use std::ops::{Range, RangeBounds};
5
6use bytemuck::AnyBitPattern;
7use types::{BigEndian, FixedSize, Scalar};
8
9use crate::array::ComputedArray;
10use crate::read::{ComputeSize, FontRead, ReadArgs, ReadError};
11
12#[derive(Debug, Default, Clone, Copy)]
17pub struct FontData<'a> {
18 bytes: &'a [u8],
19}
20
21#[derive(Debug, Default, Clone, Copy)]
29pub struct Cursor<'a> {
30 pos: usize,
31 data: FontData<'a>,
32}
33
34const ARR_LEN: usize = FontData::NULL_POOL_SIZE + u16::RAW_BYTE_LEN;
37
38static EMPTY_TABLE_BYTES: [u8; ARR_LEN] = {
43 let mut arr = [0u8; ARR_LEN];
44 arr[1] = 1;
45 arr
46};
47
48impl FontData<'static> {
49 const NULL_POOL_SIZE: usize = 262;
54
55 #[allow(dead_code)]
58 pub(crate) const fn default_data_long_enough(n_bytes: usize) -> bool {
60 n_bytes <= Self::NULL_POOL_SIZE
61 }
62
63 pub(crate) fn default_table_data() -> Self {
65 FontData::new(&EMPTY_TABLE_BYTES[2..])
66 }
67
68 pub(crate) fn default_format_1_u16_table_data() -> Self {
71 FontData::new(&EMPTY_TABLE_BYTES)
72 }
73
74 pub(crate) fn default_format_1_u8_table_data() -> Self {
77 FontData::new(&EMPTY_TABLE_BYTES[1..])
78 }
79}
80
81impl<'a> FontData<'a> {
82 pub const EMPTY: FontData<'static> = FontData { bytes: &[] };
84
85 pub const fn new(bytes: &'a [u8]) -> Self {
90 FontData { bytes }
91 }
92
93 pub fn len(&self) -> usize {
95 self.bytes.len()
96 }
97
98 pub fn is_empty(&self) -> bool {
100 self.bytes.is_empty()
101 }
102
103 pub fn split_off(&self, pos: usize) -> Option<FontData<'a>> {
105 self.bytes.get(pos..).map(|bytes| FontData { bytes })
106 }
107
108 pub fn take_up_to(&mut self, pos: usize) -> Option<FontData<'a>> {
110 if pos > self.len() {
111 return None;
112 }
113 let (head, tail) = self.bytes.split_at(pos);
114 self.bytes = tail;
115 Some(FontData { bytes: head })
116 }
117
118 pub fn slice(&self, range: impl RangeBounds<usize>) -> Option<FontData<'a>> {
119 let bounds = (range.start_bound().cloned(), range.end_bound().cloned());
120 self.bytes.get(bounds).map(|bytes| FontData { bytes })
121 }
122
123 pub fn read_at<T: Scalar>(&self, offset: usize) -> Result<T, ReadError> {
125 let end = offset
126 .checked_add(T::RAW_BYTE_LEN)
127 .ok_or(ReadError::OutOfBounds)?;
128 self.bytes
129 .get(offset..end)
130 .and_then(T::read)
131 .ok_or(ReadError::OutOfBounds)
132 }
133
134 pub fn read_be_at<T: Scalar>(&self, offset: usize) -> Result<BigEndian<T>, ReadError> {
136 let end = offset
137 .checked_add(T::RAW_BYTE_LEN)
138 .ok_or(ReadError::OutOfBounds)?;
139 self.bytes
140 .get(offset..end)
141 .and_then(BigEndian::from_slice)
142 .ok_or(ReadError::OutOfBounds)
143 }
144
145 pub fn read_with_args<T>(&self, range: Range<usize>, args: T::Args) -> Result<T, ReadError>
146 where
147 T: FontRead<'a>,
148 {
149 self.slice(range)
150 .ok_or(ReadError::OutOfBounds)
151 .and_then(|data| T::read_with_args(data, args))
152 }
153
154 fn check_in_bounds(&self, offset: usize) -> Result<(), ReadError> {
155 self.bytes
156 .get(..offset)
157 .ok_or(ReadError::OutOfBounds)
158 .map(|_| ())
159 }
160
161 pub fn read_ref_at<T: AnyBitPattern + FixedSize>(
175 &self,
176 offset: usize,
177 ) -> Result<&'a T, ReadError> {
178 let end = offset
179 .checked_add(T::RAW_BYTE_LEN)
180 .ok_or(ReadError::OutOfBounds)?;
181 self.bytes
182 .get(offset..end)
183 .ok_or(ReadError::OutOfBounds)
184 .map(bytemuck::from_bytes)
185 }
186
187 pub fn read_array<T: AnyBitPattern + FixedSize>(
202 &self,
203 range: Range<usize>,
204 ) -> Result<&'a [T], ReadError> {
205 let bytes = self
206 .bytes
207 .get(range.clone())
208 .ok_or(ReadError::OutOfBounds)?;
209 if bytes
210 .len()
211 .checked_rem(std::mem::size_of::<T>())
212 .unwrap_or(1) != 0
214 {
215 return Err(ReadError::InvalidArrayLen);
216 };
217 Ok(bytemuck::cast_slice(bytes))
218 }
219
220 pub(crate) fn cursor(&self) -> Cursor<'a> {
221 Cursor {
222 pos: 0,
223 data: *self,
224 }
225 }
226
227 pub fn as_bytes(&self) -> &'a [u8] {
229 self.bytes
230 }
231}
232
233impl<'a> Cursor<'a> {
234 pub(crate) fn advance<T: Scalar>(&mut self) {
235 self.pos = self.pos.saturating_add(T::RAW_BYTE_LEN);
236 }
237
238 pub(crate) fn advance_by(&mut self, n_bytes: usize) {
239 self.pos = self.pos.saturating_add(n_bytes);
240 }
241
242 pub(crate) fn read_u32_var(&mut self) -> Result<u32, ReadError> {
244 let mut next = || self.read::<u8>().map(|v| v as u32);
245 let b0 = next()?;
246 #[allow(clippy::arithmetic_side_effects)] let result = match b0 {
249 _ if b0 < 0x80 => b0,
250 _ if b0 < 0xC0 => ((b0 - 0x80) << 8) | next()?,
251 _ if b0 < 0xE0 => ((b0 - 0xC0) << 16) | (next()? << 8) | next()?,
252 _ if b0 < 0xF0 => ((b0 - 0xE0) << 24) | (next()? << 16) | (next()? << 8) | next()?,
253 _ => {
254 (next()? << 24) | (next()? << 16) | (next()? << 8) | next()?
257 }
258 };
259
260 Ok(result)
261 }
262
263 pub(crate) fn read<T: Scalar>(&mut self) -> Result<T, ReadError> {
265 let temp = self.data.read_at(self.pos);
266 self.advance::<T>();
267 temp
268 }
269
270 pub(crate) fn read_be<T: Scalar>(&mut self) -> Result<BigEndian<T>, ReadError> {
272 let temp = self.data.read_be_at(self.pos);
273 self.advance::<T>();
274 temp
275 }
276
277 pub(crate) fn read_with_args<T>(&mut self, args: T::Args) -> Result<T, ReadError>
278 where
279 T: FontRead<'a> + ComputeSize,
280 {
281 let len = T::compute_size(args)?;
282 let range_end = self.pos.checked_add(len).ok_or(ReadError::OutOfBounds)?;
283 let temp = self.data.read_with_args(self.pos..range_end, args);
284 self.advance_by(len);
285 temp
286 }
287
288 pub(crate) fn read_computed_array<T>(
290 &mut self,
291 len: usize,
292 args: T::Args,
293 ) -> Result<ComputedArray<'a, T>, ReadError>
294 where
295 T: FontRead<'a> + ComputeSize,
296 {
297 let len = len
298 .checked_mul(T::compute_size(args)?)
299 .ok_or(ReadError::OutOfBounds)?;
300 let range_end = self.pos.checked_add(len).ok_or(ReadError::OutOfBounds)?;
301 let temp = self.data.read_with_args(self.pos..range_end, args);
302 self.advance_by(len);
303 temp
304 }
305
306 pub(crate) fn read_array<T: AnyBitPattern + FixedSize>(
307 &mut self,
308 n_elem: usize,
309 ) -> Result<&'a [T], ReadError> {
310 let len = n_elem
311 .checked_mul(T::RAW_BYTE_LEN)
312 .ok_or(ReadError::OutOfBounds)?;
313 let end = self.pos.checked_add(len).ok_or(ReadError::OutOfBounds)?;
314 let temp = self.data.read_array(self.pos..end);
315 self.advance_by(len);
316 temp
317 }
318
319 pub(crate) fn position(&self) -> Result<usize, ReadError> {
321 self.data.check_in_bounds(self.pos).map(|_| self.pos)
322 }
323
324 pub(crate) fn remaining_bytes(&self) -> usize {
327 self.data.len().saturating_sub(self.pos)
328 }
329
330 pub(crate) fn remaining(self) -> Option<FontData<'a>> {
331 self.data.split_off(self.pos)
332 }
333
334 pub fn is_empty(&self) -> bool {
335 self.pos >= self.data.len()
336 }
337}
338
339impl ReadArgs for FontData<'_> {
341 type Args = ();
342}
343
344impl<'a> FontRead<'a> for FontData<'a> {
345 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
346 Ok(data)
347 }
348}
349
350impl AsRef<[u8]> for FontData<'_> {
351 fn as_ref(&self) -> &[u8] {
352 self.bytes
353 }
354}
355
356impl<'a> From<&'a [u8]> for FontData<'a> {
357 fn from(src: &'a [u8]) -> FontData<'a> {
358 FontData::new(src)
359 }
360}
361
362#[cfg(feature = "std")]
365impl<'a> From<FontData<'a>> for std::borrow::Cow<'a, [u8]> {
366 fn from(src: FontData<'a>) -> Self {
367 src.bytes.into()
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374 #[test]
375 fn how_does_big_endian_work_again() {
376 let data = FontData::default_format_1_u16_table_data();
377 assert_eq!(data.read_at(0), Ok(1u16));
378
379 assert_eq!(
380 FontData::default_format_1_u8_table_data().read_at(0),
381 Ok(1u8)
382 );
383 }
384}