use byte::is_token;
use byte_slice::ByteStream;
use std::{ fmt,
str };
macro_rules! submit_error {
($iter:expr, $error:expr) => ({
bs_jump!($iter.context, bs_available!($iter.context));
(*$iter.on_error)($error($iter.context.byte));
return None;
});
}
macro_rules! submit_name {
($iter:expr) => ({
return Some((
unsafe {
let mut s = String::with_capacity($iter.name.len());
s.as_mut_vec().extend_from_slice(&$iter.name);
s
},
None
));
});
}
macro_rules! submit_name_value {
($name:expr, $value:expr) => ({
return Some((
unsafe {
let mut s = String::with_capacity($name.len());
s.as_mut_vec().extend_from_slice(&$name);
s
},
unsafe {
let mut s = String::with_capacity($value.len());
s.as_mut_vec().extend_from_slice(&$value);
Some(s)
}
));
});
($iter:expr) => ({
return Some((
unsafe {
let mut s = String::with_capacity($iter.name.len());
s.as_mut_vec().extend_from_slice(&$iter.name);
s
},
unsafe {
let mut s = String::with_capacity($iter.value.len());
s.as_mut_vec().extend_from_slice(&$iter.value);
Some(s)
}
));
});
}
pub enum DecodeError {
Byte(u8),
HexSequence(u8)
}
impl fmt::Debug for DecodeError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
DecodeError::Byte(x) => {
write!(
formatter,
"DecodeError::Byte(Invalid byte on byte {})",
x
)
},
DecodeError::HexSequence(x) => {
write!(
formatter,
"DecodeError::HexSequence(Invalid hex sequence on byte {})",
x
)
}
}
}
}
impl fmt::Display for DecodeError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
DecodeError::Byte(x) => {
write!(
formatter,
"Invalid byte on byte {}",
x
)
},
DecodeError::HexSequence(x) => {
write!(
formatter,
"Invalid hex sequence on byte {}",
x
)
}
}
}
}
pub enum FieldError {
Name(u8),
Value(u8)
}
impl fmt::Debug for FieldError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldError::Name(x) => {
write!(
formatter,
"FieldError::Name(Invalid field name on byte {})",
x
)
},
FieldError::Value(x) => {
write!(
formatter,
"FieldError::Value(Invalid field value on byte {})",
x
)
}
}
}
}
impl fmt::Display for FieldError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
FieldError::Name(x) => {
write!(
formatter,
"Invalid field name on byte {}",
x
)
},
FieldError::Value(x) => {
write!(
formatter,
"Invalid field value on byte {}",
x
)
}
}
}
}
pub struct FieldIterator<'a> {
context: ByteStream<'a>,
delimiter: u8,
name: Vec<u8>,
normalize: bool,
on_error: Box<FnMut(FieldError) + 'a>,
value: Vec<u8>
}
impl<'a> FieldIterator<'a> {
pub fn new(field: &'a [u8], delimiter: u8, normalize: bool) -> FieldIterator<'a> {
FieldIterator{
context: ByteStream::new(field),
delimiter: delimiter,
name: Vec::new(),
normalize: normalize,
on_error: Box::new(|_|{}),
value: Vec::new()
}
}
pub fn on_error<F>(&mut self, on_error: F) -> &mut Self
where F : FnMut(FieldError) + 'a {
self.on_error = Box::new(on_error);
self
}
}
impl<'a> Iterator for FieldIterator<'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 {
consume_spaces!(
self.context,
return None
);
bs_mark!(self.context);
collect_tokens_iter!(
self,
self.context,
FieldError::Name,
self.context.byte == b'='
|| self.context.byte == self.delimiter
|| self.context.byte == b'/'
|| (self.normalize && self.context.byte > 0x40 && self.context.byte < 0x5B),
{
if bs_slice_length!(self.context) > 0 {
self.name.extend_from_slice(bs_slice!(self.context));
}
submit_name!(self);
}
);
self.name.extend_from_slice(bs_slice_ignore!(self.context));
match self.context.byte {
b'=' => {
if bs_available!(self.context) == 0 {
submit_name!(self);
}
bs_next!(self.context);
if self.context.byte == b'"' {
loop {
bs_mark!(self.context);
collect_quoted_iter!(
self,
self.context,
FieldError::Value,
submit_error!(self, FieldError::Value)
);
if self.context.byte == b'"' {
self.value.extend_from_slice(bs_slice_ignore!(self.context));
consume_spaces!(
self.context,
submit_name_value!(self)
);
if bs_available!(self.context) == 0 {
submit_name_value!(self);
}
bs_next!(self.context);
if self.context.byte == self.delimiter {
submit_name_value!(self);
}
submit_error!(self, FieldError::Value);
} else {
if bs_is_eos!(self.context) {
submit_error!(self, FieldError::Name);
}
self.value.extend_from_slice(bs_slice_ignore!(self.context));
bs_next!(self.context);
self.value.push(self.context.byte);
}
}
} else {
bs_replay!(self.context);
bs_mark!(self.context);
collect_field_iter!(
self,
self.context,
FieldError::Value,
self.context.byte == self.delimiter,
{
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) == 0 {
submit_name!(self);
}
submit_name_value!(self.name, bs_slice_ignore!(self.context));
}
},
b'/' => {
self.name.push(b'/');
},
byte if byte == self.delimiter => {
submit_name!(self);
},
_ => {
self.name.push(self.context.byte + 0x20);
}
}
}
}
}
pub enum QueryError {
Name(u8),
Value(u8)
}
impl fmt::Debug for QueryError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
QueryError::Name(x) => {
write!(
formatter,
"QueryError::Name(Invalid query name on byte {})",
x
)
},
QueryError::Value(x) => {
write!(
formatter,
"QueryError::Value(Invalid query value on byte {})",
x
)
}
}
}
}
impl fmt::Display for QueryError {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self {
QueryError::Name(x) => {
write!(
formatter,
"Invalid query name on byte {}",
x
)
},
QueryError::Value(x) => {
write!(
formatter,
"Invalid query value on byte {}",
x
)
}
}
}
}
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_iter!(
self,
self.context,
QueryError::Name,
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));
}
if self.context.byte == b'%' {
if bs_has_bytes!(self.context, 2) {
bs_next!(self.context);
let mut byte = if is_digit!(self.context.byte) {
(self.context.byte - b'0') << 4
} else if b'@' < self.context.byte && self.context.byte < b'G' {
(self.context.byte - 0x37) << 4
} else if b'`' < self.context.byte && self.context.byte < b'g' {
(self.context.byte - 0x57) << 4
} else {
submit_error!(self, QueryError::Name);
} as u8;
bs_next!(self.context);
byte |= if is_digit!(self.context.byte) {
self.context.byte - b'0'
} else if b'@' < self.context.byte && self.context.byte < b'G' {
self.context.byte - 0x37
} else if b'`' < self.context.byte && self.context.byte < b'g' {
self.context.byte - 0x57
} else {
submit_error!(self, QueryError::Name);
} as u8;
self.name.push(byte);
} else {
if bs_has_bytes!(self.context, 1) {
bs_next!(self.context);
}
submit_error!(self, QueryError::Name);
}
} else if self.context.byte == b'+' {
self.name.push(b' ');
} else if self.context.byte == b'=' {
if self.context.stream_index == 1 {
submit_error!(self, QueryError::Name);
}
break;
} else if self.context.stream_index == 1 {
submit_error!(self, QueryError::Name);
} else {
submit_name!(self);
}
}
loop {
bs_mark!(self.context);
collect_visible_iter!(
self,
self.context,
QueryError::Value,
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));
}
if self.context.byte == b'%' {
if bs_has_bytes!(self.context, 2) {
bs_next!(self.context);
let mut byte = if is_digit!(self.context.byte) {
(self.context.byte - b'0') << 4
} else if b'@' < self.context.byte && self.context.byte < b'G' {
(self.context.byte - 0x37) << 4
} else if b'`' < self.context.byte && self.context.byte < b'g' {
(self.context.byte - 0x57) << 4
} else {
submit_error!(self, QueryError::Value);
} as u8;
bs_next!(self.context);
byte |= if is_digit!(self.context.byte) {
self.context.byte - b'0'
} else if b'@' < self.context.byte && self.context.byte < b'G' {
self.context.byte - 0x37
} else if b'`' < self.context.byte && self.context.byte < b'g' {
self.context.byte - 0x57
} else {
submit_error!(self, QueryError::Value);
} as u8;
self.value.push(byte);
} else {
if bs_has_bytes!(self.context, 1) {
bs_next!(self.context);
}
submit_error!(self, QueryError::Value);
}
} else if self.context.byte == b'+' {
self.value.push(b' ');
} else {
submit_name_value!(self);
}
}
}
}
}
pub fn decode(encoded: &[u8]) -> Result<String, DecodeError> {
macro_rules! submit {
($string:expr, $slice:expr) => (unsafe {
$string.as_mut_vec().extend_from_slice($slice);
});
}
let mut context = ByteStream::new(encoded);
let mut string = String::new();
loop {
bs_mark!(context);
collect_visible!(
context,
DecodeError::Byte,
context.byte == b'%'
|| context.byte == b'+',
{
if context.mark_index < context.stream_index {
submit!(string, bs_slice!(context));
}
return Ok(string);
}
);
if bs_slice_length!(context) > 1 {
submit!(string, bs_slice_ignore!(context));
}
if context.byte == b'+' {
submit!(string, b" ");
} else if bs_has_bytes!(context, 2) {
bs_next!(context);
let mut byte = if is_digit!(context.byte) {
(context.byte - b'0') << 4
} else if b'@' < context.byte && context.byte < b'G' {
(context.byte - 0x37) << 4
} else if b'`' < context.byte && context.byte < b'g' {
(context.byte - 0x57) << 4
} else {
return Err(DecodeError::HexSequence(context.byte));
} as u8;
bs_next!(context);
byte |= if is_digit!(context.byte) {
context.byte - b'0'
} else if b'@' < context.byte && context.byte < b'G' {
context.byte - 0x37
} else if b'`' < context.byte && context.byte < b'g' {
context.byte - 0x57
} else {
return Err(DecodeError::HexSequence(context.byte));
} as u8;
submit!(string, &[byte]);
} else {
if bs_has_bytes!(context, 1) {
bs_next!(context);
}
return Err(DecodeError::HexSequence(context.byte));
}
}
}