diff --git a/src/bin/flat/tube/mod.rs b/src/bin/flat/tube/mod.rs index 6b256c0..846a7a0 100644 --- a/src/bin/flat/tube/mod.rs +++ b/src/bin/flat/tube/mod.rs @@ -171,22 +171,35 @@ impl Space { } } +/// Like [`std::iter::successors`] but with an upper limit on iteration count. +/// +/// # Panics +/// +/// Panics if the sequence doesn’t terminate in `max_iters` calls of `succ`. +fn iterate_with_limit(max_iters: usize, init: T, mut succ: impl FnMut(T) -> Option) { + let mut state = init; + for _ in 0..max_iters { + match succ(state) { + Some(next) => state = next, + None => return, + } + } + panic!("iteration limit exceeded"); +} + impl Traceable for Space { fn trace(&self, camera: Location, ray: Ray) -> Vec { let ray = self.camera_ray_to_abs(camera, ray); let mut hits = vec![]; - std::iter::successors(Some(ray), |ray: &Ray| { + iterate_with_limit(100, ray, |ray| { let ret = self - .trace_iter(*ray) + .trace_iter(ray) .skip(1) .find_map(|ray| self.obj_hitter(ray.pos).map(|hitter| hitter(self, ray))) .expect("Space::trace_iter does not terminate"); hits.extend(ret.objects); // TODO fix distance ret.end - }) - .nth(100) - .is_some() - .then(|| panic!("tracing didn't terminate")); + }); hits } }