Repository: typst/typst
File: crates/typst-library/src/introspection/counter.rs (Rust)

Code before:
                .to_packed::<HeadingElem>()
                .and_then(|elem| elem.numbering.as_option().clone())
                .flatten()
        } else if self.0 == FigureElem::ELEM {
            content
                .to_packed::<FigureElem>()
                .and_then(|elem| elem.numbering.as_option().clone())
                .flatten()
        } else if self.0 == EquationElem::ELEM {
            content
                .to_packed::<EquationElem>()
                .and_then(|elem| elem.numbering.as_option().clone())
                .flatten()
        } else if self.0 == FootnoteElem::ELEM {
            content
                .to_packed::<FootnoteElem>()
                .and_then(|elem| elem.numbering.as_option().clone())
        } else {
            None
        };

        Ok(numbering)
    }

    fn diagnose(&self, _: &History<Self::Output>) -> SourceDiagnostic {
        warning!(self.2, "is a warning even needed here")
    }
}

/// Produces the whole sequence of a counter.
///
/// Due to memoization, this has to happen just once for all retrievals of the
/// same counter, cutting down the number of computations from quadratic to
/// linear.
fn sequence(
    counter: &Counter,
    engine: &mut Engine,
    introspector: Tracked<Introspector>,
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
    sequence_impl(
        counter,
        engine.routines,
        engine.world,
        introspector,
        engine.traced,
        TrackedMut::reborrow_mut(&mut engine.sink),
        engine.route.track(),
    )
}

/// Memoized implementation of `sequence`.

Review comment (bug):
yes :D 

it can fail to converge if the content appears and / or disappears depending on the layout iteration.

but you can use the `QueryUniqueIntrospection` with a `Selector::Location` here.

Code after:
    ) -> Self::Output {
        let Self(counter, _) = self;
        let sequence = sequence(counter, engine, introspector)?;
        let (mut state, page) = sequence.last().unwrap().clone();
        if counter.is_page() {
            let delta = introspector.pages().get().saturating_sub(page.get());
            state.step(NonZeroUsize::ONE, delta as u64);
        }
        Ok(state)
    }

    fn diagnose(&self, history: &History<Self::Output>) -> SourceDiagnostic {
        format_convergence_warning(&self.0, self.1, history)
    }
}

/// Produces the whole sequence of a counter.
///
/// Due to memoization, this has to happen just once for all retrievals of the
/// same counter, cutting down the number of computations from quadratic to
/// linear.
fn sequence(
    counter: &Counter,
    engine: &mut Engine,
    introspector: Tracked<Introspector>,
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
    sequence_impl(
        counter,
        engine.routines,
        engine.world,
        introspector,
        engine.traced,
        TrackedMut::reborrow_mut(&mut engine.sink),
        engine.route.track(),
    )
}

/// Memoized implementation of `sequence`.
#[comemo::memoize]
fn sequence_impl(
    counter: &Counter,
    routines: &Routines,
    world: Tracked<dyn World + '_>,
    introspector: Tracked<Introspector>,
    traced: Tracked<Traced>,
    sink: TrackedMut<Sink>,
    route: Tracked<Route>,
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
    let mut engine = Engine {
        routines,
        world,