Move the indent level for plain list's exit matcher to const fn instead of grabbing from the context.
All checks were successful
rust-test Build rust-test has succeeded
rust-build Build rust-build has succeeded

This made a slight improvement to performance.
This commit is contained in:
Tom Alexander 2023-08-24 20:37:58 -04:00
parent ae3510abd5
commit 03faa7257f
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
2 changed files with 30 additions and 25 deletions

View File

@ -112,9 +112,6 @@ pub enum ContextElement<'r, 's> {
ExitMatcherNode(ExitMatcherNode<'r>), ExitMatcherNode(ExitMatcherNode<'r>),
Context(&'r str), Context(&'r str),
/// Stores the indentation level of the current list item.
ListItem(usize),
/// Stores the name of the greater block. /// Stores the name of the greater block.
GreaterBlock(&'s str), GreaterBlock(&'s str),

View File

@ -135,12 +135,12 @@ pub fn plain_list_item<'r, 's>(
}; };
let (remaining, _ws) = space1(remaining)?; let (remaining, _ws) = space1(remaining)?;
let exit_matcher = plain_list_item_end(indent_level);
let parser_context = context let parser_context = context
.with_additional_node(ContextElement::ConsumeTrailingWhitespace(true)) .with_additional_node(ContextElement::ConsumeTrailingWhitespace(true))
.with_additional_node(ContextElement::ListItem(indent_level))
.with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode { .with_additional_node(ContextElement::ExitMatcherNode(ExitMatcherNode {
class: ExitClass::Beta, class: ExitClass::Beta,
exit_matcher: &plain_list_item_end, exit_matcher: &exit_matcher,
})); }));
let (remaining, (children, _exit_contents)) = verify( let (remaining, (children, _exit_contents)) = verify(
@ -194,47 +194,55 @@ fn plain_list_end<'r, 's>(
)))(input) )))(input)
} }
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] const fn plain_list_item_end(
fn plain_list_item_end<'r, 's>( indent_level: usize,
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
let line_indented_lte_matcher = line_indented_lte(indent_level);
move |context: Context, input: OrgSource<'_>| {
_plain_list_item_end(context, input, &line_indented_lte_matcher)
}
}
#[cfg_attr(
feature = "tracing",
tracing::instrument(ret, level = "debug", skip(line_indented_lte_matcher))
)]
fn _plain_list_item_end<'r, 's>(
context: Context<'r, 's>, context: Context<'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
line_indented_lte_matcher: impl for<'rr, 'ss> Fn(
Context<'rr, 'ss>,
OrgSource<'ss>,
) -> Res<OrgSource<'ss>, OrgSource<'ss>>,
) -> Res<OrgSource<'s>, OrgSource<'s>> { ) -> Res<OrgSource<'s>, OrgSource<'s>> {
start_of_line(input)?; start_of_line(input)?;
recognize(tuple(( recognize(tuple((
opt(blank_line), opt(blank_line),
parser_with_context!(line_indented_lte)(context), parser_with_context!(line_indented_lte_matcher)(context),
)))(input) )))(input)
} }
const fn line_indented_lte(
indent_level: usize,
) -> impl for<'r, 's> Fn(Context<'r, 's>, OrgSource<'s>) -> Res<OrgSource<'s>, OrgSource<'s>> {
move |context: Context, input: OrgSource<'_>| _line_indented_lte(context, input, indent_level)
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
fn line_indented_lte<'r, 's>( fn _line_indented_lte<'r, 's>(
context: Context<'r, 's>, context: Context<'r, 's>,
input: OrgSource<'s>, input: OrgSource<'s>,
indent_level: usize,
) -> Res<OrgSource<'s>, OrgSource<'s>> { ) -> Res<OrgSource<'s>, OrgSource<'s>> {
let current_item_indent_level: &usize =
get_context_item_indent(context).ok_or(nom::Err::Error(CustomError::MyError(MyError(
"Not inside a plain list item".into(),
))))?;
let matched = recognize(verify( let matched = recognize(verify(
tuple((space0::<OrgSource<'_>, _>, non_whitespace_character)), tuple((space0::<OrgSource<'_>, _>, non_whitespace_character)),
// It is fine that we get the indent level using the number of bytes rather than the number of characters because nom's space0 only matches space and tab (0x20 and 0x09) // It is fine that we get the indent level using the number of bytes rather than the number of characters because nom's space0 only matches space and tab (0x20 and 0x09)
|(_space0, _anychar)| _space0.len() <= *current_item_indent_level, |(_space0, _anychar)| _space0.len() <= indent_level,
))(input)?; ))(input)?;
Ok(matched) Ok(matched)
} }
fn get_context_item_indent<'r, 's>(context: Context<'r, 's>) -> Option<&'r usize> {
for thing in context.iter() {
match thing.get_data() {
ContextElement::ListItem(depth) => return Some(depth),
_ => {}
};
}
None
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;