use crate::de::{DeError, DeEvent, Deserializer, XmlRead};
use crate::encoding::Decoder;
use crate::events::BytesStart;
use serde::de::{DeserializeSeed, SeqAccess};
pub fn not_in(
fields: &'static [&'static str],
start: &BytesStart,
decoder: Decoder,
) -> Result<bool, DeError> {
let tag = decoder.decode(start.name().into_inner())?;
Ok(fields.iter().all(|&field| field != tag.as_ref()))
}
#[derive(Debug)]
pub enum TagFilter<'de> {
Include(BytesStart<'de>), Exclude(&'static [&'static str]),
}
impl<'de> TagFilter<'de> {
pub fn is_suitable(&self, start: &BytesStart, decoder: Decoder) -> Result<bool, DeError> {
match self {
Self::Include(n) => Ok(n.name() == start.name()),
Self::Exclude(fields) => not_in(fields, start, decoder),
}
}
}
pub struct TopLevelSeqAccess<'de, 'a, R>
where
R: XmlRead<'de>,
{
de: &'a mut Deserializer<'de, R>,
filter: TagFilter<'de>,
#[cfg(feature = "overlapped-lists")]
checkpoint: usize,
}
impl<'a, 'de, R> TopLevelSeqAccess<'de, 'a, R>
where
R: XmlRead<'de>,
{
pub fn new(de: &'a mut Deserializer<'de, R>) -> Result<Self, DeError> {
let filter = if let DeEvent::Start(e) = de.peek()? {
TagFilter::Include(e.clone())
} else {
TagFilter::Exclude(&[])
};
Ok(Self {
#[cfg(feature = "overlapped-lists")]
checkpoint: de.skip_checkpoint(),
de,
filter,
})
}
}
#[cfg(feature = "overlapped-lists")]
impl<'de, 'a, R> Drop for TopLevelSeqAccess<'de, 'a, R>
where
R: XmlRead<'de>,
{
fn drop(&mut self) {
self.de.start_replay(self.checkpoint);
}
}
impl<'de, 'a, R> SeqAccess<'de> for TopLevelSeqAccess<'de, 'a, R>
where
R: XmlRead<'de>,
{
type Error = DeError;
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, DeError>
where
T: DeserializeSeed<'de>,
{
let decoder = self.de.reader.decoder();
loop {
break match self.de.peek()? {
#[cfg(feature = "overlapped-lists")]
DeEvent::Start(e) if !self.filter.is_suitable(e, decoder)? => {
self.de.skip()?;
continue;
}
#[cfg(not(feature = "overlapped-lists"))]
DeEvent::Start(e) if !self.filter.is_suitable(e, decoder)? => Ok(None),
DeEvent::End(_) => Ok(None),
DeEvent::Eof => Ok(None),
_ => seed.deserialize(&mut *self.de).map(Some),
};
}
}
}
#[test]
fn test_not_in() {
let tag = BytesStart::new("tag");
assert_eq!(not_in(&[], &tag, Decoder::utf8()).unwrap(), true);
assert_eq!(
not_in(&["no", "such", "tags"], &tag, Decoder::utf8()).unwrap(),
true
);
assert_eq!(
not_in(&["some", "tag", "included"], &tag, Decoder::utf8()).unwrap(),
false
);
}