use byte_slice::ByteStream;
use std::fmt;
pub enum QueryError {
Name(u8),
Value(u8)
}
impl QueryError {
fn format(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
QueryError::Name(x) => {
write!(
formatter,
"<QueryError::Name: {}>",
x
)
},
QueryError::Value(x) => {
write!(
formatter,
"<QueryError::Value: {}>",
x
)
}
}
}
}
impl fmt::Debug for QueryError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.format(formatter)
}
}
impl fmt::Display for QueryError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.format(formatter)
}
}
pub struct QueryIterator<'a> {
context: ByteStream<'a>,
name: Vec<u8>,
on_error: Box<FnMut(QueryError) + 'a>,
value: Vec<u8>
}
impl<'a> QueryIterator<'a> {
pub fn new(query: &'a [u8]) -> QueryIterator<'a> {
QueryIterator{
context: ByteStream::new(query),
name: Vec::new(),
on_error: Box::new(|_|{}),
value: Vec::new()
}
}
pub fn on_error<F>(&mut self, on_error: F) -> &mut Self
where F : FnMut(QueryError) + 'a {
self.on_error = Box::new(on_error);
self
}
}
impl<'a> Iterator for QueryIterator<'a> {
type Item = (String, Option<String>);
fn next(&mut self) -> Option<(String, Option<String>)> {
if bs_available!(self.context) == 0 {
return None;
}
self.name.clear();
self.value.clear();
loop {
loop {
bs_mark!(self.context);
collect_visible_7bit!(
self.context,
self.context.byte == b'%'
|| self.context.byte == b'+'
|| self.context.byte == b'='
|| self.context.byte == b'&'
|| self.context.byte == b';',
{
if bs_slice_length!(self.context) > 0 {
self.name.extend_from_slice(bs_slice!(self.context));
}
submit_name!(self);
}
);
if bs_slice_length!(self.context) > 1 {
self.name.extend_from_slice(bs_slice_ignore!(self.context));
}
match self.context.byte {
b'%' => {
if bs_has_bytes!(self.context, 2) {
self.name.push(collect_hex8_iter!(
self,
self.context,
QueryError::Name
));
} else if bs_has_bytes!(self.context, 1) {
bs_next!(self.context);
}
submit_error!(self, QueryError::Name);
},
b'+' => {
self.name.push(b' ');
},
b'=' => {
if self.context.stream_index == 1 {
submit_error!(self, QueryError::Name);
}
break;
},
_ if self.context.stream_index == 1 => {
submit_error!(self, QueryError::Name);
},
b'&'
| b';' => {
submit_name!(self);
},
_ => {
bs_jump!(self.context, bs_available!(self.context));
(*self.on_error)(QueryError::Name(self.context.byte));
return None;
}
}
}
loop {
bs_mark!(self.context);
collect_visible_7bit!(
self.context,
self.context.byte == b'%'
|| self.context.byte == b'+'
|| self.context.byte == b'&'
|| self.context.byte == b';',
{
if bs_slice_length!(self.context) > 0 {
self.value.extend_from_slice(bs_slice!(self.context));
}
submit_name_value!(self);
}
);
if bs_slice_length!(self.context) > 1 {
self.value.extend_from_slice(bs_slice_ignore!(self.context));
}
match self.context.byte {
b'%' => {
if bs_has_bytes!(self.context, 2) {
self.value.push(collect_hex8_iter!(
self,
self.context,
QueryError::Value
));
} else {
if bs_has_bytes!(self.context, 1) {
bs_next!(self.context);
}
submit_error!(self, QueryError::Value);
}
},
b'+' => {
self.value.push(b' ');
},
b'&'
| b';' => {
submit_name_value!(self);
},
_ => {
bs_jump!(self.context, bs_available!(self.context));
(*self.on_error)(QueryError::Value(self.context.byte));
return None;
}
}
}
}
}
}