1#![deny(clippy::arithmetic_side_effects)]
4
5use bytemuck::AnyBitPattern;
6use font_types::FixedSize;
7
8use crate::read::{ComputeSize, FontReadWithArgs, ReadArgs, VarSize};
9use crate::{FontData, FontRead, ReadError};
10
11#[derive(Clone)]
20pub struct ComputedArray<'a, T: ReadArgs> {
21 item_len: usize,
23 len: usize,
24 data: FontData<'a>,
25 args: T::Args,
26}
27
28impl<'a, T: ComputeSize> ComputedArray<'a, T> {
29 pub fn new(data: FontData<'a>, args: T::Args) -> Result<Self, ReadError> {
30 let item_len = T::compute_size(&args)?;
31 let len = data.len().checked_div(item_len).unwrap_or(0);
32 Ok(ComputedArray {
33 item_len,
34 len,
35 data,
36 args,
37 })
38 }
39
40 pub fn len(&self) -> usize {
42 self.len
43 }
44
45 pub fn is_empty(&self) -> bool {
46 self.len == 0
47 }
48}
49
50impl<T: ReadArgs> ReadArgs for ComputedArray<'_, T> {
51 type Args = T::Args;
52}
53
54impl<'a, T> FontReadWithArgs<'a> for ComputedArray<'a, T>
55where
56 T: ComputeSize + FontReadWithArgs<'a>,
57 T::Args: Copy,
58{
59 fn read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError> {
60 Self::new(data, *args)
61 }
62}
63
64impl<'a, T> ComputedArray<'a, T>
65where
66 T: FontReadWithArgs<'a>,
67 T::Args: Copy + 'static,
68{
69 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
70 let mut i = 0;
71 let data = self.data;
72 let args = self.args;
73 let item_len = self.item_len;
74 let len = self.len;
75
76 std::iter::from_fn(move || {
77 if i == len {
78 return None;
79 }
80 let item_start = item_len.checked_mul(i)?;
81 i = i.checked_add(1)?;
82 let data = data.split_off(item_start)?;
83 Some(T::read_with_args(data, &args))
84 })
85 }
86
87 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
88 let item_start = idx
89 .checked_mul(self.item_len)
90 .ok_or(ReadError::OutOfBounds)?;
91 self.data
92 .split_off(item_start)
93 .ok_or(ReadError::OutOfBounds)
94 .and_then(|data| T::read_with_args(data, &self.args))
95 }
96}
97
98impl<T: ReadArgs> std::fmt::Debug for ComputedArray<'_, T> {
99 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
100 f.debug_struct("DynSizedArray")
101 .field("bytes", &self.data)
102 .finish()
103 }
104}
105
106pub struct VarLenArray<'a, T> {
111 data: FontData<'a>,
112 phantom: std::marker::PhantomData<*const T>,
113}
114
115impl<'a, T: FontRead<'a> + VarSize> VarLenArray<'a, T> {
116 pub fn get(&self, idx: usize) -> Option<Result<T, ReadError>> {
129 let mut pos = 0usize;
130 for _ in 0..idx {
131 pos = pos.checked_add(T::read_len_at(self.data, pos)?)?;
132 }
133 self.data.split_off(pos).map(T::read)
134 }
135
136 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
138 let mut data = self.data;
139 std::iter::from_fn(move || {
140 if data.is_empty() {
141 return None;
142 }
143
144 let item_len = T::read_len_at(data, 0)?;
145 let item_data = data.slice(..item_len)?;
146 let next = T::read(item_data);
147 data = data.split_off(item_len)?;
148 Some(next)
149 })
150 }
151}
152
153impl<'a, T> FontRead<'a> for VarLenArray<'a, T> {
154 fn read(data: FontData<'a>) -> Result<Self, ReadError> {
155 Ok(VarLenArray {
156 data,
157 phantom: core::marker::PhantomData,
158 })
159 }
160}
161
162impl<T: AnyBitPattern> ReadArgs for &[T] {
163 type Args = u16;
164}
165
166impl<'a, T: AnyBitPattern + FixedSize> FontReadWithArgs<'a> for &'a [T] {
167 fn read_with_args(data: FontData<'a>, args: &u16) -> Result<Self, ReadError> {
168 let len = (*args as usize)
169 .checked_mul(T::RAW_BYTE_LEN)
170 .ok_or(ReadError::OutOfBounds)?;
171 data.read_array(0..len)
172 }
173}