From 5df9da2af4a304f45b34ddaaa36757f5c28625c8 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 4 Apr 2023 16:00:59 +0200 Subject: [PATCH] schema: implement split_list iterator and reuse splitting code in no_schema's SeqAccess as well Signed-off-by: Wolfgang Bumiller Reviewed-by: Lukas Wagner --- proxmox-schema/src/de/mod.rs | 10 ++--- proxmox-schema/src/de/no_schema.rs | 68 +++++++++++++++--------------- 2 files changed, 37 insertions(+), 41 deletions(-) diff --git a/proxmox-schema/src/de/mod.rs b/proxmox-schema/src/de/mod.rs index 60b40771..75b500e5 100644 --- a/proxmox-schema/src/de/mod.rs +++ b/proxmox-schema/src/de/mod.rs @@ -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> { +pub(crate) fn next_str_entry(input: &str, at: &mut usize, has_null: bool) -> Option> { while *at != input.len() { let begin = *at; @@ -373,7 +375,7 @@ fn next_str_entry(input: &str, at: &mut usize, has_null: bool) -> Option 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")); diff --git a/proxmox-schema/src/de/no_schema.rs b/proxmox-schema/src/de/no_schema.rs index 254ebd96..546e5001 100644 --- a/proxmox-schema/src/de/no_schema.rs +++ b/proxmox-schema/src/de/no_schema.rs @@ -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]) } }