src/iterate.rs

branch
dev
changeset 40
daf0e3a70c79
parent 38
8aaa22fcd302
child 41
121cf065e9ed
--- a/src/iterate.rs	Sat Oct 19 10:39:54 2024 -0500
+++ b/src/iterate.rs	Sun Oct 20 23:28:16 2024 -0500
@@ -52,6 +52,8 @@
 use std::marker::PhantomData;
 use std::time::Duration;
 use std::error::Error;
+use std::rc::Rc;
+use std::cell::Cell;
 use crate::types::*;
 use crate::logger::*;
 
@@ -114,7 +116,7 @@
 ///
 /// This is the parameter obtained by the closure passed to [`AlgIterator::iterate`] or
 /// [`AlgIteratorFactory::iterate`].
-pub trait AlgIteratorState {
+pub trait AlgIteratorState : Sized {
     /// Call `call_objective` if this is a verbose iteration.
     ///
     /// Verbosity depends on the [`AlgIterator`] that produced this state.
@@ -122,7 +124,7 @@
     /// The closure `calc_objective` should return an arbitrary value of type `V`, to be inserted
     /// into the log, or whatever is deemed by the [`AlgIterator`]. For usage instructions see the
     /// [module documentation][self].
-    fn if_verbose<V, E : Error>(&self, calc_objective : impl FnMut() -> V) -> Step<V, E>;
+    fn if_verbose<V, E : Error>(self, calc_objective : impl FnMut() -> V) -> Step<V, Self, E>;
 
     /// Returns the current iteration count.
     fn iteration(&self) -> usize;
@@ -133,7 +135,7 @@
 
 /// Result of a step of an [`AlgIterator`]
 #[derive(Debug, Serialize)]
-pub enum Step<V, Fail : Error = std::convert::Infallible> {
+pub enum Step<V, S, Fail : Error = std::convert::Infallible> {
     /// Iteration should be terminated
     Terminated,
     /// Iteration should be terminated due to failure
@@ -141,14 +143,14 @@
     /// No result this iteration (due to verbosity settings)
     Quiet,
     /// Result of this iteration (due to verbosity settings)
-    Result(V),
+    Result(V, S),
 }
 
-impl<V, E : Error> Step<V, E> {
+impl<V, S, E : Error> Step<V, S, E> {
     /// Maps the value contained within the `Step`, if any, by the closure `f`.
-    pub fn map<U>(self, mut f : impl FnMut(V) -> U) -> Step<U, E> {
+    pub fn map<U>(self, mut f : impl FnMut(V) -> U) -> Step<U, S, E> {
         match self {
-            Step::Result(v) =>  Step::Result(f(v)),
+            Step::Result(v, s) =>  Step::Result(f(v), s),
             Step::Failure(e) => Step::Failure(e),
             Step::Quiet =>      Step::Quiet,
             Step::Terminated => Step::Terminated,
@@ -156,6 +158,12 @@
     }
 }
 
+impl<V, S, E : Error> Default for Step<V, S, E> {
+    fn default() -> Self {
+        Step::Quiet
+    }
+}
+
 /// An iterator for algorithms, produced by [`AlgIteratorFactory::prepare`].
 ///
 /// Typically not accessed directly, but transparently produced by an [`AlgIteratorFactory`].
@@ -163,13 +171,26 @@
 pub trait AlgIterator : Sized {
     /// The state type
     type State : AlgIteratorState;
-    /// The output type for [`Self::step`].
+    /// The output type for [`Self::poststep`] and [`Self::step`].
     type Output;
-    /// The error type for [`Self::step`] and [`Self::iterate`].
-    type Err : Error;
+    /// The input type for [`Self::poststep`].
+    type Input;
 
-    /// Advance the iterator.
-    fn step(&mut self) -> Step<Self::Output, Self::Err>;
+    /// Advance the iterator, performing `step_fn` with the state
+    fn step<F, E>(&mut self, step_fn : &mut F) -> Step<Self::Output, Self::State, E>
+    where F : FnMut(Self::State) -> Step<Self::Input, Self::State, E>,
+          E : Error {
+        self.prestep().map_or(Step::Terminated,
+                              |state| self.poststep(step_fn(state)))
+    }
+
+    /// Initial stage of advancing the iterator, before the actual step
+    fn prestep(&mut self) -> Option<Self::State>;
+
+    /// Handle step result
+    fn poststep<E>(&mut self, result : Step<Self::Input, Self::State, E>)
+    -> Step<Self::Output, Self::State, E>
+    where E : Error;
 
     /// Return current iteration count.
     fn iteration(&self) -> usize {
@@ -179,56 +200,29 @@
     /// Return current state.
     fn state(&self) -> Self::State;
 
-    /// Iterate the `AlgIterator` until termination.
+    /// Iterate the `AlgIterator` until termination, erforming `step_fn` on each step.
     ///
     /// Returns either `()` or an error if the step closure terminated in [`Step::FailureĀ“].
     #[inline]
-    fn iterate(&mut self) -> Result<(), Self::Err> {
+    fn iterate<F, E>(&mut self, mut step_fn : F) -> Result<(), E>
+    where F : FnMut(Self::State) -> Step<Self::Input, Self::State, E>,
+          E : Error {
         loop {
-            match self.step() {
+            match self.step(&mut step_fn) {
                 Step::Terminated => return Ok(()),
                 Step::Failure(e) => return Err(e),
                 _ => {},
             }
         }
     }
-
-    /// Converts the `AlgIterator` into a plain [`Iterator`].
-    ///
-    /// [`Step::Quiet`] results are discarded, and [`Step::Failure`] results **panic**.
-    fn downcast(self) -> AlgIteratorI<Self> {
-        AlgIteratorI(self)
-    }
-}
-
-/// Conversion of an `AlgIterator` into a plain [`Iterator`].
-///
-/// The conversion discards [`Step::Quiet`] and **panics** on [`Step::Failure`].
-pub struct AlgIteratorI<A>(A);
-
-impl<A> Iterator for AlgIteratorI<A>
-where A : AlgIterator {
-    type Item = A::Output;
-
-    fn next(&mut self) -> Option<A::Output> {
-        loop {
-            match self.0.step() {
-                Step::Result(v) => return Some(v),
-                Step::Failure(e) => panic!("{e:?}"),
-                Step::Terminated => return None,
-                Step::Quiet => continue,
-            }
-        }
-    }
 }
 
 /// A factory for producing an [`AlgIterator`].
 ///
 /// For usage instructions see the [module documentation][self].
 pub trait AlgIteratorFactory<V> : Sized {
-    type Iter<F, E> : AlgIterator<State = Self::State, Output = Self::Output, Err = E>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter : AlgIterator<State = Self::State, Input = V, Output = Self::Output>;
+
     /// The state type of the corresponding [`AlgIterator`].
     /// A reference to this is passed to the closures passed to methods such as [`Self::iterate`].
     type State : AlgIteratorState;
@@ -238,12 +232,7 @@
     type Output;
 
     /// Prepare an [`AlgIterator`], consuming the factory.
-    ///
-    /// The function `step_fn` should accept a `state` ([`AlgIteratorState`] parameter, and return
-    /// a [`Step`].
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error;
+    fn prepare(self) -> Self::Iter;
 
     /// Iterate the the closure `step`.
     ///
@@ -255,9 +244,9 @@
     /// This method is equivalent to [`Self::prepare`] followed by [`AlgIterator::iterate`].
     #[inline]
     fn iterate_fallible<F, E>(self, step : F) -> Result<(), E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
+    where F : FnMut(Self::State) -> Step<V, Self::State, E>,
           E : Error {
-        self.prepare(step).iterate()
+        self.prepare().iterate(step)
     }
 
     /// Iterate the the closure `step`.
@@ -272,7 +261,7 @@
     /// with the error type `E=`[`std::convert::Infallible`].
     #[inline]
     fn iterate<F>(self, step : F)
-    where F : FnMut(&Self::State) -> Step<V> {
+    where F : FnMut(Self::State) -> Step<V, Self::State> {
         self.iterate_fallible(step).unwrap_or_default()
     }
 
@@ -288,13 +277,14 @@
     ///
     /// For usage instructions see the [module documentation][self].
     #[inline]
-    fn iterate_data_fallible<F, D, I, E>(self, mut datasource : I, mut step : F) -> Result<(), E>
-    where F : FnMut(&Self::State, D) -> Step<V, E>,
+    fn iterate_data_fallible<F, D, I, E>(self, mut datasource : I, mut step : F)
+    -> Result<(), E>
+    where F : FnMut(Self::State, D) -> Step<V, Self::State, E>,
           I : Iterator<Item = D>,
           E : Error {
-        self.prepare(move |state| {
+        self.prepare().iterate(move |state| {
             datasource.next().map_or(Step::Terminated, |d| step(state, d))
-        }).iterate()
+        })
     }
 
     /// Iterate the closure `step` with data produced by `datasource`.
@@ -309,7 +299,7 @@
     /// For usage instructions see the [module documentation][self].
     #[inline]
     fn iterate_data<F, D, I>(self, datasource : I, step : F)
-    where F : FnMut(&Self::State, D) -> Step<V>,
+    where F : FnMut(Self::State, D) -> Step<V, Self::State>,
           I : Iterator<Item = D> {
         self.iterate_data_fallible(datasource, step).unwrap_or_default()
     }
@@ -398,6 +388,17 @@
 
     /// Is the iterator quiet, i.e., on-verbose?
     fn is_quiet(&self) -> bool { false }
+
+    /// Returns an an [`std::iter::Iterator`] that can be used in a `for`-loop.
+    fn iter(self) -> AlgIteratorIterator<Self::Iter> {
+        AlgIteratorIterator {
+            algi : self.prepare(),
+            result : Rc::new(AlgIteratorResponse{
+                expected_iter : 0,
+                response : Cell::new(Step::Quiet)
+            })
+        }
+    }
 }
 
 /// Options for [`BasicAlgIteratorFactory`].
@@ -483,11 +484,10 @@
 
 /// The simplest [`AlgIterator`], created by [`BasicAlgIteratorFactory`]
 #[derive(Clone,Debug)]
-pub struct BasicAlgIterator<F, V, E : Error> {
+pub struct BasicAlgIterator<V> {
     options : AlgIteratorOptions,
     iter : usize,
-    step_fn : F,
-    _phantoms : PhantomData<(V, E)>,
+    _phantoms : PhantomData<V>,
 }
 
 impl AlgIteratorOptions {
@@ -505,18 +505,13 @@
 impl<V> AlgIteratorFactory<V> for AlgIteratorOptions
 where V : LogRepr {
     type State = BasicState;
-    type Iter<F, E> = BasicAlgIterator<F, V, E>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = BasicAlgIterator<V>;
     type Output = V;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         BasicAlgIterator{
             options : self,
             iter : 0,
-            step_fn,
             _phantoms : PhantomData,
         }
     }
@@ -530,18 +525,13 @@
 impl<V> AlgIteratorFactory<V> for BasicAlgIteratorFactory<V>
 where V : LogRepr {
     type State = BasicState;
-    type Iter<F, E> = BasicAlgIterator<F, V, E>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = BasicAlgIterator<V>;
     type Output = V;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         BasicAlgIterator {
             options : self.options,
             iter : 0,
-            step_fn,
             _phantoms : PhantomData
         }
     }
@@ -552,33 +542,33 @@
     }
 }
 
-impl<F, V, E> AlgIterator for BasicAlgIterator<F, V, E>
-where V : LogRepr,
-      E : Error,
-      F : FnMut(&BasicState) -> Step<V, E> {
+impl<V> AlgIterator for BasicAlgIterator<V>
+where V : LogRepr {
     type State = BasicState;
     type Output = V;
-    type Err = E;
+    type Input = V;
 
     #[inline]
-    fn step(&mut self) -> Step<V, E> {
+    fn prestep(&mut self) -> Option<Self::State> {
         if self.iter >= self.options.max_iter {
-            Step::Terminated
+            None
         } else {
             self.iter += 1;
-            let state = self.state();
-            let res = (self.step_fn)(&state);
-            if let Step::Result(ref val) = res {
-                if state.verbose && !self.options.quiet {
-                    println!("{}{}/{} {}{}", "".dimmed(),
-                            state.iter,
-                            self.options.max_iter,
-                            val.logrepr(),
-                            "".clear());
-                }
+            Some(self.state())
+        }
+    }
+
+    fn poststep<E : Error>(&mut self, res : Step<V, Self::State, E>) -> Step<V, Self::State, E> {
+        if let Step::Result(ref val, ref state) = res {
+            if state.verbose && !self.options.quiet {
+                println!("{}{}/{} {}{}", "".dimmed(),
+                        state.iter,
+                        self.options.max_iter,
+                        val.logrepr(),
+                        "".clear());
             }
-            res
         }
+        res
     }
 
     #[inline]
@@ -601,9 +591,9 @@
 
 impl AlgIteratorState for BasicState {
     #[inline]
-    fn if_verbose<V, E : Error>(&self, mut calc_objective : impl FnMut() -> V) -> Step<V, E> {
+    fn if_verbose<V, E : Error>(self, mut calc_objective : impl FnMut() -> V) -> Step<V, Self, E> {
         if self.calc {
-            Step::Result(calc_objective())
+            Step::Result(calc_objective(), self)
         } else {
             Step::Quiet
         }
@@ -647,17 +637,13 @@
 for StallIteratorFactory<U, BaseFactory>
 where BaseFactory : AlgIteratorFactory<V, Output=U>,
       U : SignedNum + PartialOrd {
-    type Iter<F, E> = StallIterator<U, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = StallIterator<U, BaseFactory::Iter>;
     type State = BaseFactory::State;
     type Output = BaseFactory::Output;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         StallIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             stall : self.stall,
             previous_value : None,
         }
@@ -673,18 +659,24 @@
 where BaseIterator : AlgIterator<Output=U>,
       U : SignedNum + PartialOrd {
     type State = BaseIterator::State;
-    type Output = BaseIterator::Output;
-    type Err = BaseIterator::Err;
+    type Output = U;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<U, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(nv) => {
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<U, Self::State, E>
+    where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(nv, state) => {
                 let previous_v = self.previous_value;
                 self.previous_value = Some(nv);
                 match previous_v {
                     Some(pv) if (nv - pv).abs() <= self.stall * pv.abs() => Step::Terminated,
-                    _ => Step::Result(nv),
+                    _ => Step::Result(nv, state),
                 }
             },
             val => val,
@@ -722,17 +714,13 @@
 for ValueIteratorFactory<U, BaseFactory>
 where BaseFactory : AlgIteratorFactory<V, Output=U>,
       U : SignedNum + PartialOrd {
-    type Iter<F, E> = ValueIterator<U, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = ValueIterator<U, BaseFactory::Iter>;
     type State = BaseFactory::State;
     type Output = BaseFactory::Output;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         ValueIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             target : self.target
         }
     }
@@ -747,17 +735,22 @@
 where BaseIterator : AlgIterator<Output=U>,
       U : SignedNum + PartialOrd {
     type State = BaseIterator::State;
-    type Output = BaseIterator::Output;
-    type Err = BaseIterator::Err;
+    type Output = U;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<U, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(v) => {
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<U, Self::State, E> where E : Error{
+        match self.base_iterator.poststep(res) {
+            Step::Result(v, state) => {
                  if v <= self.target {
                     Step::Terminated
                  } else {
-                    Step::Result(v)
+                    Step::Result(v, state)
                  }
             },
             val => val,
@@ -803,16 +796,12 @@
 where BaseFactory : AlgIteratorFactory<V>,
       BaseFactory::Output : 'log {
     type State = BaseFactory::State;
-    type Iter<F, E> = LoggingIterator<'log, BaseFactory::Output, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = LoggingIterator<'log, BaseFactory::Output, BaseFactory::Iter>;
     type Output = ();
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         LoggingIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             logger : self.logger,
         }
     }
@@ -829,12 +818,17 @@
       BaseIterator::Output : 'log {
     type State = BaseIterator::State;
     type Output = ();
-    type Err = BaseIterator::Err;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<Self::Output, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(v) => {
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<(), Self::State, E> where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(v, _) => {
                 self.logger.log(v);
                 Step::Quiet
             },
@@ -856,7 +850,7 @@
 }
 
 /// This [`AlgIteratorFactory`] allows output mapping.
-/// 
+///
 /// Typically produced with [`AlgIteratorFactory::mapped`].
 #[derive(Debug)]
 pub struct MappingIteratorFactory<G, BaseFactory> {
@@ -879,16 +873,12 @@
 where BaseFactory : AlgIteratorFactory<V>,
       G : Fn(usize, BaseFactory::Output) -> U {
     type State = BaseFactory::State;
-    type Iter<F, E> = MappingIterator<G, BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = MappingIterator<G, BaseFactory::Iter>;
     type Output = U;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         MappingIterator {
-            base_iterator : self.base_options.prepare(step_fn),
+            base_iterator : self.base_options.prepare(),
             map : self.map
         }
     }
@@ -905,12 +895,17 @@
       G : Fn(usize, BaseIterator::Output) -> U {
     type State = BaseIterator::State;
     type Output = U;
-    type Err = BaseIterator::Err;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<Self::Output, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(v) => Step::Result((self.map)(self.iteration(), v)),
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<Self::Output, Self::State, E> where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(v, state) => Step::Result((self.map)(self.iteration(), v), state),
             Step::Quiet => Step::Quiet,
             Step::Terminated => Step::Terminated,
             Step::Failure(e) => Step::Failure(e),
@@ -962,16 +957,12 @@
 for TimingIteratorFactory<BaseFactory>
 where BaseFactory : AlgIteratorFactory<V> {
     type State = BaseFactory::State;
-    type Iter<F, E> = TimingIterator<BaseFactory::Iter<F, E>>
-        where F : FnMut(&Self::State) -> Step<V, E>,
-              E : Error;
+    type Iter = TimingIterator<BaseFactory::Iter>;
     type Output = Timed<BaseFactory::Output>;
 
-    fn prepare<F, E>(self, step_fn : F) -> Self::Iter<F, E>
-    where F : FnMut(&Self::State) -> Step<V, E>,
-          E : Error {
+    fn prepare(self) -> Self::Iter {
         TimingIterator {
-            base_iterator : self.0.prepare(step_fn),
+            base_iterator : self.0.prepare(),
             start_time : ProcessTime::now()
         }
     }
@@ -987,16 +978,21 @@
 where BaseIterator : AlgIterator {
     type State = BaseIterator::State;
     type Output = Timed<BaseIterator::Output>;
-    type Err = BaseIterator::Err;
+    type Input = BaseIterator::Input;
 
     #[inline]
-    fn step(&mut self) -> Step<Self::Output, Self::Err> {
-        match self.base_iterator.step() {
-            Step::Result(data) => {
+    fn prestep(&mut self) -> Option<Self::State> {
+        self.base_iterator.prestep()
+    }
+
+    #[inline]
+    fn poststep<E>(&mut self, res : Step<Self::Input, Self::State, E>) -> Step<Self::Output, Self::State, E> where E : Error {
+        match self.base_iterator.poststep(res) {
+            Step::Result(data, state) => {
                 Step::Result(Timed{
                     cpu_time : self.start_time.elapsed(),
                     data
-                })
+                }, state)
             },
             Step::Quiet => Step::Quiet,
             Step::Terminated => Step::Terminated,
@@ -1016,6 +1012,100 @@
 }
 
 //
+// New for-loop interface
+//
+
+struct AlgIteratorResponse<I : AlgIterator> {
+    expected_iter : usize,
+    response : Cell<Step<I::Input, I::State>>,
+}
+pub struct AlgIteratorIterator<I : AlgIterator> {
+    algi : I,
+    result : Rc<AlgIteratorResponse<I>>,
+}
+
+pub struct AlgIteratorIteration<I : AlgIterator> {
+    state : I::State,
+    result : Rc<AlgIteratorResponse<I>>,
+}
+
+impl<I : AlgIterator> AlgIteratorIterator<I> {
+    fn poststep(&mut self, even_if_quiet : bool) {
+        let res = self.result.response.take();
+        if !even_if_quiet {
+            if let Step::Quiet = res {
+                return
+            }
+        }
+        self.algi.poststep(res);
+    }
+}
+
+impl<I : AlgIterator> std::iter::Iterator for AlgIteratorIterator<I> {
+    type Item = AlgIteratorIteration<I>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.poststep(true);
+        self.algi.prestep().map(|state| AlgIteratorIteration {
+            state,
+            result : self.result.clone(),
+        })
+    }
+}
+
+impl<I : AlgIterator> Drop for AlgIteratorIterator<I> {
+    fn drop(&mut self) {
+        self.poststep(false)
+    }
+}
+
+/// Types of errors that may occur
+#[derive(Debug,PartialEq,Eq)]
+pub enum IterationError {
+    /// [`AlgIteratorIteration::if_verbose_check`] is not called in iteration order.
+    ReportingOrderingError
+}
+
+impl<I : AlgIterator> AlgIteratorIteration<I> {
+    /// Call `call_objective` if this is a verbose iteration.
+    ///
+    /// Verbosity depends on the [`AlgIterator`] that produced this state.
+    ///
+    /// The closure `calc_objective` should return an arbitrary value of type `V`, to be inserted
+    /// into the log, or whatever is deemed by the [`AlgIterator`]. For usage instructions see the
+    /// [module documentation][self].
+    ///
+    /// This function may panic if result reporting is not ordered correctly (an unlikely mistake
+    /// if using this facility correctly). For a version that propagates errors, see
+    /// [`Self::if_verbose_check`].
+    pub fn if_verbose(self, calc_objective : impl FnMut() -> I::Input) {
+        self.if_verbose_check(calc_objective).unwrap()
+    }
+
+    /// Version of [`Self::if_verbose`] that propagates errors instead of panicking.
+    pub fn if_verbose_check(self, mut calc_objective : impl FnMut() -> I::Input)
+    -> Result<(), IterationError> {
+        if self.result.expected_iter != self.state.iteration() {
+            Err(IterationError::ReportingOrderingError)
+        } else {
+            let res = calc_objective();
+            self.result.response.replace(Step::Result(res, self.state));
+            Ok(())
+        }
+    }
+
+    /// Returns the current iteration count.
+    pub fn iteration(&self) -> usize {
+        self.state.iteration()
+    }
+
+    /// Indicates whether the iterator is quiet
+    pub fn is_quiet(&self) -> bool {
+        self.state.is_quiet()
+    }
+}
+
+//
 // Tests
 //
 

mercurial