mod split_behavior;
pub use split_behavior::SplitFlags;
#[ cfg( feature = "simd" ) ]
mod simd;
#[ cfg( feature = "simd" ) ]
pub use simd::{ SIMDSplitIterator, simd_split_cached, get_or_create_cached_patterns };
mod private {
#[ cfg( feature = "std" ) ]
use std::{ borrow::Cow, vec, vec::Vec, string::{ String, ToString } };
#[ cfg( all( feature = "use_alloc", not( feature = "std" ) ) ) ]
use alloc::{ borrow::Cow, vec, vec::Vec, string::{ String, ToString } };
#[ cfg( all( feature = "string_parse_request", feature = "std" ) ) ]
use crate::string::parse_request::OpType;
use super::SplitFlags;
#[ allow( clippy::elidable_lifetime_names ) ] fn unescape_str< 'a >( input : &'a str ) -> Cow< 'a, str >
{
if !input.contains( '\\' )
{
return Cow::Borrowed( input );
}
let mut output = String::with_capacity( input.len() );
let mut chars = input.chars();
while let Some(ch) = chars.next() {
if ch == '\\' {
if let Some(next_ch) = chars.next() {
match next_ch {
'"' => output.push('"'),
'\\' => output.push('\\'),
'n' => output.push('\n'),
't' => output.push('\t'),
'r' => output.push('\r'),
'\'' => output.push('\''),
_ => {
output.push('\\');
output.push(next_ch);
}
}
} else {
output.push('\\');
}
} else {
output.push(ch);
}
}
Cow::Owned(output)
}
#[ cfg( test ) ]
#[ allow( clippy::elidable_lifetime_names ) ] #[ must_use ] pub fn test_unescape_str< 'a >( input : &'a str ) -> Cow< 'a, str >
{
unescape_str( input )
}
#[ derive( Debug, Clone, PartialEq, Eq ) ]
pub struct Split<'a> {
pub string: Cow<'a, str>,
pub typ: SplitType,
pub start: usize,
pub end: usize,
pub was_quoted: bool,
}
impl<'a> From<Split<'a>> for String {
fn from(src: Split<'a>) -> Self {
src.string.into_owned()
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq ) ]
pub enum SplitType {
Delimited,
Delimiter,
}
pub trait Searcher {
fn pos(&self, src: &str) -> Option< (usize, usize) >;
}
impl Searcher for &str {
fn pos(&self, src: &str) -> Option< (usize, usize) > {
if self.is_empty() {
return None;
}
src.find(self).map(|start| (start, start + self.len()))
}
}
impl Searcher for String {
fn pos(&self, src: &str) -> Option< (usize, usize) > {
if self.is_empty() {
return None;
}
src.find(self).map(|start| (start, start + self.len()))
}
}
impl Searcher for Vec< &str > {
fn pos(&self, src: &str) -> Option< (usize, usize) > {
let mut r = vec![];
for pat in self {
if pat.is_empty() {
continue;
}
if let Some(x) = src.find(pat) {
r.push((x, x + pat.len()));
}
}
if r.is_empty() {
return None;
}
r.sort_by(|a, b| a.0.cmp(&b.0).then_with(|| (a.1 - a.0).cmp(&(b.1 - b.0))));
r.first().copied()
}
}
#[ derive( Debug ) ]
pub struct SplitFastIterator<'a, D>
where
D: Searcher,
{
iterable: &'a str,
current_offset: usize,
counter: i32,
delimeter: D,
}
impl<'a, D: Searcher + Default + Clone> SplitFastIterator<'a, D> {
fn new(o: &impl SplitOptionsAdapter<'a, D>) -> Self {
Self {
iterable: o.src(),
current_offset: 0,
delimeter: o.delimeter(),
counter: 0,
}
}
#[ allow( dead_code ) ]
pub fn set_test_state(
&mut self,
iterable: &'a str,
current_offset: usize,
counter: i32,
) {
self.iterable = iterable;
self.current_offset = current_offset;
self.counter = counter;
}
#[ allow( dead_code ) ]
pub fn get_test_iterable(&self) -> &'a str {
self.iterable
}
#[ allow( dead_code ) ]
pub fn get_test_current_offset(&self) -> usize {
self.current_offset
}
#[ allow( dead_code ) ]
pub fn get_test_counter(&self) -> i32 {
self.counter
}
}
impl<'a, D: Searcher> Iterator for SplitFastIterator<'a, D> {
type Item = Split<'a>;
#[ allow( clippy::too_many_lines ) ]
fn next(&mut self) -> Option< Self::Item > {
if self.iterable.is_empty() && self.counter > 0
{
return None;
}
if self.iterable.is_empty() && self.counter > 0 {
return None;
}
self.counter += 1;
if self.counter % 2 == 1 {
if let Some((d_start, _d_end)) = self.delimeter.pos(self.iterable) {
if d_start == 0 {
return Some(Split {
string: Cow::Borrowed(""),
typ: SplitType::Delimited,
start: self.current_offset,
end: self.current_offset,
was_quoted: false,
});
}
let segment_str = &self.iterable[..d_start];
let split = Split {
string: Cow::Borrowed(segment_str),
typ: SplitType::Delimited,
start: self.current_offset,
end: self.current_offset + segment_str.len(),
was_quoted: false,
};
self.current_offset += segment_str.len();
self.iterable = &self.iterable[d_start..];
Some(split)
} else {
if self.iterable.is_empty() && self.counter > 1 {
return None;
}
let segment_str = self.iterable;
let split = Split {
string: Cow::Borrowed(segment_str),
typ: SplitType::Delimited,
start: self.current_offset,
end: self.current_offset + segment_str.len(),
was_quoted: false,
};
self.current_offset += segment_str.len();
self.iterable = "";
Some(split)
}
} else if let Some((d_start, d_end)) = self.delimeter.pos(self.iterable) {
if d_start > 0 {
self.iterable = "";
return None;
}
let delimiter_str = &self.iterable[..d_end];
let split = Split {
string: Cow::Borrowed(delimiter_str),
typ: SplitType::Delimiter,
start: self.current_offset,
end: self.current_offset + delimiter_str.len(),
was_quoted: false,
};
self.current_offset += delimiter_str.len();
self.iterable = &self.iterable[d_end..];
Some(split)
} else {
None
}
}
}
#[ allow( clippy::struct_excessive_bools ) ]
#[ derive( Debug ) ]
pub struct SplitIterator<'a> {
iterator: SplitFastIterator<'a, Vec< &'a str >>,
src: &'a str,
flags: SplitFlags,
quoting_prefixes: Vec< &'a str >,
quoting_postfixes: Vec< &'a str >,
pending_opening_quote_delimiter: Option<Split<'a>>,
last_yielded_token_was_delimiter: bool,
just_finished_peeked_quote_end_offset: Option< usize >,
skip_next_spurious_empty: bool,
active_quote_char: Option< char >, just_processed_quote: bool,
}
impl<'a> SplitIterator<'a> {
fn new(o: &impl SplitOptionsAdapter<'a, Vec< &'a str >>) -> Self {
let mut delimeter_list_for_fast_iterator = o.delimeter();
delimeter_list_for_fast_iterator.retain(|&pat| !pat.is_empty());
let iterator = SplitFastIterator::new(&o.clone_options_for_sfi());
let flags = o.flags();
Self {
iterator,
src: o.src(),
flags,
quoting_prefixes: o.quoting_prefixes().clone(),
quoting_postfixes: o.quoting_postfixes().clone(),
pending_opening_quote_delimiter: None,
last_yielded_token_was_delimiter: false,
just_finished_peeked_quote_end_offset: None,
skip_next_spurious_empty: false,
active_quote_char: None, just_processed_quote: false,
}
}
}
impl<'a> Iterator for SplitIterator<'a> {
type Item = Split<'a>;
#[ allow( clippy::too_many_lines ) ]
fn next(&mut self) -> Option< Self::Item > {
loop {
if let Some(offset) = self.just_finished_peeked_quote_end_offset.take() {
if self.iterator.current_offset != offset {
if offset > self.iterator.current_offset {
self.iterator.iterable = &self.iterator.iterable[offset - self.iterator.current_offset..];
} else {
let src_len = self.src.len();
if offset < src_len {
self.iterator.iterable = &self.src[offset..];
}
}
self.iterator.current_offset = offset;
}
}
if let Some(pending_split) = self.pending_opening_quote_delimiter.take() {
if pending_split.typ != SplitType::Delimiter || self.flags.contains( SplitFlags::PRESERVING_DELIMITERS )
{
if self.flags.contains( SplitFlags::QUOTING ) && self.quoting_prefixes.contains( &pending_split.string.as_ref() )
{
}
self.last_yielded_token_was_delimiter = pending_split.typ == SplitType::Delimiter;
return Some(pending_split);
}
if self.flags.contains(SplitFlags::QUOTING) && self.quoting_prefixes.contains(&pending_split.string.as_ref()) {
}
}
let about_to_process_quote = self.flags.contains(SplitFlags::QUOTING)
&& self.active_quote_char.is_none()
&& self.quoting_prefixes.iter().any(|p| self.iterator.iterable.starts_with(p));
let last_was_quoted_content = self.just_processed_quote;
let has_consecutive_delimiters = self
.iterator
.delimeter
.pos(self.iterator.iterable)
.is_some_and(|(ds, _)| ds == 0);
let preserving_empty_check = self.last_yielded_token_was_delimiter
&& self.flags.contains(SplitFlags::PRESERVING_EMPTY)
&& !last_was_quoted_content
&& (has_consecutive_delimiters
|| (about_to_process_quote
&& !self.iterator.iterable.starts_with("\"\"")
&& !self.iterator.iterable.starts_with("''")
&& !self.iterator.iterable.starts_with("``")));
if preserving_empty_check {
let current_sfi_offset = self.iterator.current_offset;
let empty_token = Split {
string: Cow::Borrowed(""),
typ: SplitType::Delimited,
start: current_sfi_offset,
end: current_sfi_offset,
was_quoted: false,
};
self.last_yielded_token_was_delimiter = false;
self.iterator.counter += 1;
return Some(empty_token);
}
self.last_yielded_token_was_delimiter = false;
let sfi_next_internal_counter_will_be_odd = self.iterator.counter % 2 == 0;
let sfi_iterable_starts_with_delimiter = self
.iterator
.delimeter
.pos(self.iterator.iterable)
.is_some_and(|(d_start, _)| d_start == 0);
let sfi_should_yield_empty_now = self.flags.contains(SplitFlags::PRESERVING_EMPTY)
&& sfi_next_internal_counter_will_be_odd
&& sfi_iterable_starts_with_delimiter;
let effective_split_opt: Option<Split<'a>>;
let mut quote_handled_by_peek = false;
if self.flags.contains(SplitFlags::QUOTING) && self.active_quote_char.is_none() && !sfi_should_yield_empty_now {
if let Some(first_char_iterable) = self.iterator.iterable.chars().next() {
if let Some(prefix_idx) = self
.quoting_prefixes
.iter()
.position(|p| self.iterator.iterable.starts_with(p))
{
quote_handled_by_peek = true;
let prefix_str = self.quoting_prefixes[prefix_idx];
let opening_quote_original_start = self.iterator.current_offset;
let prefix_len = prefix_str.len();
let expected_postfix = self.quoting_postfixes[prefix_idx];
self.iterator.current_offset += prefix_len;
self.iterator.iterable = &self.iterator.iterable[prefix_len..];
self.active_quote_char = Some(first_char_iterable);
let mut end_of_quote_idx: Option< usize > = None;
let mut chars = self.iterator.iterable.chars();
let mut current_char_offset = 0;
let mut escaped = false;
while let Some(c) = chars.next() {
if escaped {
escaped = false;
current_char_offset += c.len_utf8();
} else if c == '\\' {
escaped = true;
current_char_offset += c.len_utf8();
} else if c == first_char_iterable
{
let remaining_chars = chars.as_str();
if !remaining_chars.is_empty() {
let next_char = remaining_chars.chars().next().unwrap();
if next_char.is_alphanumeric() && current_char_offset > 0 {
let content_so_far = &self.iterator.iterable[..current_char_offset];
if let Some(last_char) = content_so_far.chars().last() {
if !last_char.is_whitespace() {
end_of_quote_idx = Some(current_char_offset);
break;
}
}
}
}
end_of_quote_idx = Some(current_char_offset);
break;
} else {
current_char_offset += c.len_utf8();
}
}
let (quoted_content_str, consumed_len_in_sfi_iterable) = if let Some(end_idx) = end_of_quote_idx {
let content = &self.iterator.iterable[..end_idx];
let remaining_chars = &self.iterator.iterable[end_idx..];
let is_adjacent = if remaining_chars.len() > 1 {
let chars_after_quote: Vec< char > = remaining_chars.chars().take(2).collect();
if chars_after_quote.len() >= 2 {
chars_after_quote[0] == '"' && chars_after_quote[1].is_alphanumeric()
} else {
false
}
} else {
false
};
let consumed = if is_adjacent {
end_idx } else {
end_idx + expected_postfix.len() };
(content, consumed)
} else {
(self.iterator.iterable, self.iterator.iterable.len())
};
if quoted_content_str.is_empty() && end_of_quote_idx.is_some() {
self.last_yielded_token_was_delimiter = false;
}
self.iterator.current_offset += consumed_len_in_sfi_iterable;
self.iterator.iterable = &self.iterator.iterable[consumed_len_in_sfi_iterable..];
self.active_quote_char = None;
if self.flags.contains(SplitFlags::PRESERVING_QUOTING) {
let full_quoted_len = prefix_len
+ quoted_content_str.len()
+ if end_of_quote_idx.is_some() {
expected_postfix.len()
} else {
0
};
let new_string = if opening_quote_original_start + full_quoted_len <= self.src.len() {
Cow::Borrowed(&self.src[opening_quote_original_start..(opening_quote_original_start + full_quoted_len)])
} else {
Cow::Borrowed("")
};
let new_end = opening_quote_original_start + new_string.len();
effective_split_opt = Some(Split {
string: new_string,
typ: SplitType::Delimited,
start: opening_quote_original_start,
end: new_end,
was_quoted: true,
});
} else {
let unescaped_string: Cow<'a, str> = unescape_str(quoted_content_str).into_owned().into();
let new_start = opening_quote_original_start + prefix_len;
let new_end = new_start + unescaped_string.len();
effective_split_opt = Some(Split {
string: unescaped_string,
typ: SplitType::Delimited,
start: new_start,
end: new_end,
was_quoted: true,
});
}
if effective_split_opt.is_some() {
self.last_yielded_token_was_delimiter = false;
self.just_processed_quote = true;
}
} else {
effective_split_opt = self.iterator.next();
}
} else {
effective_split_opt = self.iterator.next();
}
} else {
effective_split_opt = self.iterator.next();
}
let mut current_split = effective_split_opt?;
if quote_handled_by_peek {
self.skip_next_spurious_empty = true;
}
if self.skip_next_spurious_empty && current_split.typ == SplitType::Delimited && current_split.string.is_empty() {
self.skip_next_spurious_empty = false;
continue;
}
if !quote_handled_by_peek
&& self.flags.contains(SplitFlags::QUOTING)
&& current_split.typ == SplitType::Delimiter
&& self.active_quote_char.is_none()
{
if let Some(_prefix_idx) = self.quoting_prefixes.iter().position(|p| *p == current_split.string.as_ref()) {
let opening_quote_delimiter = current_split.clone();
if self.flags.contains(SplitFlags::PRESERVING_DELIMITERS) {
self.pending_opening_quote_delimiter = Some(opening_quote_delimiter.clone());
}
if let Some(fcoq) = opening_quote_delimiter.string.chars().next() {
self.active_quote_char = Some(fcoq);
}
if !self.flags.contains(SplitFlags::PRESERVING_DELIMITERS) {
continue;
}
}
}
if self.flags.contains(SplitFlags::STRIPPING) && current_split.typ == SplitType::Delimited {
let original_len = current_split.string.len();
let trimmed_string = current_split.string.trim();
if trimmed_string.len() < original_len {
let leading_whitespace_len = trimmed_string.as_ptr() as usize - current_split.string.as_ptr() as usize;
current_split.start += leading_whitespace_len;
current_split.string = Cow::Owned(trimmed_string.to_string());
current_split.end = current_split.start + current_split.string.len();
}
}
let skip = (current_split.typ == SplitType::Delimited
&& current_split.string.is_empty()
&& !self.flags.contains(SplitFlags::PRESERVING_EMPTY))
|| (current_split.typ == SplitType::Delimiter && !self.flags.contains(SplitFlags::PRESERVING_DELIMITERS));
if current_split.typ == SplitType::Delimiter {
if !self.just_processed_quote {
self.last_yielded_token_was_delimiter = true;
}
}
if skip {
continue;
}
self.just_processed_quote = false;
return Some(current_split);
}
}
}
#[ derive( Debug, Clone ) ]
pub struct SplitOptions<'a, D>
where
D: Searcher + Default + Clone,
{
src: &'a str,
delimeter: D,
flags: SplitFlags,
quoting_prefixes: Vec< &'a str >,
quoting_postfixes: Vec< &'a str >,
}
impl<'a> SplitOptions<'a, Vec< &'a str >> {
#[ must_use ]
pub fn split(self) -> SplitIterator<'a> {
SplitIterator::new(&self)
}
}
impl<'a, D: Searcher + Default + Clone> SplitOptions<'a, D> {
#[ allow( dead_code ) ]
pub fn split_fast(self) -> SplitFastIterator<'a, D> {
SplitFastIterator::new(&self)
}
}
impl<'a> core::iter::IntoIterator for SplitOptions<'a, Vec< &'a str >> {
type Item = Split<'a>;
type IntoIter = SplitIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
SplitIterator::new(&self)
}
}
pub trait SplitOptionsAdapter<'a, D>
where
D: Searcher + Default + Clone,
{
fn src(&self) -> &'a str;
fn delimeter(&self) -> D;
fn flags(&self) -> SplitFlags;
fn quoting_prefixes(&self) -> &Vec< &'a str >;
fn quoting_postfixes(&self) -> &Vec< &'a str >;
fn clone_options_for_sfi(&self) -> SplitOptions<'a, D>;
}
impl<'a, D: Searcher + Clone + Default> SplitOptionsAdapter<'a, D> for SplitOptions<'a, D> {
fn src(&self) -> &'a str {
self.src
}
fn delimeter(&self) -> D {
self.delimeter.clone()
}
fn flags(&self) -> SplitFlags {
self.flags
}
fn quoting_prefixes(&self) -> &Vec< &'a str > {
&self.quoting_prefixes
}
fn quoting_postfixes(&self) -> &Vec< &'a str > {
&self.quoting_postfixes
}
fn clone_options_for_sfi(&self) -> SplitOptions<'a, D> {
self.clone()
}
}
#[ derive( Debug ) ]
pub struct BasicSplitBuilder<'a> {
src: &'a str,
delimiters: Vec<&'a str>,
flags: SplitFlags,
quoting_prefixes: Vec<&'a str>,
quoting_postfixes: Vec<&'a str>,
}
impl<'a> Default for BasicSplitBuilder<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> BasicSplitBuilder<'a> {
#[ must_use ]
pub fn new() -> BasicSplitBuilder<'a> {
Self {
src: "",
delimiters: vec![],
flags: SplitFlags::PRESERVING_DELIMITERS, quoting_prefixes: vec![],
quoting_postfixes: vec![],
}
}
pub fn src(&mut self, value: &'a str) -> &mut Self {
self.src = value;
self
}
pub fn delimeter(&mut self, value: &'a str) -> &mut Self {
self.delimiters = vec![value];
self
}
pub fn delimeters(&mut self, value: &[&'a str]) -> &mut Self {
self.delimiters = value.to_vec();
self
}
pub fn quoting(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::QUOTING);
if self.quoting_prefixes.is_empty() {
self.quoting_prefixes = vec!["\"", "'"];
}
if self.quoting_postfixes.is_empty() {
self.quoting_postfixes = vec!["\"", "'"];
}
} else {
self.flags.remove(SplitFlags::QUOTING);
}
self
}
pub fn stripping(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::STRIPPING);
} else {
self.flags.remove(SplitFlags::STRIPPING);
}
self
}
pub fn preserving_empty(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::PRESERVING_EMPTY);
} else {
self.flags.remove(SplitFlags::PRESERVING_EMPTY);
}
self
}
pub fn preserving_delimeters(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::PRESERVING_DELIMITERS);
} else {
self.flags.remove(SplitFlags::PRESERVING_DELIMITERS);
}
self
}
pub fn preserving_quoting(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::PRESERVING_QUOTING);
} else {
self.flags.remove(SplitFlags::PRESERVING_QUOTING);
}
self
}
pub fn quoting_prefixes(&mut self, value: &[&'a str]) -> &mut Self {
self.quoting_prefixes = value.to_vec();
self
}
pub fn quoting_postfixes(&mut self, value: &[&'a str]) -> &mut Self {
self.quoting_postfixes = value.to_vec();
self
}
pub fn perform(&mut self) -> SplitIterator<'a> {
let options = SplitOptions {
src: self.src,
delimeter: self.delimiters.clone(),
flags: self.flags,
quoting_prefixes: self.quoting_prefixes.clone(),
quoting_postfixes: self.quoting_postfixes.clone(),
};
options.split()
}
#[ cfg( feature = "simd" ) ]
pub fn perform_simd(&mut self) -> SplitIterator<'a> {
self.perform()
}
#[ cfg( not( feature = "simd" ) ) ]
pub fn perform_simd(&mut self) -> SplitIterator<'a> {
self.perform()
}
}
#[ cfg( all( feature = "string_parse_request", feature = "std" ) ) ]
#[ derive( Debug ) ]
pub struct SplitOptionsFormer<'a> {
src: &'a str,
delimeter: OpType<&'a str>,
flags: SplitFlags,
quoting_prefixes: Vec< &'a str >,
quoting_postfixes: Vec< &'a str >,
}
#[ cfg( all( feature = "string_parse_request", feature = "std" ) ) ]
impl<'a> SplitOptionsFormer<'a> {
pub fn new<D: Into<OpType<&'a str>>>(delimeter: D) -> SplitOptionsFormer<'a> {
Self {
src: "",
delimeter: OpType::Vector(vec![]).append(delimeter.into()),
flags: SplitFlags::PRESERVING_DELIMITERS, quoting_prefixes: vec![],
quoting_postfixes: vec![],
}
}
pub fn preserving_empty(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::PRESERVING_EMPTY);
} else {
self.flags.remove(SplitFlags::PRESERVING_EMPTY);
}
self
}
pub fn preserving_delimeters(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::PRESERVING_DELIMITERS);
} else {
self.flags.remove(SplitFlags::PRESERVING_DELIMITERS);
}
self
}
pub fn preserving_quoting(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::PRESERVING_QUOTING);
} else {
self.flags.remove(SplitFlags::PRESERVING_QUOTING);
}
self
}
pub fn stripping(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::STRIPPING);
} else {
self.flags.remove(SplitFlags::STRIPPING);
}
self
}
pub fn quoting(&mut self, value: bool) -> &mut Self {
if value {
self.flags.insert(SplitFlags::QUOTING);
} else {
self.flags.remove(SplitFlags::QUOTING);
}
self
}
pub fn quoting_prefixes(&mut self, value: Vec< &'a str >) -> &mut Self {
self.quoting_prefixes = value;
self
}
pub fn quoting_postfixes(&mut self, value: Vec< &'a str >) -> &mut Self {
self.quoting_postfixes = value;
self
}
pub fn src(&mut self, value: &'a str) -> &mut Self {
self.src = value;
self
}
pub fn delimeter<D: Into<OpType<&'a str>>>(&mut self, value: D) -> &mut Self {
self.delimeter = OpType::Vector(vec![]).append(value.into());
self
}
pub fn form(&mut self) -> SplitOptions<'a, Vec< &'a str >> {
if self.flags.contains(SplitFlags::QUOTING) {
if self.quoting_prefixes.is_empty() {
self.quoting_prefixes = vec!["\"", "`", "'"];
}
if self.quoting_postfixes.is_empty() {
self.quoting_postfixes = vec!["\"", "`", "'"];
}
}
SplitOptions {
src: self.src,
delimeter: self.delimeter.clone().vector().unwrap(),
flags: self.flags,
quoting_prefixes: self.quoting_prefixes.clone(),
quoting_postfixes: self.quoting_postfixes.clone(),
}
}
pub fn perform(&mut self) -> SplitIterator<'a> {
self.form().split()
}
#[ cfg( feature = "simd" ) ]
pub fn perform_simd(&mut self) -> SplitIterator<'a> {
if let OpType::Vector(ref delims) = self.delimeter {
if delims.len() > 1 {
if let Ok(_simd_iter) = super::simd_split_cached(self.src, delims) {
return self.perform(); }
}
}
self.perform()
}
#[ cfg( not( feature = "simd" ) ) ]
pub fn perform_simd(&mut self) -> SplitIterator<'a> {
self.perform()
}
}
#[ must_use ]
pub fn split<'a>() -> BasicSplitBuilder<'a> {
BasicSplitBuilder::new()
}
#[ cfg( all( feature = "string_parse_request", feature = "std" ) ) ]
#[ must_use ]
pub fn split_advanced<'a>() -> SplitOptionsFormer<'a> {
SplitOptionsFormer::new(<&str>::default())
}
}
#[ doc( inline ) ]
#[ allow( unused_imports ) ]
pub use own::*;
#[ allow( unused_imports ) ]
pub mod own {
#[ allow( unused_imports ) ]
use super::*;
pub use orphan::*;
pub use private::{ Split, SplitType, SplitIterator, Searcher, BasicSplitBuilder, split };
#[ cfg( all( feature = "string_parse_request", feature = "std" ) ) ]
pub use private::{ split_advanced, SplitOptionsFormer };
#[ cfg( feature = "simd" ) ]
pub use super::{ SIMDSplitIterator, simd_split_cached, get_or_create_cached_patterns };
#[ cfg( test ) ]
pub use private::{ SplitFastIterator, test_unescape_str };
}
#[ allow( unused_imports ) ]
pub mod orphan {
#[ allow( unused_imports ) ]
use super::*;
pub use exposed::*;
}
#[ allow( unused_imports ) ]
pub mod exposed {
#[ allow( unused_imports ) ]
use super::*;
pub use prelude::*;
pub use super::own::{ Split, SplitType, SplitIterator, Searcher, BasicSplitBuilder, split };
#[ cfg( all( feature = "string_parse_request", feature = "std" ) ) ]
pub use super::own::{ split_advanced, SplitOptionsFormer };
#[ cfg( feature = "simd" ) ]
pub use super::own::{ SIMDSplitIterator, simd_split_cached, get_or_create_cached_patterns };
#[ cfg( test ) ]
pub use super::own::{ SplitFastIterator, test_unescape_str };
}
#[ allow( unused_imports ) ]
pub mod prelude {
#[ allow( unused_imports ) ]
use super::*;
pub use private::{ Searcher, BasicSplitBuilder, split };
#[ cfg( all( feature = "string_parse_request", feature = "std" ) ) ]
pub use private::{ SplitOptionsFormer, split_advanced };
#[ cfg( test ) ]
pub use private::{ SplitFastIterator, test_unescape_str as unescape_str };
}