1#![deny(clippy::arithmetic_side_effects)]
4
5use bytemuck::AnyBitPattern;
6use font_types::FixedSize;
7
8use crate::read::{ComputeSize, FontRead, ReadArgs, VarSize};
9use crate::{FontData, 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> FontRead<'a> for ComputedArray<'a, T>
55where
56 T: ComputeSize + FontRead<'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<T> Default for ComputedArray<'_, T>
65where
66 T: ReadArgs,
67 T::Args: Default,
68{
69 fn default() -> Self {
70 Self {
71 item_len: 0,
72 len: 0,
73 data: Default::default(),
74 args: Default::default(),
75 }
76 }
77}
78
79impl<'a, T> ComputedArray<'a, T>
80where
81 T: FontRead<'a>,
82 T::Args: Copy + 'static,
83{
84 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
85 let mut i = 0;
86 let data = self.data;
87 let args = self.args;
88 let item_len = self.item_len;
89 let len = self.len;
90
91 std::iter::from_fn(move || {
92 if i == len {
93 return None;
94 }
95 let item_start = item_len.checked_mul(i)?;
96 i = i.checked_add(1)?;
97 let data = data.split_off(item_start)?;
98 Some(T::read_with_args(data, args))
99 })
100 }
101
102 #[inline]
103 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
104 let item_start = idx
105 .checked_mul(self.item_len)
106 .ok_or(ReadError::OutOfBounds)?;
107 self.data
108 .split_off(item_start)
109 .ok_or(ReadError::OutOfBounds)
110 .and_then(|data| T::read_with_args(data, self.args))
111 }
112}
113
114impl<T: ReadArgs> std::fmt::Debug for ComputedArray<'_, T> {
115 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
116 f.debug_struct("DynSizedArray")
117 .field("bytes", &self.data)
118 .finish()
119 }
120}
121
122pub struct VarLenArray<'a, T> {
127 data: FontData<'a>,
128 phantom: std::marker::PhantomData<*const T>,
129}
130
131impl<'a, T: FontRead<'a, Args = ()> + VarSize> VarLenArray<'a, T> {
132 pub fn get(&self, idx: usize) -> Option<Result<T, ReadError>> {
145 if self.data.is_empty() {
146 return None;
147 }
148 let mut pos = 0usize;
149 for _ in 0..idx {
150 pos = pos.checked_add(T::read_len_at(self.data, pos)?)?;
151 }
152 let len = T::read_len_at(self.data, pos)?;
153 let end = pos.checked_add(len)?;
154 self.data.slice(pos..end).map(T::read)
155 }
156
157 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
159 let mut data = self.data;
160 std::iter::from_fn(move || {
161 if data.is_empty() {
162 return None;
163 }
164
165 let item_len = T::read_len_at(data, 0)?;
166 if item_len == 0 {
171 return None;
172 }
173 let item_data = data.slice(..item_len)?;
174 let next = T::read(item_data);
175 data = data.split_off(item_len)?;
176 Some(next)
177 })
178 }
179}
180
181impl<T> ReadArgs for VarLenArray<'_, T> {
182 type Args = ();
183}
184
185impl<'a, T> FontRead<'a> for VarLenArray<'a, T> {
186 fn read_with_args(data: FontData<'a>, _: ()) -> Result<Self, ReadError> {
187 Ok(VarLenArray {
188 data,
189 phantom: core::marker::PhantomData,
190 })
191 }
192}
193
194impl<T> Default for VarLenArray<'_, T> {
195 fn default() -> Self {
196 Self {
197 data: Default::default(),
198 phantom: std::marker::PhantomData,
199 }
200 }
201}
202
203impl<T: AnyBitPattern> ReadArgs for &[T] {
204 type Args = u16;
205}
206
207impl<'a, T: AnyBitPattern + FixedSize> FontRead<'a> for &'a [T] {
208 fn read_with_args(data: FontData<'a>, args: u16) -> Result<Self, ReadError> {
209 let len = (args as usize)
210 .checked_mul(T::RAW_BYTE_LEN)
211 .ok_or(ReadError::OutOfBounds)?;
212 data.read_array(0..len)
213 }
214}
215
216pub(crate) fn get_pair<T>(slice: &[T], idx: usize) -> Result<&[T; 2], ReadError> {
219 slice
220 .get(idx..)
221 .ok_or(ReadError::OutOfBounds)?
222 .first_chunk()
223 .ok_or(ReadError::OutOfBounds)
224}
225
226#[cfg(test)]
227mod tests {
228 use super::*;
229 use crate::codegen_test::records::VarLenItem;
230 use font_test_data::bebuffer::BeBuffer;
231
232 impl VarSize for VarLenItem<'_> {
233 type Size = u32;
234
235 fn read_len_at(data: FontData, pos: usize) -> Option<usize> {
236 data.read_at::<u32>(pos).ok().map(|len| len as usize)
237 }
238 }
239
240 #[test]
244 fn var_len_iter_with_zero_length_item() {
245 let mut buf = BeBuffer::new();
248 buf = buf.push(8u32).extend([0u8; 4]);
249 buf = buf.push(18u32).extend([0u8; 14]);
250 buf = buf.push(0u32);
251 let arr: VarLenArray<VarLenItem> = VarLenArray::read(FontData::new(buf.data())).unwrap();
252 assert_eq!(arr.iter().take(10).count(), 2);
256 }
257
258 #[test]
259 fn var_len_iter_same_as_get() {
260 let mut buf = BeBuffer::new();
261 buf = buf.push(4u32).extend([1u8, 2, 3, 4]);
262 buf = buf.push(2u32).extend([5u8, 6]);
263 buf = buf.push(3u32).extend([7u8, 8, 9]);
264 let arr: VarLenArray<VarLenItem> = VarLenArray::read(FontData::new(buf.data())).unwrap();
265 let iter_items: Vec<_> = arr.iter().map(|x| x.unwrap()).collect();
266 let get_items: Vec<_> = (0..iter_items.len())
267 .map(|i| arr.get(i).unwrap().unwrap())
268 .collect();
269 assert_eq!(iter_items.len(), get_items.len());
270 for (a, b) in iter_items.iter().zip(get_items.iter()) {
271 assert_eq!(a.data(), b.data());
272 }
273 }
274}