Skip to main content

omena_parser/
instrumentation.rs

1//! Lightweight instrumentation for parser materialization.
2//!
3//! The counters in this module support regression gates that verify parser
4//! consumers do not accidentally rematerialize token streams.
5
6use std::cell::Cell;
7#[cfg(test)]
8use std::sync::atomic::{AtomicUsize, Ordering};
9
10use serde::Serialize;
11
12#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)]
13#[serde(rename_all = "camelCase")]
14pub struct OmenaParserLexInstrumentationSnapshotV0 {
15    pub lex_invocation_count: u64,
16    pub lex_token_count: u64,
17}
18
19#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize)]
20#[serde(rename_all = "camelCase")]
21pub struct OmenaParserParseInstrumentationSnapshotV0 {
22    pub parse_invocation_count: u64,
23    pub parse_token_count: u64,
24}
25
26thread_local! {
27    static LEX_INSTRUMENTATION: Cell<Option<OmenaParserLexInstrumentationSnapshotV0>> =
28        const { Cell::new(None) };
29    static PARSE_INSTRUMENTATION: Cell<Option<OmenaParserParseInstrumentationSnapshotV0>> =
30        const { Cell::new(None) };
31    #[cfg(test)]
32    static SYNTAX_ROOT_MATERIALIZATION_COUNT: AtomicUsize =
33        const { AtomicUsize::new(0) };
34    #[cfg(feature = "test-support")]
35    static CLOSED_WORLD_BUNDLE_CONSTRUCTION_COUNT: Cell<usize> = const { Cell::new(0) };
36}
37
38pub fn with_omena_parser_lex_instrumentation<T>(
39    operation: impl FnOnce() -> T,
40) -> (T, OmenaParserLexInstrumentationSnapshotV0) {
41    LEX_INSTRUMENTATION.with(|instrumentation| {
42        let previous =
43            instrumentation.replace(Some(OmenaParserLexInstrumentationSnapshotV0::default()));
44        let value = operation();
45        let snapshot = instrumentation
46            .replace(previous)
47            .unwrap_or_else(OmenaParserLexInstrumentationSnapshotV0::default);
48        (value, snapshot)
49    })
50}
51
52pub fn with_omena_parser_parse_instrumentation<T>(
53    operation: impl FnOnce() -> T,
54) -> (T, OmenaParserParseInstrumentationSnapshotV0) {
55    PARSE_INSTRUMENTATION.with(|instrumentation| {
56        let previous =
57            instrumentation.replace(Some(OmenaParserParseInstrumentationSnapshotV0::default()));
58        let value = operation();
59        let snapshot = instrumentation
60            .replace(previous)
61            .unwrap_or_else(OmenaParserParseInstrumentationSnapshotV0::default);
62        (value, snapshot)
63    })
64}
65
66pub(crate) fn record_omena_parser_lex_materialization(token_count: usize) {
67    LEX_INSTRUMENTATION.with(|instrumentation| {
68        if let Some(mut snapshot) = instrumentation.get() {
69            snapshot.lex_invocation_count += 1;
70            snapshot.lex_token_count += token_count as u64;
71            instrumentation.set(Some(snapshot));
72        }
73    });
74}
75
76pub(crate) fn record_omena_parser_parse_materialization(token_count: usize) {
77    PARSE_INSTRUMENTATION.with(|instrumentation| {
78        if let Some(mut snapshot) = instrumentation.get() {
79            snapshot.parse_invocation_count += 1;
80            snapshot.parse_token_count += token_count as u64;
81            instrumentation.set(Some(snapshot));
82        }
83    });
84}
85
86#[cfg(feature = "test-support")]
87pub(crate) fn record_closed_world_bundle_construction_for_test() {
88    CLOSED_WORLD_BUNDLE_CONSTRUCTION_COUNT.with(|counter| counter.set(counter.get() + 1));
89}
90
91#[cfg(feature = "test-support")]
92pub fn reset_closed_world_bundle_construction_count_for_test() {
93    CLOSED_WORLD_BUNDLE_CONSTRUCTION_COUNT.with(|counter| counter.set(0));
94}
95
96#[cfg(feature = "test-support")]
97pub fn closed_world_bundle_construction_count_for_test() -> usize {
98    CLOSED_WORLD_BUNDLE_CONSTRUCTION_COUNT.with(Cell::get)
99}
100
101#[cfg(test)]
102pub(crate) fn record_omena_parser_syntax_root_materialization() {
103    SYNTAX_ROOT_MATERIALIZATION_COUNT.with(|counter| counter.fetch_add(1, Ordering::SeqCst));
104}
105
106#[cfg(not(test))]
107pub(crate) fn record_omena_parser_syntax_root_materialization() {}
108
109#[cfg(test)]
110pub(crate) fn reset_omena_parser_syntax_root_materialization_count() {
111    SYNTAX_ROOT_MATERIALIZATION_COUNT.with(|counter| counter.store(0, Ordering::SeqCst));
112}
113
114#[cfg(test)]
115pub(crate) fn omena_parser_syntax_root_materialization_count() -> usize {
116    SYNTAX_ROOT_MATERIALIZATION_COUNT.with(|counter| counter.load(Ordering::SeqCst))
117}