schema: implement split_list iterator

and reuse splitting code in no_schema's SeqAccess as well

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Reviewed-by: Lukas Wagner <l.wagner@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2023-04-04 16:00:59 +02:00
parent ae7454b05e
commit 5df9da2af4
2 changed files with 37 additions and 41 deletions

View File

@ -19,6 +19,8 @@ pub use extract::ExtractValueDeserializer;
use cow3::{str_slice_to_range, Cow3};
pub use no_schema::{split_list, SplitList};
// Used to disable calling `check_constraints` on a `StringSchema` if it is being deserialized
// for a `PropertyString`, which performs its own checking.
thread_local! {
@ -350,7 +352,7 @@ impl<'de, 'i> de::Deserializer<'de> for SchemaDeserializer<'de, 'i> {
}
}
fn next_str_entry(input: &str, at: &mut usize, has_null: bool) -> Option<Range<usize>> {
pub(crate) fn next_str_entry(input: &str, at: &mut usize, has_null: bool) -> Option<Range<usize>> {
while *at != input.len() {
let begin = *at;
@ -373,7 +375,7 @@ fn next_str_entry(input: &str, at: &mut usize, has_null: bool) -> Option<Range<u
}
};
if input[..end].is_empty() {
if begin == end || input[..end].is_empty() {
continue;
}
@ -420,10 +422,6 @@ impl<'de, 'i, 's> de::SeqAccess<'de> for SeqAccess<'de, 'i, 's> {
}
while let Some(el_range) = next_str_entry(&self.input, &mut self.at, self.has_null) {
if el_range.is_empty() {
continue;
}
if let Some(max) = self.schema.max_length {
if self.count == max {
return Err(Error::msg("too many elements"));

View File

@ -271,41 +271,39 @@ impl<'de, 'i> de::SeqAccess<'de> for SimpleSeqAccess<'de, 'i> {
where
T: de::DeserializeSeed<'de>,
{
while self.at != self.input.len() {
let begin = self.at;
let range = match super::next_str_entry(&self.input, &mut self.at, self.has_null) {
None => return Ok(None),
Some(range) => range,
};
let input = &self.input[self.at..];
let end = if self.has_null {
input.find('\0')
} else {
input.find(|c: char| c == ',' || c == ';' || char::is_ascii_whitespace(&c))
};
let end = match end {
None => {
self.at = self.input.len();
input.len()
}
Some(pos) => {
self.at += pos + 1;
pos
}
};
if input[..end].is_empty() {
continue;
}
return seed
.deserialize(NoSchemaDeserializer::new(match &self.input {
Cow3::Original(input) => Cow::Borrowed(&input[begin..end]),
Cow3::Intermediate(input) => Cow::Owned(input[begin..end].to_string()),
Cow3::Owned(input) => Cow::Owned(input[begin..end].to_string()),
}))
.map(Some);
}
Ok(None)
seed.deserialize(NoSchemaDeserializer::new(match &self.input {
Cow3::Original(input) => Cow::Borrowed(&input[range]),
Cow3::Intermediate(input) => Cow::Owned(input[range].to_string()),
Cow3::Owned(input) => Cow::Owned(input[range].to_string()),
}))
.map(Some)
}
}
pub fn split_list(input: &str) -> SplitList<'_> {
SplitList {
has_null: input.contains('\0'),
input,
at: 0,
}
}
pub struct SplitList<'a> {
input: &'a str,
has_null: bool,
at: usize,
}
impl<'a> Iterator for SplitList<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<&'a str> {
let range = super::next_str_entry(&self.input, &mut self.at, self.has_null)?;
Some(&self.input[range])
}
}