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}; 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 // Used to disable calling `check_constraints` on a `StringSchema` if it is being deserialized
// for a `PropertyString`, which performs its own checking. // for a `PropertyString`, which performs its own checking.
thread_local! { 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() { while *at != input.len() {
let begin = *at; 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; 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) { 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 let Some(max) = self.schema.max_length {
if self.count == max { if self.count == max {
return Err(Error::msg("too many elements")); return Err(Error::msg("too many elements"));

View File

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