1use crate::offset::ResolveNullableOffset;
7use font_types::{BigEndian, Nullable, Offset16, Scalar};
8
9use crate::{FontData, FontReadWithArgs, Offset, ReadArgs, ReadError, ResolveOffset};
10
11#[derive(Clone)]
18pub struct ArrayOfOffsets<'a, T: ReadArgs, O: Scalar = Offset16> {
19 offsets: &'a [BigEndian<O>],
20 data: FontData<'a>,
21 args: T::Args,
22}
23
24#[derive(Clone)]
29pub struct ArrayOfNullableOffsets<'a, T: ReadArgs, O: Scalar = Offset16> {
30 offsets: &'a [BigEndian<Nullable<O>>],
31 data: FontData<'a>,
32 args: T::Args,
33}
34
35impl<'a, T, O> ArrayOfOffsets<'a, T, O>
36where
37 O: Scalar,
38 T: ReadArgs,
39{
40 pub(crate) fn new(offsets: &'a [BigEndian<O>], data: FontData<'a>, args: T::Args) -> Self {
41 Self {
42 offsets,
43 data,
44 args,
45 }
46 }
47}
48
49impl<'a, T, O> ArrayOfOffsets<'a, T, O>
50where
51 O: Scalar + Offset,
52 T: ReadArgs + FontReadWithArgs<'a>,
53 T::Args: Copy + 'static,
54{
55 pub fn len(&self) -> usize {
57 self.offsets.len()
58 }
59
60 pub fn is_empty(&self) -> bool {
62 self.offsets.is_empty()
63 }
64
65 pub fn get(&self, idx: usize) -> Result<T, ReadError> {
70 self.offsets
71 .get(idx)
72 .ok_or(ReadError::InvalidCollectionIndex(idx as _))
73 .and_then(|o| o.get().resolve_with_args(self.data, &self.args))
74 }
75
76 pub fn iter(&self) -> impl Iterator<Item = Result<T, ReadError>> + 'a {
80 let mut iter = self.offsets.iter();
81 let args = self.args;
82 let data = self.data;
83 std::iter::from_fn(move || {
84 iter.next()
85 .map(|off| off.get().resolve_with_args(data, &args))
86 })
87 }
88
89 pub(crate) fn iter_as_nullable(
93 &self,
94 ) -> impl Iterator<Item = Option<Result<T, ReadError>>> + 'a {
95 self.iter().map(|off| match off {
96 Err(ReadError::NullOffset) => None,
97 other => Some(other),
98 })
99 }
100}
101
102impl<'a, T, O> ArrayOfNullableOffsets<'a, T, O>
103where
104 O: Scalar + Offset,
105 T: ReadArgs,
106{
107 pub(crate) fn new(
108 offsets: &'a [BigEndian<Nullable<O>>],
109 data: FontData<'a>,
110 args: T::Args,
111 ) -> Self {
112 Self {
113 offsets,
114 data,
115 args,
116 }
117 }
118}
119
120impl<'a, T, O> ArrayOfNullableOffsets<'a, T, O>
121where
122 O: Scalar + Offset,
123 T: ReadArgs + FontReadWithArgs<'a>,
124 T::Args: Copy + 'static,
125{
126 pub fn len(&self) -> usize {
128 self.offsets.len()
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.offsets.is_empty()
134 }
135
136 pub fn get(&self, idx: usize) -> Option<Result<T, ReadError>> {
142 let Some(offset) = self.offsets.get(idx) else {
143 return Some(Err(ReadError::InvalidCollectionIndex(idx as _)));
144 };
145 offset.get().resolve_with_args(self.data, &self.args)
146 }
147
148 pub fn iter(&self) -> impl Iterator<Item = Option<Result<T, ReadError>>> + 'a {
152 let mut iter = self.offsets.iter();
153 let args = self.args;
154 let data = self.data;
155 std::iter::from_fn(move || {
156 iter.next()
157 .map(|off| off.get().resolve_with_args(data, &args))
158 })
159 }
160}
161
162#[cfg(feature = "experimental_traverse")]
163impl<'a, T, O> crate::traversal::SomeArray<'a> for ArrayOfOffsets<'a, T, O>
164where
165 O: Scalar + Offset + Into<crate::traversal::OffsetType>,
166 T: ReadArgs + FontReadWithArgs<'a> + crate::traversal::SomeTable<'a> + 'a,
167 T::Args: Copy + 'static,
168{
169 fn type_name(&self) -> &str {
170 let full_name = std::any::type_name::<T>();
171 full_name.split("::").last().unwrap_or(full_name)
172 }
173
174 fn len(&self) -> usize {
175 self.offsets.len()
176 }
177
178 fn get(&self, idx: usize) -> Option<crate::traversal::FieldType<'a>> {
179 let off = self.offsets.get(idx)?;
180 let raw = off.get();
181 let result = raw.resolve_with_args::<T>(self.data, &self.args);
182 Some(crate::traversal::FieldType::offset(raw, result))
183 }
184}
185
186#[cfg(feature = "experimental_traverse")]
187impl<'a, T, O> crate::traversal::SomeArray<'a> for ArrayOfNullableOffsets<'a, T, O>
188where
189 O: Scalar + Offset + Into<crate::traversal::OffsetType> + Clone,
190 T: ReadArgs + FontReadWithArgs<'a> + crate::traversal::SomeTable<'a> + 'a,
191 T::Args: Copy + 'static,
192{
193 fn type_name(&self) -> &str {
194 let full_name = std::any::type_name::<T>();
195 full_name.split("::").last().unwrap_or(full_name)
196 }
197
198 fn len(&self) -> usize {
199 self.offsets.len()
200 }
201
202 fn get(&self, idx: usize) -> Option<crate::traversal::FieldType<'a>> {
203 let off = self.offsets.get(idx)?;
204 let raw = off.get();
205 let result = raw.resolve_with_args::<T>(self.data, &self.args);
206 Some(crate::traversal::FieldType::offset(raw, result))
207 }
208}