tamer: obj::xmle::xir: Extract ElemWrap into ir::xir::iter
This generalizes it a bit and provides tests, which was always the intent; the existing code was POC to determine if this could be done without performance degradation (see that commit for more information).main
parent
cde08b125c
commit
bc5e8ebe75
|
@ -216,7 +216,7 @@ impl TryFrom<&str> for LocalPart {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Whitespace(SymbolId);
|
||||
|
||||
impl Deref for Whitespace {
|
||||
|
@ -415,7 +415,7 @@ impl AttrValue {
|
|||
/// such as whether a node is open,
|
||||
/// and so this IR can be processed by a simple state machine
|
||||
/// (see [`writer::WriterState`]).
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Token {
|
||||
/// Opening tag of an element.
|
||||
Open(QName, Span),
|
||||
|
|
|
@ -18,21 +18,54 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! XIR [`Token`] stream iterators.
|
||||
//!
|
||||
//! These iterators are provided for convenience in constructing token
|
||||
//! streams.
|
||||
//!
|
||||
//! - [`elem_wrap`] wraps a token stream iterator as the body of an
|
||||
//! element of the given name.
|
||||
|
||||
use super::Token;
|
||||
use super::{QName, Token};
|
||||
use crate::span::Span;
|
||||
use std::iter::{once, Chain, Once};
|
||||
|
||||
/// Wrap an inner [`Token`] stream iterator in an element.
|
||||
///
|
||||
/// This produces a [`Token::Open`] before the `inner` iterator and a
|
||||
/// [`Token::Close`] after `inner` completes.
|
||||
/// The provided two-[`Span`] is associated,
|
||||
/// respectively,
|
||||
/// with the opening and closing tags.
|
||||
///
|
||||
/// The inner iterator will be in the proper context to produce attributes.
|
||||
#[inline]
|
||||
pub fn elem_wrap<S, I>(name: QName, span: S, inner: I) -> ElemWrapIter<I>
|
||||
where
|
||||
S: Into<(Span, Span)>,
|
||||
I: Iterator<Item = Token>,
|
||||
{
|
||||
let twospan: (Span, Span) = span.into();
|
||||
|
||||
ElemWrapIter::new(
|
||||
Token::Open(name, twospan.0),
|
||||
inner,
|
||||
Token::Close(Some(name), twospan.1),
|
||||
)
|
||||
}
|
||||
|
||||
/// An iterator that wraps a [`Token`] iterator in an element.
|
||||
///
|
||||
/// This introduces an opening and closing token before and after the
|
||||
/// iterator.
|
||||
///
|
||||
/// See [`elem_wrap`] to construct this iterator.
|
||||
pub struct ElemWrapIter<I: Iterator<Item = Token>>(
|
||||
Chain<Chain<Once<Token>, I>, Once<Token>>,
|
||||
);
|
||||
|
||||
impl<I: Iterator<Item = Token>> ElemWrapIter<I> {
|
||||
#[inline]
|
||||
pub fn new(open: Token, inner: I, close: Token) -> Self {
|
||||
fn new(open: Token, inner: I, close: Token) -> Self {
|
||||
Self(once(open).chain(inner).chain(once(close)))
|
||||
}
|
||||
}
|
||||
|
@ -45,3 +78,35 @@ impl<I: Iterator<Item = Token>> Iterator for ElemWrapIter<I> {
|
|||
self.0.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{convert::ExpectInto, ir::xir::Token, span::DUMMY_SPAN};
|
||||
|
||||
#[test]
|
||||
fn elem_wrap_iter() {
|
||||
let inner = vec![
|
||||
Token::Open("foo".unwrap_into(), DUMMY_SPAN),
|
||||
Token::Close(None, DUMMY_SPAN),
|
||||
];
|
||||
|
||||
let elem_name = "element".unwrap_into();
|
||||
let twospan = (
|
||||
DUMMY_SPAN.offset_add(1).unwrap(),
|
||||
DUMMY_SPAN.offset_add(2).unwrap(),
|
||||
);
|
||||
|
||||
let result = elem_wrap(elem_name, twospan, inner.clone().into_iter());
|
||||
|
||||
assert_eq!(
|
||||
result.collect::<Vec<_>>(),
|
||||
vec![
|
||||
Token::Open(elem_name, twospan.0),
|
||||
inner[0].clone(),
|
||||
inner[1].clone(),
|
||||
Token::Close(Some(elem_name), twospan.1),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,10 @@ use crate::{
|
|||
asg::{
|
||||
IdentKind, IdentObject, IdentObjectData, Sections, SectionsIter,
|
||||
},
|
||||
xir::{iter::ElemWrapIter, AttrValue, QName, Text, Token},
|
||||
xir::{
|
||||
iter::{elem_wrap, ElemWrapIter},
|
||||
AttrValue, QName, Text, Token,
|
||||
},
|
||||
},
|
||||
ld::LSPAN,
|
||||
sym::{st::*, SymbolId},
|
||||
|
@ -376,40 +379,36 @@ pub fn lower_iter<'a, T: IdentObjectData>(
|
|||
pkg_name: SymbolId,
|
||||
relroot: SymbolId,
|
||||
) -> LowerIter<'a, T> {
|
||||
LowerIter(ElemWrapIter::new(
|
||||
Token::Open(QN_PACKAGE, LSPAN),
|
||||
LowerIter(elem_wrap(
|
||||
QN_PACKAGE,
|
||||
LSPAN,
|
||||
header(pkg_name, relroot)
|
||||
.chain(ElemWrapIter::new(
|
||||
Token::Open(QN_L_DEP, LSPAN),
|
||||
.chain(elem_wrap(
|
||||
QN_L_DEP,
|
||||
LSPAN,
|
||||
DepListIter::new(sections, relroot),
|
||||
Token::Close(Some(QN_L_DEP), LSPAN),
|
||||
))
|
||||
.chain(ElemWrapIter::new(
|
||||
Token::Open(QN_L_MAP_FROM, LSPAN),
|
||||
MapFromsIter::new(sections),
|
||||
Token::Close(Some(QN_L_MAP_FROM), LSPAN),
|
||||
))
|
||||
.chain(ElemWrapIter::new(
|
||||
Token::Open(QN_L_MAP_EXEC, LSPAN),
|
||||
.chain(elem_wrap(QN_L_MAP_FROM, LSPAN, MapFromsIter::new(sections)))
|
||||
.chain(elem_wrap(
|
||||
QN_L_MAP_EXEC,
|
||||
LSPAN,
|
||||
FragmentIter::new(sections.iter_map()),
|
||||
Token::Close(Some(QN_L_MAP_EXEC), LSPAN),
|
||||
))
|
||||
.chain(ElemWrapIter::new(
|
||||
Token::Open(QN_L_RETMAP_EXEC, LSPAN),
|
||||
.chain(elem_wrap(
|
||||
QN_L_RETMAP_EXEC,
|
||||
LSPAN,
|
||||
FragmentIter::new(sections.iter_retmap()),
|
||||
Token::Close(Some(QN_L_RETMAP_EXEC), LSPAN),
|
||||
))
|
||||
.chain(ElemWrapIter::new(
|
||||
Token::Open(QN_L_STATIC, LSPAN),
|
||||
.chain(elem_wrap(
|
||||
QN_L_STATIC,
|
||||
LSPAN,
|
||||
FragmentIter::new(sections.iter_static()),
|
||||
Token::Close(Some(QN_L_STATIC), LSPAN),
|
||||
))
|
||||
.chain(ElemWrapIter::new(
|
||||
Token::Open(QN_L_EXEC, LSPAN),
|
||||
.chain(elem_wrap(
|
||||
QN_L_EXEC,
|
||||
LSPAN,
|
||||
FragmentIter::new(sections.iter_exec()),
|
||||
Token::Close(Some(QN_L_EXEC), LSPAN),
|
||||
)),
|
||||
Token::Close(Some(QN_PACKAGE), LSPAN),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue