1use std::collections::HashSet;
2
3use crate::{
4 SubblockMode,
5 array::Constraint,
6 error::{Error, InvalidData},
7 file::{ReadAt, SubFile},
8 pqarray::read::{MultiIter, NullableGroupIter, NullableIter, SimpleIter},
9};
10
11use super::{
12 FloatType, NumberType,
13 write_checks::{subblock_is_octree_compat, valid_subblock_sizes},
14};
15
16#[derive(Debug)]
20pub struct GenericScalars<T: FloatType, R: ReadAt> {
21 inner: SimpleIter<T, SubFile<R>>,
22 is_size: bool,
23}
24
25impl<T: FloatType, R: ReadAt> GenericScalars<T, R> {
26 pub(crate) fn new(inner: SimpleIter<T, SubFile<R>>, constraint: &Constraint) -> Self {
27 Self {
28 inner,
29 is_size: matches!(constraint, Constraint::Size),
30 }
31 }
32}
33
34impl<T: FloatType, R: ReadAt> Iterator for GenericScalars<T, R> {
35 type Item = Result<T, Error>;
36
37 fn next(&mut self) -> Option<Self::Item> {
38 let item = self.inner.next()?;
39 if self.is_size {
40 if let Ok(value) = item {
41 if value <= T::default() {
42 return Some(Err(InvalidData::SizeZeroOrLess {
43 value: value.into(),
44 }
45 .into()));
46 }
47 }
48 }
49 Some(item)
50 }
51}
52
53#[derive(Debug)]
57pub struct Indices<R: ReadAt> {
58 inner: NullableIter<u32, SubFile<R>>,
59 category_count: u64,
60}
61
62impl<R: ReadAt> Indices<R> {
63 pub(crate) fn new(inner: NullableIter<u32, SubFile<R>>, constraint: &Constraint) -> Self {
64 let &Constraint::Index(category_count) = constraint else {
65 panic!("invalid constraint");
66 };
67 Self {
68 inner,
69 category_count,
70 }
71 }
72}
73
74impl<R: ReadAt> Iterator for Indices<R> {
75 type Item = Result<Option<u32>, Error>;
76
77 fn next(&mut self) -> Option<Self::Item> {
78 let item = self.inner.next()?;
79 if let Ok(Some(i)) = &item {
80 let index: u64 = (*i).into();
81 if index >= self.category_count {
82 return Some(Err(InvalidData::IndexOutOfRange {
83 value: index,
84 maximum: self.category_count.saturating_add(1),
85 }
86 .into()));
87 }
88 }
89 Some(item)
90 }
91}
92
93#[derive(Debug)]
97pub struct GenericPrimitives<const N: usize, R: ReadAt> {
98 inner: MultiIter<u32, SubFile<R>, N>,
99 vertex_count: u64,
100}
101
102impl<const N: usize, R: ReadAt> GenericPrimitives<N, R> {
103 pub(crate) fn new(inner: MultiIter<u32, SubFile<R>, N>, constraint: &Constraint) -> Self {
104 let vertex_count = match constraint {
105 Constraint::Segment(n) | Constraint::Triangle(n) => *n,
106 _ => panic!("invalid constraint"),
107 };
108 Self {
109 inner,
110 vertex_count,
111 }
112 }
113}
114
115impl<const N: usize, R: ReadAt> Iterator for GenericPrimitives<N, R> {
116 type Item = Result<[u32; N], Error>;
117
118 fn next(&mut self) -> Option<Self::Item> {
119 let item = self.inner.next()?;
120 if let Ok(value) = &item {
121 for i in value {
122 let index: u64 = (*i).into();
123 if index >= self.vertex_count {
124 return Some(Err(InvalidData::IndexOutOfRange {
125 value: index,
126 maximum: self.vertex_count.saturating_add(1),
127 }
128 .into()));
129 }
130 }
131 }
132 Some(item)
133 }
134}
135
136#[derive(Debug)]
140pub(super) struct BoundaryValues<T: NumberType, R: ReadAt> {
141 inner: SimpleIter<T, SubFile<R>>,
142 previous: Option<T>,
143}
144
145impl<T: NumberType, R: ReadAt> BoundaryValues<T, R> {
146 pub(crate) fn new(inner: SimpleIter<T, SubFile<R>>) -> Self {
147 Self {
148 inner,
149 previous: None,
150 }
151 }
152}
153
154impl<T: NumberType, R: ReadAt> Iterator for BoundaryValues<T, R> {
155 type Item = Result<T, Error>;
156
157 fn next(&mut self) -> Option<Self::Item> {
158 let item = self.inner.next()?;
159 if let (Ok(v), Some(p)) = (&item, &self.previous) {
160 if v < p {
161 return Some(Err(InvalidData::BoundaryDecreases.into()));
162 }
163 }
164 Some(item)
165 }
166}
167
168#[derive(Debug)]
172pub struct GenericFreeformSubblocks<T: FloatType, R: ReadAt> {
173 parents: MultiIter<u32, SubFile<R>, 3>,
174 corners: MultiIter<T, SubFile<R>, 6>,
175 block_count: [u32; 3],
176}
177
178impl<T: FloatType, R: ReadAt> GenericFreeformSubblocks<T, R> {
179 pub(crate) fn new(
180 parents: MultiIter<u32, SubFile<R>, 3>,
181 corners: MultiIter<T, SubFile<R>, 6>,
182 constraint: &Constraint,
183 ) -> Self {
184 let block_count = match constraint {
185 &Constraint::RegularSubblock { block_count, .. }
186 | &Constraint::FreeformSubblock { block_count } => block_count,
187 _ => panic!("invalid constraint"),
188 };
189 Self {
190 parents,
191 corners,
192 block_count,
193 }
194 }
195}
196
197impl<T: FloatType, R: ReadAt> Iterator for GenericFreeformSubblocks<T, R> {
198 type Item = Result<([u32; 3], [T; 6]), Error>;
199
200 fn next(&mut self) -> Option<Self::Item> {
201 match (self.parents.next(), self.corners.next()) {
202 (None, _) | (_, None) => None,
203 (Some(Err(e)), _) | (_, Some(Err(e))) => Some(Err(e)),
204 (Some(Ok(parent)), Some(Ok(corners))) => {
205 if let Err(e) = check_freeform_corners(corners) {
206 Some(Err(e))
207 } else if let Err(e) = check_parent(self.block_count, parent) {
208 Some(Err(e))
209 } else {
210 Some(Ok((parent, corners)))
211 }
212 }
213 }
214 }
215}
216
217#[derive(Debug)]
221pub struct RegularSubblocks<R: ReadAt> {
222 parents: MultiIter<u32, SubFile<R>, 3>,
223 corners: MultiIter<u32, SubFile<R>, 6>,
224 block_count: [u32; 3],
225 subblock_count: [u32; 3],
226 mode: Option<(SubblockMode, HashSet<[u32; 3]>)>,
227}
228
229impl<R: ReadAt> RegularSubblocks<R> {
230 pub(crate) fn new(
231 parents: MultiIter<u32, SubFile<R>, 3>,
232 corners: MultiIter<u32, SubFile<R>, 6>,
233 constraint: &Constraint,
234 ) -> Self {
235 let &Constraint::RegularSubblock {
236 block_count,
237 subblock_count,
238 mode,
239 } = constraint
240 else {
241 panic!("invalid constraint");
242 };
243 Self {
244 parents,
245 corners,
246 block_count,
247 subblock_count,
248 mode: mode.map(|m| (m, valid_subblock_sizes(m, subblock_count))),
249 }
250 }
251}
252
253impl<R: ReadAt> Iterator for RegularSubblocks<R> {
254 type Item = Result<([u32; 3], [u32; 6]), Error>;
255
256 fn next(&mut self) -> Option<Self::Item> {
257 match (self.parents.next(), self.corners.next()) {
258 (None, _) | (_, None) => None,
259 (Some(Err(e)), _) | (_, Some(Err(e))) => Some(Err(e)),
260 (Some(Ok(parent)), Some(Ok(corners))) => {
261 if let Err(e) = check_regular_corners(self.subblock_count, &self.mode, corners) {
262 Some(Err(e))
263 } else if let Err(e) = check_parent(self.block_count, parent) {
264 Some(Err(e))
265 } else {
266 Some(Ok((parent, corners)))
267 }
268 }
269 }
270 }
271}
272
273#[inline]
274fn check_parent(block_count: [u32; 3], parent: [u32; 3]) -> Result<(), Error> {
275 for (count, index) in block_count.into_iter().zip(parent) {
276 if index >= count {
277 return Err(InvalidData::BlockIndexOutOfRange {
278 value: parent.map(Into::into),
279 maximum: block_count,
280 }
281 .into());
282 }
283 }
284 Ok(())
285}
286
287#[inline]
288fn check_regular_corners(
289 subblock_count: [u32; 3],
290 mode_and_sizes: &Option<(SubblockMode, HashSet<[u32; 3]>)>,
291 corners: [u32; 6],
292) -> Result<(), Error> {
293 let corners: [u32; 6] = corners.map(Into::into);
294 for i in 0..3 {
295 if corners[i] >= corners[i + 3] {
296 return Err(InvalidData::RegularSubblockZeroSize { corners }.into());
297 }
298 if corners[i + 3] > subblock_count[i] {
299 return Err(InvalidData::RegularSubblockOutsideParent {
300 corners,
301 maximum: subblock_count,
302 }
303 .into());
304 }
305 }
306 if let Some((mode, valid_sizes)) = &mode_and_sizes {
307 let size = std::array::from_fn(|i| corners[i + 3] - corners[i]);
308 if !valid_sizes.contains(&size) {
309 return Err(InvalidData::RegularSubblockNotInMode {
310 corners,
311 mode: *mode,
312 }
313 .into());
314 }
315 if *mode == SubblockMode::Octree && !subblock_is_octree_compat(&corners) {
316 return Err(InvalidData::RegularSubblockNotInMode {
317 corners,
318 mode: *mode,
319 }
320 .into());
321 }
322 }
323 Ok(())
324}
325
326#[inline]
327fn check_freeform_corners<T: FloatType>(corners: [T; 6]) -> Result<(), Error> {
328 for i in 0..3 {
329 if corners[i] < T::ZERO {
330 return Err(InvalidData::FreeformSubblockOutsideParent {
331 corners: corners.map(Into::into),
332 }
333 .into());
334 }
335 if corners[i + 3] > T::ONE {
336 return Err(InvalidData::FreeformSubblockOutsideParent {
337 corners: corners.map(Into::into),
338 }
339 .into());
340 }
341 if corners[i] >= corners[i + 3] {
342 return Err(InvalidData::FreeformSubblockZeroSize {
343 corners: corners.map(Into::into),
344 }
345 .into());
346 }
347 }
348 Ok(())
349}
350
351#[derive(Debug)]
353pub struct GenericNumbers<T: NumberType, R: ReadAt>(pub(crate) NullableIter<T, SubFile<R>>);
354
355impl<T: NumberType, R: ReadAt> Iterator for GenericNumbers<T, R> {
356 type Item = Result<Option<T>, Error>;
357
358 fn next(&mut self) -> Option<Self::Item> {
359 self.0.next()
360 }
361}
362
363#[derive(Debug)]
365pub struct GenericArrays<T: NumberType, const N: usize, R: ReadAt>(
366 pub(crate) MultiIter<T, SubFile<R>, N>,
367);
368
369impl<T: NumberType, const N: usize, R: ReadAt> Iterator for GenericArrays<T, N, R> {
370 type Item = Result<[T; N], Error>;
371
372 fn next(&mut self) -> Option<Self::Item> {
373 self.0.next()
374 }
375}
376
377#[derive(Debug)]
379pub struct Gradient<R: ReadAt>(pub(crate) MultiIter<u8, SubFile<R>, 4>);
380
381impl<R: ReadAt> Iterator for Gradient<R> {
382 type Item = Result<[u8; 4], Error>;
383
384 fn next(&mut self) -> Option<Self::Item> {
385 self.0.next()
386 }
387}
388
389#[derive(Debug)]
391pub struct GenericOptionalArrays<T: NumberType, const N: usize, R: ReadAt>(
392 pub(crate) NullableGroupIter<T, SubFile<R>, N>,
393);
394
395impl<T: NumberType, const N: usize, R: ReadAt> Iterator for GenericOptionalArrays<T, N, R> {
396 type Item = Result<Option<[T; N]>, Error>;
397
398 fn next(&mut self) -> Option<Self::Item> {
399 self.0.next()
400 }
401}
402
403#[derive(Debug)]
405pub struct Colors<R: ReadAt>(pub(crate) NullableGroupIter<u8, SubFile<R>, 4>);
406
407impl<R: ReadAt> Iterator for Colors<R> {
408 type Item = Result<Option<[u8; 4]>, Error>;
409
410 fn next(&mut self) -> Option<Self::Item> {
411 self.0.next()
412 }
413}
414
415#[derive(Debug)]
417pub struct Booleans<R: ReadAt>(pub(crate) NullableIter<bool, SubFile<R>>);
418
419impl<R: ReadAt> Iterator for Booleans<R> {
420 type Item = Result<Option<bool>, Error>;
421
422 fn next(&mut self) -> Option<Self::Item> {
423 self.0.next()
424 }
425}
426
427#[derive(Debug)]
429pub struct Names<R: ReadAt>(pub(crate) SimpleIter<String, SubFile<R>>);
430
431impl<R: ReadAt> Iterator for Names<R> {
432 type Item = Result<String, Error>;
433
434 fn next(&mut self) -> Option<Self::Item> {
435 self.0.next()
436 }
437}
438
439#[derive(Debug)]
441pub struct Text<R: ReadAt>(pub(crate) NullableIter<String, SubFile<R>>);
442
443impl<R: ReadAt> Iterator for Text<R> {
444 type Item = Result<Option<String>, Error>;
445
446 fn next(&mut self) -> Option<Self::Item> {
447 self.0.next()
448 }
449}