use std::iter::Peekable;
use std::str::Chars;
use error::Error;
use json::Json;
use number::Number;
pub fn number(slice: &mut Peekable<&mut Chars>) -> Result<Json, Error>
{
let mut token = String::new();
#[derive(Debug, PartialEq)]
enum Stages {
Sign,
AfterSign,
AfterZero,
Integer,
AfterDot,
Fraction,
AfterExp,
AfterExpSign,
Exponent,
End,
}
let mut stage = Stages::Sign;
let mut is_unsigned = true;
'tokenizer: loop {
let current = match slice.peek() {
Some(chr) => *chr,
None => { break 'tokenizer },
};
match stage {
Stages::Sign => match current {
'-' => { stage = Stages::AfterSign; is_unsigned = false; token.push(current); slice.next(); },
'0' => { stage = Stages::AfterZero; token.push(current); slice.next(); },
'1'...'9' => { stage = Stages::Integer; token.push(current); slice.next(); },
_ => {
return Err(Error::InvalidCharacter(current.to_string()));
},
},
Stages::AfterSign => match current {
'0' => { stage = Stages::AfterZero; token.push(current); slice.next(); },
'1'...'9' => { stage = Stages::Integer; token.push(current); slice.next(); },
'.' => { stage = Stages::AfterDot; token.push(current); slice.next(); },
'e' | 'E' => { stage = Stages::AfterExp; token.push(current); slice.next(); },
_ => {
return Err(Error::InvalidCharacter(current.to_string()));
},
},
Stages::AfterZero => match current {
'.' => { stage = Stages::AfterDot; token.push(current); slice.next(); },
'e' | 'E' => { stage = Stages::AfterExp; token.push(current); slice.next(); },
_ => { break 'tokenizer; },
},
Stages::Integer => match current {
'0'...'9' => { stage = Stages::Integer; token.push(current); slice.next(); },
'.' => { stage = Stages::AfterDot; token.push(current); slice.next(); },
'e' | 'E' => { stage = Stages::AfterExp; token.push(current); slice.next(); },
_ => { break 'tokenizer; },
},
Stages::AfterDot => match current {
'0'...'9' => { stage = Stages::Fraction; token.push(current); slice.next(); },
'e' | 'E' => { stage = Stages::AfterExp; token.push(current); slice.next(); },
_ => {
return Err(Error::InvalidCharacter(current.to_string()));
},
},
Stages::Fraction => match current {
'0'...'9' => { stage = Stages::Fraction; token.push(current); slice.next(); },
'e' | 'E' => { stage = Stages::AfterExp; token.push(current); slice.next(); },
_ => { break 'tokenizer; },
},
Stages::AfterExp => match current {
'+' | '-' => { stage = Stages::AfterExpSign; token.push(current); slice.next(); },
'0' => { stage = Stages::End; token.push(current); slice.next(); },
'1'...'9' => { stage = Stages::Exponent; token.push(current); slice.next(); },
_ => {
return Err(Error::InvalidCharacter(current.to_string()));
},
},
Stages::AfterExpSign => match current {
'1'...'9' => { stage = Stages::Exponent; token.push(current); slice.next(); },
_ => {
return Err(Error::InvalidCharacter(current.to_string()));
},
},
Stages::Exponent => match current {
'0'...'9' => { token.push(current); slice.next(); },
_ => { break 'tokenizer; },
},
Stages::End => match current {
_ => { break 'tokenizer; },
},
}
}
Ok(Json::Number(
match stage {
Stages::Integer | Stages::AfterZero => {
if is_unsigned {
Number::Unsigned(token.parse::<u64>().unwrap())
} else {
Number::Integer(token.parse::<i64>().unwrap())
}
},
_ => {
Number::Float(token.parse::<f64>().unwrap())
},
}
))
}