use core::default::Default;
#[ cfg( feature = "std" ) ]
use std::collections::HashMap;
#[ cfg( all( feature = "use_alloc", not( feature = "std" ) ) ) ]
use alloc::collections::BTreeMap as HashMap;
#[ cfg( feature = "std" ) ]
use std::{ vec, vec::Vec, string::String };
#[ cfg( all( feature = "use_alloc", not( feature = "std" ) ) ) ]
use alloc::{ vec, vec::Vec, string::String };
pub mod private {
#[ cfg( all( feature = "string_split", feature = "string_isolate", feature = "std" ) ) ]
use crate::string::split::split;
#[ cfg( all( feature = "string_split", feature = "string_isolate", feature = "std" ) ) ]
use crate::string::{
isolate::isolate_right,
isolate::private::Src,
isolate::private::Delimiter,
};
use super::*;
#[ derive( Debug, Clone, PartialEq, Eq ) ]
pub enum OpType<T> {
Primitive(T),
Vector(Vec< T >),
Map(HashMap<String, T>),
}
impl<T: Default> Default for OpType<T> {
fn default() -> Self {
OpType::Primitive(T::default())
}
}
impl<T> From<T> for OpType<T> {
fn from(value: T) -> Self {
OpType::Primitive(value)
}
}
impl<T> From<Vec< T >> for OpType<T> {
fn from(value: Vec< T >) -> Self {
OpType::Vector(value)
}
}
#[ allow( clippy::from_over_into ) ]
impl<T> Into<Vec< T >> for OpType<T> {
fn into(self) -> Vec< T > {
match self {
OpType::Vector(vec) => vec,
_ => unimplemented!("not implemented"),
}
}
}
impl<T: Clone> OpType<T> {
#[ must_use ]
pub fn append(mut self, item: OpType<T>) -> OpType<T> {
let mut mut_item = item;
match self {
OpType::Primitive(value) => match mut_item {
OpType::Primitive(ins) => {
let vector = vec![value, ins];
OpType::Vector(vector)
}
OpType::Vector(ref mut vector) => {
vector.insert(0, value);
mut_item
}
OpType::Map(_) => panic!("Unexpected operation. Please, use method `insert` to insert item in hash map."),
},
OpType::Vector(ref mut vector) => match mut_item {
OpType::Primitive(ins) => {
vector.push(ins);
self
}
OpType::Vector(ref mut ins_vec) => {
vector.append(ins_vec);
self
}
OpType::Map(_) => panic!("Unexpected operation. Please, use method `insert` to insert item in hash map."),
},
OpType::Map(_) => panic!("Unexpected operation. Please, use method `insert` to insert item in hash map."),
}
}
pub fn primitive(self) -> Option< T > {
match self {
OpType::Primitive(v) => Some(v),
_ => None,
}
}
pub fn vector(self) -> Option<Vec< T >> {
match self {
OpType::Vector(vec) => Some(vec),
_ => None,
}
}
}
#[ allow( dead_code ) ]
#[ derive( Debug, Default, PartialEq, Eq ) ]
pub struct Request<'a> {
pub original: &'a str,
pub key_val_delimeter: &'a str,
pub commands_delimeter: &'a str,
pub subject: String,
pub subjects: Vec< String >,
pub map: HashMap<String, OpType<String>>,
pub maps: Vec<HashMap<String, OpType<String>>>,
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default ) ]
pub struct ParseSrc<'a>(pub &'a str);
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash ) ]
pub struct ParseKeyValDelimeter<'a>(pub &'a str);
impl Default for ParseKeyValDelimeter<'_>
{
fn default() -> Self
{
Self( ": " )
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash ) ]
pub struct ParseCommandsDelimeter<'a>(pub &'a str);
impl Default for ParseCommandsDelimeter<'_>
{
fn default() -> Self
{
Self( ";" )
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash ) ]
pub struct ParseQuoting(pub bool);
impl Default for ParseQuoting
{
fn default() -> Self
{
Self( true )
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash ) ]
pub struct ParseUnquoting(pub bool);
impl Default for ParseUnquoting
{
fn default() -> Self
{
Self( true )
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash ) ]
pub struct ParseParsingArrays(pub bool);
impl Default for ParseParsingArrays
{
fn default() -> Self
{
Self( true )
}
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default ) ]
pub struct ParseSeveralValues(pub bool);
#[ derive( Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default ) ]
pub struct ParseSubjectWinPathsMaybe(pub bool);
#[ allow( clippy::struct_excessive_bools ) ]
#[ derive( Debug, Default ) ] pub struct ParseOptions<'a> {
pub src: ParseSrc<'a>,
pub key_val_delimeter: ParseKeyValDelimeter<'a>,
pub commands_delimeter: ParseCommandsDelimeter<'a>,
pub quoting: ParseQuoting,
pub unquoting: ParseUnquoting,
pub parsing_arrays: ParseParsingArrays,
pub several_values: ParseSeveralValues,
pub subject_win_paths_maybe: ParseSubjectWinPathsMaybe,
}
impl<'a> ParseOptions<'a> {
#[ allow( clippy::assigning_clones, clippy::too_many_lines, clippy::collapsible_if ) ]
#[ cfg( all( feature = "string_split", feature = "string_isolate", feature = "std" ) ) ]
pub fn parse(&mut self) -> Request<'a> {
let mut result = Request {
original: self.src.0, key_val_delimeter: self.key_val_delimeter.0, commands_delimeter: self.commands_delimeter.0, ..Default::default()
};
self.src.0 = self.src.0.trim();
if self.src.0.is_empty()
{
return result;
}
let commands = if self.commands_delimeter.0.trim().is_empty()
{
vec![self.src.0.to_string()] } else {
let iter = split()
.src( self.src.0 ) .delimeter( self.commands_delimeter.0 ) .quoting( self.quoting.0 ) .stripping( true )
.preserving_empty( false )
.preserving_delimeters( false )
.perform();
iter.map(String::from).collect::<Vec< _ >>()
};
for command in commands {
let mut map_entries;
if self.key_val_delimeter.0.trim().is_empty()
{
map_entries = (command.as_str(), None, "");
} else {
map_entries = match command.split_once( self.key_val_delimeter.0 ) {
Some( entries ) => ( entries.0, Some( self.key_val_delimeter.0 ), entries.1 ), None => ( command.as_str(), None, "" ),
};
}
let subject;
let mut map: HashMap<String, OpType<String>> = HashMap::new();
if let Some(map_entry_1) = map_entries.1 {
let mut options = isolate_right();
options.src = Src( map_entries.0 );
options.delimiter = Delimiter( " " );
let subject_and_key = options.isolate();
subject = subject_and_key.0;
map_entries.0 = subject_and_key.2;
let mut join = String::from(map_entries.0);
join.push_str(map_entry_1);
join.push_str(map_entries.2);
let mut splits = split()
.src( join.as_str() )
.delimeter( self.key_val_delimeter.0 ) .stripping( false )
.quoting( self.quoting.0 ) .preserving_empty( true )
.preserving_delimeters( true )
.preserving_quoting( true )
.perform()
.map( String::from ).collect::< Vec< _ > >();
let mut pairs = vec![];
for a in (0..splits.len() - 2).step_by(2) {
let mut right = splits[a + 2].clone();
while a < (splits.len() - 3) {
let mut options = isolate_right();
options.src = Src( &splits[a + 2] );
options.delimiter = Delimiter( " " );
let cuts = options.isolate();
if cuts.1.is_none() {
let mut joined = splits[a + 2].clone();
joined.push_str(splits[a + 3].as_str());
joined.push_str(splits[a + 4].as_str());
splits[a + 2] = joined;
right = splits[a + 2].clone();
splits.remove(a + 3);
splits.remove(a + 4);
continue;
}
let cuts_2_owned = cuts.2.to_string();
let cuts_0_owned = cuts.0.to_string();
splits[a + 2] = cuts_2_owned;
right = cuts_0_owned;
break;
}
let left = splits[a].clone();
let right = right.trim().to_string();
if self.unquoting.0
{
if left.contains('\"') || left.contains('\'') || right.contains('\"') || right.contains('\'') {
unimplemented!("not implemented");
}
}
pairs.push(left);
pairs.push(right);
}
let str_to_vec_maybe = |src: &str| -> Option<Vec< String >> {
if !src.starts_with('[') || !src.ends_with(']') {
return None;
}
let splits = split()
.src( &src[ 1..src.len() - 1 ] )
.delimeter( "," )
.stripping( true )
.quoting( self.quoting.0 ) .preserving_empty( false )
.preserving_delimeters( false )
.preserving_quoting( false )
.perform()
.map( | e | String::from( e ).trim().to_owned() ).collect::< Vec< String > >();
Some(splits)
};
for a in (0..pairs.len() - 1).step_by(2) {
let left = &pairs[a];
let right_str = &pairs[a + 1];
let mut right = OpType::Primitive(pairs[a + 1].clone());
if self.parsing_arrays.0
{
if let Some(vector) = str_to_vec_maybe(right_str) {
right = OpType::Vector(vector);
}
}
if self.several_values.0
{
if let Some(op) = map.get(left) {
let value = op.clone().append(right);
map.insert(left.clone(), value);
} else {
map.insert(left.clone(), right);
}
} else {
map.insert(left.clone(), right);
}
}
} else {
subject = map_entries.0;
}
if self.unquoting.0
{
if subject.contains('\"') || subject.contains('\'') {
unimplemented!("not implemented");
}
}
if self.subject_win_paths_maybe.0
{
unimplemented!("not implemented");
}
result.subjects.push(subject.to_string());
result.maps.push(map);
}
if !result.subjects.is_empty() {
result.subject = result.subjects[0].clone();
}
if !result.maps.is_empty() {
result.map = result.maps[0].clone();
}
result
}
}
#[ must_use ]
#[ cfg( all( feature = "string_split", feature = "string_isolate", feature = "std" ) ) ]
pub fn request_parse<'a>() -> ParseOptions<'a> {
ParseOptions::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::{
OpType,
Request,
ParseOptions,
ParseSrc,
ParseKeyValDelimeter,
ParseCommandsDelimeter,
ParseQuoting,
ParseUnquoting,
ParseParsingArrays,
ParseSeveralValues,
ParseSubjectWinPathsMaybe,
};
#[ cfg( all( feature = "string_split", feature = "string_isolate", feature = "std" ) ) ]
pub use private::request_parse;
}
#[ 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 as parse_request;
#[ cfg( all( feature = "string_split", feature = "string_isolate", feature = "std" ) ) ]
pub use private::request_parse;
}
#[ allow( unused_imports ) ]
pub mod prelude {
#[ allow( unused_imports ) ]
use super::*;
}