1use std::str::Lines;
2
3use bunny_mesh::Triangle32;
4
5use super::{
6 face_indices_are_valid, parse_face_line, parse_vertex_line, statement_kind, ObjError, ObjVertex,
7};
8
9#[derive(Clone, Debug)]
11pub struct ObjVertices<'a> {
12 lines: Lines<'a>,
13}
14
15impl<'a> ObjVertices<'a> {
16 pub(super) fn new(source: &'a str) -> Self {
17 Self { lines: source.lines() }
18 }
19}
20
21impl Iterator for ObjVertices<'_> {
22 type Item = Result<ObjVertex, ObjError>;
23
24 fn next(&mut self) -> Option<Self::Item> {
25 next_record(&mut self.lines, "v").map(|line| line.and_then(parse_vertex_line))
26 }
27}
28
29#[derive(Clone, Debug)]
31pub struct ObjTriangles<'a> {
32 lines: Lines<'a>,
33 vertex_count: usize,
34}
35
36impl<'a> ObjTriangles<'a> {
37 pub(super) fn new(source: &'a str, vertex_count: usize) -> Self {
38 Self { lines: source.lines(), vertex_count }
39 }
40}
41
42impl Iterator for ObjTriangles<'_> {
43 type Item = Result<Triangle32, ObjError>;
44
45 fn next(&mut self) -> Option<Self::Item> {
46 next_record(&mut self.lines, "f").map(|line| {
47 line.and_then(parse_face_line)
48 .and_then(|triangle| validate_iter_triangle(triangle, self.vertex_count))
49 })
50 }
51}
52
53pub(super) fn find_record<'a>(source: &'a str, kind: &str, index: usize) -> Option<&'a str> {
54 let mut lines = source.lines();
55 let mut found = 0;
56 while let Some(record) = next_record(&mut lines, kind) {
57 let Ok(line) = record else {
58 return None;
59 };
60 if found == index {
61 return Some(line);
62 }
63 found += 1;
64 }
65 None
66}
67
68fn next_record<'a>(lines: &mut Lines<'a>, kind: &str) -> Option<Result<&'a str, ObjError>> {
69 for line in lines {
70 match statement_kind(line) {
71 Ok(Some(record_kind)) if record_kind == kind => return Some(Ok(line)),
72 Ok(Some(_) | None) => {}
73 Err(error) => return Some(Err(error)),
74 }
75 }
76 None
77}
78
79fn validate_iter_triangle(
80 triangle: Triangle32,
81 vertex_count: usize,
82) -> Result<Triangle32, ObjError> {
83 if face_indices_are_valid(triangle, vertex_count) {
84 Ok(triangle)
85 } else {
86 Err(ObjError::IndexOutOfBounds)
87 }
88}