use super::error::ScalarItemError;
use super::options::{
CollectionConversionOptions,
EmptyItemPolicy,
};
use super::scalar_item::ScalarItem;
#[derive(Debug, Clone)]
pub struct ScalarItems<'a> {
value: &'a str,
delimiters: &'a [char],
split_scalar_strings: bool,
trim_items: bool,
empty_item_policy: EmptyItemPolicy,
next_start: Option<usize>,
next_source_index: usize,
}
impl<'a> ScalarItems<'a> {
pub(super) fn new(
options: &'a CollectionConversionOptions,
value: &'a str,
) -> Self {
Self {
value,
delimiters: &options.delimiters,
split_scalar_strings: options.split_scalar_strings,
trim_items: options.trim_items,
empty_item_policy: options.empty_item_policy,
next_start: Some(0),
next_source_index: 0,
}
}
fn next_raw(&mut self) -> Option<ScalarItem<'a>> {
let start = self.next_start?;
let source_index = self.next_source_index;
self.next_source_index += 1;
if !self.split_scalar_strings {
self.next_start = None;
return Some(ScalarItem {
source_index,
value: self.value,
});
}
let remaining = &self.value[start..];
match remaining
.char_indices()
.find(|(_, character)| self.delimiters.contains(character))
{
Some((relative_end, delimiter)) => {
let end = start + relative_end;
self.next_start = Some(end + delimiter.len_utf8());
Some(ScalarItem {
source_index,
value: &self.value[start..end],
})
}
None => {
self.next_start = None;
Some(ScalarItem {
source_index,
value: remaining,
})
}
}
}
}
impl<'a> Iterator for ScalarItems<'a> {
type Item = Result<ScalarItem<'a>, ScalarItemError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let mut item = self.next_raw()?;
if self.trim_items {
item.value = item.value.trim();
}
if !item.value.is_empty() {
return Some(Ok(item));
}
match self.empty_item_policy {
EmptyItemPolicy::Keep => return Some(Ok(item)),
EmptyItemPolicy::Skip => {}
EmptyItemPolicy::Reject => {
return Some(Err(ScalarItemError {
source_index: item.source_index,
}));
}
}
}
}
}