Currently, the callback chain building and the actual invocation is done at the same time.
This means that invocation of Generator::run needs to check for initialization and that under debug mode, there might be 2n stack frames where n is the number of pipelines.
Here, I propose a new API for Generator:
trait Callback {
fn call(&mut self) -> GeneratorResult;
}
trait Generator {
type Output: Callback;
fn run(&mut self, output: impl FnMut(Self::Output) -> crate::ValueResult) -> Self::Output;
}
Call to Generator::run will initialize the pipeline (e.g. for Dedup, it would be getting the first element) and then return a callback to a closure that have the entire pipelines already built.
As a result, even under the debug build where no inline is performed, the stack frames used is guaranteed to be equal to the number of pipelines.
The function returned will be called inside for_each, try_for_each and IteratorAdaptor.
This would also make it clear to new contributors on which part is responsible for initialization and which part is accounted for the "loop body" and possibly remove some uses of Option.
Currently, the callback chain building and the actual invocation is done at the same time.
This means that invocation of
Generator::runneeds to check for initialization and that under debug mode, there might be2nstack frames wherenis the number of pipelines.Here, I propose a new API for
Generator:Call to
Generator::runwill initialize the pipeline (e.g. forDedup, it would be getting the first element) and then return a callback to a closure that have the entire pipelines already built.As a result, even under the debug build where no inline is performed, the stack frames used is guaranteed to be equal to the number of pipelines.
The function returned will be called inside
for_each,try_for_eachandIteratorAdaptor.This would also make it clear to new contributors on which part is responsible for initialization and which part is accounted for the "loop body" and possibly remove some uses of
Option.