use super::*;
use crate::advanced::AcceptsRegexOverride;
#[derive(Clone, Copy)]
pub struct SeqMatch<'t, 'input> {
pub(crate) children: &'t [Option<MatchTreeTemplate>],
pub(crate) captures: &'t Captures,
pub(crate) input: &'input str,
pub(crate) full_text: &'input str,
pub(crate) context: ContextChain<'t>,
}
impl<'t, 'input> SeqMatch<'t, 'input> {
pub fn text(&self) -> &'input str {
self.full_text
}
pub fn num_children(&self) -> usize {
self.children.len()
}
#[track_caller]
pub fn parse_at<T: FromScanf<'input>>(
&self,
index: usize,
options: &FormatOptions,
) -> Option<T> {
let context = Context::ParseAt(std::any::type_name::<T>(), index);
T::from_match(self.inner_at(index, context), options)
}
#[doc(hidden)] #[track_caller]
pub fn parse_at_from_custom_regex<T: AcceptsRegexOverride<'input>>(
&self,
index: usize,
options: &FormatOptions,
) -> Option<T> {
let context = Context::ParseAt(std::any::type_name::<T>(), index);
AcceptsRegexOverride::from_regex_match(self.inner_at(index, context).text(), options)
}
#[track_caller]
pub fn parse_field<T: FromScanf<'input>>(
&self,
name: &'static str,
index: usize,
options: &FormatOptions,
) -> Option<T> {
let context = Context::ParseField(name, index, std::any::type_name::<T>());
T::from_match(self.inner_at(index, context), options)
}
#[doc(hidden)] #[track_caller]
pub fn parse_field_from_custom_regex<T: AcceptsRegexOverride<'input>>(
&self,
name: &'static str,
index: usize,
options: &FormatOptions,
) -> Option<T> {
let context = Context::ParseField(name, index, std::any::type_name::<T>());
AcceptsRegexOverride::from_regex_match(self.inner_at(index, context).text(), options)
}
#[track_caller]
pub fn at(&'t self, index: usize) -> Match<'t, 'input> {
self.inner_at(index, Context::At(index))
}
#[track_caller]
fn inner_at(&'t self, index: usize, context: Context) -> Match<'t, 'input> {
let context = self.context.and(context);
let Some(child) = self.children.get(index) else {
panic!(
"sscanf: index {index} is out of bounds of a SeqMatch with {} children.\nContext: {context}",
self.children.len(),
);
};
let Some(child) = child.as_ref() else {
panic!("sscanf: sub-match at index {index} was not a Matcher.\nContext: {context}");
};
let Some(span) = self.captures.get_group(child.index) else {
panic!(
"sscanf: sub-match at index {index} is None. Are there any unescaped `?` or `|` in a regex?\nContext: {context}"
);
};
Match::new(child, self.captures, self.input, span, context)
}
#[track_caller]
pub fn get(&'t self, index: usize) -> Option<Match<'t, 'input>> {
let child = self.children.get(index)?.as_ref()?;
let context = self.context.and(Context::Get(index));
let Some(span) = self.captures.get_group(child.index) else {
panic!(
"sscanf: sub-match at index {index} is None. Are there any unescaped `?` or `|` in a regex?\nContext: {context}"
);
};
Some(Match::new(child, self.captures, self.input, span, context))
}
}
impl std::fmt::Debug for SeqMatch<'_, '_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let children = self
.children
.iter()
.map(|match_tree| {
let match_tree = match_tree.as_ref()?;
let span = self.captures.get_group(match_tree.index).unwrap();
Some(Match::new(
match_tree,
self.captures,
self.input,
span,
self.context.and(Context::At(match_tree.index)),
))
})
.collect::<Vec<_>>();
f.debug_struct("Match::Seq")
.field("full_text", &self.text())
.field("children", &children.as_slice())
.finish_non_exhaustive()
}
}