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