omf/data/
iterators.rs

1use std::fmt::Display;
2
3use chrono::{DateTime, NaiveDate, Utc};
4
5use crate::{
6    date_time::{date_time_to_f64, date_time_to_i64, date_to_f64, date_to_i64},
7    error::Error,
8    file::{ReadAt, SubFile},
9    pqarray::read::SimpleIter,
10};
11
12use super::{
13    BoundaryValues, GenericArrays, GenericFreeformSubblocks, GenericNumbers, GenericOptionalArrays,
14    GenericScalars, NumberType,
15};
16
17#[derive(Debug, Clone, Copy, PartialEq)]
18pub enum Boundary<T: NumberType> {
19    Less(T),
20    LessEqual(T),
21}
22
23impl<T: NumberType> Boundary<T> {
24    pub fn from<U: NumberType + Into<T>>(other: Boundary<U>) -> Self {
25        match other {
26            Boundary::Less(value) => Self::Less(value.into()),
27            Boundary::LessEqual(value) => Self::LessEqual(value.into()),
28        }
29    }
30
31    pub fn from_value(value: T, is_inclusive: bool) -> Self {
32        if is_inclusive {
33            Self::LessEqual(value)
34        } else {
35            Self::Less(value)
36        }
37    }
38
39    pub fn value(self) -> T {
40        match self {
41            Boundary::Less(value) | Boundary::LessEqual(value) => value,
42        }
43    }
44
45    pub fn is_inclusive(self) -> bool {
46        match self {
47            Boundary::Less(_) => false,
48            Boundary::LessEqual(_) => true,
49        }
50    }
51
52    pub fn map<U: NumberType>(self, func: impl FnOnce(T) -> U) -> Boundary<U> {
53        match self {
54            Boundary::Less(t) => Boundary::Less(func(t)),
55            Boundary::LessEqual(t) => Boundary::LessEqual(func(t)),
56        }
57    }
58}
59
60impl<T: NumberType + Display> Display for Boundary<T> {
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        match self {
63            Self::Less(value) => write!(f, "< {value}"),
64            Self::LessEqual(value) => write!(f, "≤ {value}"),
65        }
66    }
67}
68
69/// Iterator for reading scalar data.
70///
71/// Casts to `f64` by default or you can access the variants directly.
72#[derive(Debug)]
73pub enum Scalars<R: ReadAt> {
74    F32(GenericScalars<f32, R>),
75    F64(GenericScalars<f64, R>),
76}
77
78impl<R: ReadAt> Iterator for Scalars<R> {
79    type Item = Result<f64, Error>;
80
81    fn next(&mut self) -> Option<Self::Item> {
82        match self {
83            Self::F64(iter) => iter.next(),
84            Self::F32(iter) => iter.next().map(|r| r.map(Into::into)),
85        }
86    }
87}
88
89/// Iterator for reading vertex data of various types.
90///
91/// Can be used as an iterator that casts to `[f64; 3]` or you can access the variants directly.
92#[derive(Debug)]
93pub enum Vertices<R: ReadAt> {
94    F32(GenericArrays<f32, 3, R>),
95    F64(GenericArrays<f64, 3, R>),
96}
97
98impl<R: ReadAt> Iterator for Vertices<R> {
99    type Item = Result<[f64; 3], Error>;
100
101    fn next(&mut self) -> Option<Self::Item> {
102        match self {
103            Self::F64(iter) => iter.next(),
104            Self::F32(iter) => array_item_cast(iter.next()),
105        }
106    }
107}
108
109fn array_item_cast<T, U: From<T>, const N: usize>(
110    input: Option<Result<[T; N], Error>>,
111) -> Option<Result<[U; N], Error>> {
112    input.map(|r| r.map(|a| a.map(Into::into)))
113}
114
115/// Iterator for reading texture coordinate data of various types.
116///
117/// Can be used as an iterator that casts to `[f64; 2]` or you can access the variants directly.
118#[derive(Debug)]
119pub enum Texcoords<R: ReadAt> {
120    F32(GenericArrays<f32, 2, R>),
121    F64(GenericArrays<f64, 2, R>),
122}
123
124impl<R: ReadAt> Iterator for Texcoords<R> {
125    type Item = Result<[f64; 2], Error>;
126
127    fn next(&mut self) -> Option<Self::Item> {
128        match self {
129            Self::F64(iter) => iter.next(),
130            Self::F32(iter) => array_item_cast(iter.next()),
131        }
132    }
133}
134
135/// Iterator for reading number data of various types.
136///
137/// You can access the variants directly or use the `try_into_f64` and `try_into_i64` methods.
138/// These methods can both fail so aren't automatic.
139#[derive(Debug)]
140pub enum Numbers<R: ReadAt> {
141    F32(GenericNumbers<f32, R>),
142    F64(GenericNumbers<f64, R>),
143    I64(GenericNumbers<i64, R>),
144    Date(GenericNumbers<NaiveDate, R>),
145    DateTime(GenericNumbers<DateTime<Utc>, R>),
146}
147
148impl<R: ReadAt> Numbers<R> {
149    /// Turns this into an `f64` iterator, casting values.
150    ///
151    /// If the numbers use type `i64` this will fail with `Error::UnsafeCast`. Dates will become
152    /// days since the '1970-01-01' epoch. Date-times will become seconds since the
153    /// '1970-01-01T00:00:00Z' epoch with a small loss of precision.
154    ///
155    /// Currently can't fail but future number types might yield `Error::UnsafeCast`.
156    pub fn try_into_f64(self) -> Result<NumbersF64<R>, Error> {
157        match &self {
158            Numbers::I64(_) => Err(Error::UnsafeCast("64-bit integer", "64-bit float")),
159            Numbers::F32(_) | Numbers::F64(_) | Numbers::Date(_) | Numbers::DateTime(_) => {
160                Ok(NumbersF64(self))
161            }
162        }
163    }
164
165    /// Turns this into an `i64` iterator, casting values.
166    ///
167    /// Floating-point types will be rejected with `Error::UnsafeCast`. Dates will become
168    /// days since the '1970-01-01' epoch. Date-times will become microseconds since the
169    /// '1970-01-01T00:00:00Z' epoch.
170    pub fn try_into_i64(self) -> Result<NumbersI64<R>, Error> {
171        match self {
172            Numbers::F32(_) => Err(Error::UnsafeCast("32-bit float", "64-bit integer")),
173            Numbers::F64(_) => Err(Error::UnsafeCast("64-bit float", "64-bit integer")),
174            Numbers::I64(_) | Numbers::Date(_) | Numbers::DateTime(_) => Ok(NumbersI64(self)),
175        }
176    }
177}
178
179pub struct NumbersF64<R: ReadAt>(Numbers<R>);
180
181impl<R: ReadAt> Iterator for NumbersF64<R> {
182    type Item = Result<Option<f64>, Error>;
183
184    fn next(&mut self) -> Option<Self::Item> {
185        match &mut self.0 {
186            Numbers::F32(i) => i.next().map(|r| r.map(|o| o.map(Into::into))),
187            Numbers::F64(i) => i.next(),
188            Numbers::Date(i) => i.next().map(|r| r.map(|o| o.map(date_to_f64))),
189            Numbers::DateTime(i) => i.next().map(|r| r.map(|o| o.map(date_time_to_f64))),
190            Numbers::I64(_) => None,
191        }
192    }
193}
194
195pub struct NumbersI64<R: ReadAt>(Numbers<R>);
196
197impl<R: ReadAt> Iterator for NumbersI64<R> {
198    type Item = Result<Option<i64>, Error>;
199
200    fn next(&mut self) -> Option<Self::Item> {
201        match &mut self.0 {
202            Numbers::F32(_) | Numbers::F64(_) => None,
203            Numbers::I64(i) => i.next(),
204            Numbers::Date(i) => i.next().map(|r| r.map(|o| o.map(date_to_i64))),
205            Numbers::DateTime(i) => i.next().map(|r| r.map(|o| o.map(date_time_to_i64))),
206        }
207    }
208}
209
210/// Iterator for reading vector data.
211///
212/// Casts to `Option<[f64; 3]>` by default or you can access the variants directly.
213/// 2D vectors are cast to a 3D vector with zero in the Z component.
214#[derive(Debug)]
215pub enum Vectors<R: ReadAt> {
216    F32x2(GenericOptionalArrays<f32, 2, R>),
217    F64x2(GenericOptionalArrays<f64, 2, R>),
218    F32x3(GenericOptionalArrays<f32, 3, R>),
219    F64x3(GenericOptionalArrays<f64, 3, R>),
220}
221
222impl<R: ReadAt> Iterator for Vectors<R> {
223    type Item = Result<Option<[f64; 3]>, Error>;
224
225    fn next(&mut self) -> Option<Self::Item> {
226        match self {
227            Self::F32x2(iter) => iter
228                .next()
229                .map(|r| r.map(|o| o.map(|[x, y]| [x.into(), y.into(), 0.0]))),
230            Self::F64x2(iter) => iter.next().map(|r| r.map(|o| o.map(|[x, y]| [x, y, 0.0]))),
231            Self::F32x3(iter) => {
232                let input = iter.next();
233                input.map(|r| r.map(|o| o.map(|a| a.map(Into::into))))
234            }
235            Self::F64x3(iter) => iter.next(),
236        }
237    }
238}
239
240/// Generic iterator for boundary data.
241pub struct GenericBoundaries<T: NumberType, R: ReadAt> {
242    value: BoundaryValues<T, R>,
243    inclusive: SimpleIter<bool, SubFile<R>>,
244}
245
246impl<T: NumberType + std::fmt::Debug, R: ReadAt + std::fmt::Debug> std::fmt::Debug
247    for GenericBoundaries<T, R>
248{
249    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250        f.debug_struct("GenericBoundaries")
251            .field("value", &self.value)
252            .field("inclusive", &"...")
253            .finish()
254    }
255}
256
257impl<T: NumberType, R: ReadAt> GenericBoundaries<T, R> {
258    pub fn new(value: SimpleIter<T, SubFile<R>>, inclusive: SimpleIter<bool, SubFile<R>>) -> Self {
259        Self {
260            value: BoundaryValues::new(value),
261            inclusive,
262        }
263    }
264}
265
266impl<T: NumberType, R: ReadAt> Iterator for GenericBoundaries<T, R> {
267    type Item = Result<Boundary<T>, Error>;
268
269    fn next(&mut self) -> Option<Self::Item> {
270        match (self.value.next(), self.inclusive.next()) {
271            (Some(Err(e)), _) | (_, Some(Err(e))) => Some(Err(e)),
272            (None, _) | (_, None) => None,
273            (Some(Ok(value)), Some(Ok(false))) => Some(Ok(Boundary::Less(value))),
274            (Some(Ok(value)), Some(Ok(true))) => Some(Ok(Boundary::LessEqual(value))),
275        }
276    }
277}
278
279/// Iterator for reading color data.
280///
281/// Casting is the same as [`Numbers`](Numbers).
282#[derive(Debug)]
283pub enum Boundaries<R: ReadAt> {
284    F32(GenericBoundaries<f32, R>),
285    F64(GenericBoundaries<f64, R>),
286    I64(GenericBoundaries<i64, R>),
287    Date(GenericBoundaries<NaiveDate, R>),
288    DateTime(GenericBoundaries<DateTime<Utc>, R>),
289}
290
291impl<R: ReadAt> Boundaries<R> {
292    /// Turns this into an `f64` boundary iterator, casting values.
293    ///
294    /// If the numbers use type `i64` this will fail with `Error::UnsafeCast`. Dates will become
295    /// days since the '1970-01-01' epoch. Date-times will become seconds since the
296    /// '1970-01-01T00:00:00Z' epoch with a small loss of precision.
297    ///
298    /// Currently can't fail but future number types might yield `Error::UnsafeCast`.
299    pub fn try_into_f64(self) -> Result<BoundariesF64<R>, Error> {
300        match &self {
301            Boundaries::I64(_) => Err(Error::UnsafeCast("64-bit integer", "64-bit float")),
302            Boundaries::F32(_)
303            | Boundaries::F64(_)
304            | Boundaries::Date(_)
305            | Boundaries::DateTime(_) => Ok(BoundariesF64(self)),
306        }
307    }
308
309    /// Turns this into an `i64` boundary iterator, casting values.
310    ///
311    /// Floating-point types will be rejected with `Error::UnsafeCast`. Dates will become
312    /// days since the '1970-01-01' epoch. Date-times will become microseconds since the
313    /// '1970-01-01T00:00:00Z' epoch.
314    pub fn try_into_i64(self) -> Result<BoundariesI64<R>, Error> {
315        match self {
316            Boundaries::F32(_) => Err(Error::UnsafeCast("32-bit float", "64-bit integer")),
317            Boundaries::F64(_) => Err(Error::UnsafeCast("64-bit float", "64-bit integer")),
318            Boundaries::I64(_) | Boundaries::Date(_) | Boundaries::DateTime(_) => {
319                Ok(BoundariesI64(self))
320            }
321        }
322    }
323}
324
325pub struct BoundariesF64<R: ReadAt>(Boundaries<R>);
326
327impl<R: ReadAt> Iterator for BoundariesF64<R> {
328    type Item = Result<Boundary<f64>, Error>;
329
330    fn next(&mut self) -> Option<Self::Item> {
331        match &mut self.0 {
332            Boundaries::F32(i) => i.next().map(|r| r.map(|o| o.map(Into::into))),
333            Boundaries::F64(i) => i.next(),
334            Boundaries::Date(i) => i.next().map(|r| r.map(|o| o.map(date_to_f64))),
335            Boundaries::DateTime(i) => i.next().map(|r| r.map(|o| o.map(date_time_to_f64))),
336            Boundaries::I64(_) => None,
337        }
338    }
339}
340
341pub struct BoundariesI64<R: ReadAt>(Boundaries<R>);
342
343impl<R: ReadAt> Iterator for BoundariesI64<R> {
344    type Item = Result<Boundary<i64>, Error>;
345
346    fn next(&mut self) -> Option<Self::Item> {
347        match &mut self.0 {
348            Boundaries::F32(_) | Boundaries::F64(_) => None,
349            Boundaries::I64(i) => i.next(),
350            Boundaries::Date(i) => i.next().map(|r| r.map(|o| o.map(date_to_i64))),
351            Boundaries::DateTime(i) => i.next().map(|r| r.map(|o| o.map(date_time_to_i64))),
352        }
353    }
354}
355
356/// Iterator for reading regular sub-block corner min/max data.
357///
358/// Casts to `[f64; 6]` by default or you can access the variants directly.
359/// Each item is `[min_x, min_y, min_z, max_x, max_y, max_z]`.
360#[derive(Debug)]
361pub enum FreeformSubblocks<R: ReadAt> {
362    F32(GenericFreeformSubblocks<f32, R>),
363    F64(GenericFreeformSubblocks<f64, R>),
364}
365
366impl<R: ReadAt> Iterator for FreeformSubblocks<R> {
367    type Item = Result<([u32; 3], [f64; 6]), Error>;
368
369    fn next(&mut self) -> Option<Self::Item> {
370        match self {
371            Self::F64(iter) => iter.next(),
372            Self::F32(iter) => match iter.next() {
373                Some(Ok((parent, corners))) => Some(Ok((parent, corners.map(Into::into)))),
374                Some(Err(e)) => Some(Err(e)),
375                None => None,
376            },
377        }
378    }
379}