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

Code before:
impl Introspect for CounterFinalIntrospection {
    type Output = SourceResult<CounterState>;

    fn introspect(
        &self,
        engine: &mut Engine,
        introspector: Tracked<Introspector>,
    ) -> 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)
    }
}

/// Retrieves a counter at a specific location.
#[derive(Debug, Clone, PartialEq, Hash)]
struct NumberingAtIntrospection(Element, Location, Span);

impl Introspect for NumberingAtIntrospection {
    type Output = SourceResult<Option<Numbering>>;

    fn introspect(
        &self,
        _: &mut Engine,
        introspector: Tracked<Introspector>,
    ) -> Self::Output {
        let Some(content) = introspector.content_at(self.1) else {
            return Ok(None);
        };

        let numbering = if self.0 == HeadingElem::ELEM {
            content
                .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

Review comment (suggestion):
I probably didn't need to have done this, as it should be fine to call `.access` on the introspector myself? It's all internal anyways.

Code after:
#[derive(Debug, Clone, PartialEq, Hash)]
struct CounterBothIntrospection(Counter, Location, Span);

impl Introspect for CounterBothIntrospection {
    type Output = SourceResult<CounterState>;

    fn introspect(
        &self,
        engine: &mut Engine,
        introspector: Tracked<Introspector>,
    ) -> Self::Output {
        let Self(counter, loc, _) = self;
        let sequence = sequence(counter, engine, introspector)?;
        let offset = introspector.query_count_before(&counter.select(), *loc);
        let (mut at_state, at_page) = sequence[offset].clone();
        let (mut final_state, final_page) = sequence.last().unwrap().clone();
        if counter.is_page() {
            let at_delta = introspector.page(*loc).get().saturating_sub(at_page.get());
            at_state.step(NonZeroUsize::ONE, at_delta as u64);
            let final_delta = introspector.pages().get().saturating_sub(final_page.get());
            final_state.step(NonZeroUsize::ONE, final_delta as u64);
        }
        Ok(CounterState(smallvec![at_state.first(), final_state.first()]))
    }

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

/// Retrieves the final state of a counter.
#[derive(Debug, Clone, PartialEq, Hash)]
struct CounterFinalIntrospection(Counter, Span);

impl Introspect for CounterFinalIntrospection {
    type Output = SourceResult<CounterState>;

    fn introspect(
        &self,
        engine: &mut Engine,
        introspector: Tracked<Introspector>,
    ) -> 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)
    }