use std::{
collections::HashMap,
iter::Peekable,
str::{CharIndices, FromStr},
};
use crate::{error::SerDeJsonError, Number, Value};
enum Ident {
True,
False,
Null,
}
pub trait Deserialize {
fn deserialize(value: Value) -> Result<Self, SerDeJsonError>
where
Self: Sized;
}
impl Deserialize for Value {
fn deserialize(value: Value) -> Result<Self, SerDeJsonError>
where
Self: Sized,
{
Ok(value)
}
}
pub fn from_str<T: Deserialize>(value: &str) -> Result<T, SerDeJsonError> {
let value = Value::from_str(value)?;
T::deserialize(value)
}
impl FromStr for Value {
type Err = SerDeJsonError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let value = value.trim();
let value = value.char_indices().peekable();
let mut tokens = JsonParser::new(value);
let value = tokens.parse()?;
Ok(value)
}
}
struct JsonParser<'a> {
reader: Peekable<CharIndices<'a>>,
index: usize,
}
impl<'a> JsonParser<'a> {
pub fn new(reader: Peekable<CharIndices<'a>>) -> Self {
Self { reader, index: 0 }
}
pub fn parse(&mut self) -> Result<Value, SerDeJsonError> {
let value = match self.skip_whitespaces()? {
'{' => self.parse_object()?,
'[' => self.parse_array()?,
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
};
match self.skip_whitespaces() {
Ok('\0') | Err(..) => (),
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
}
Ok(value)
}
pub fn skip_whitespaces(&mut self) -> Result<char, SerDeJsonError> {
loop {
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
if c.is_ascii_whitespace() {
self.reader.next();
continue;
}
break Ok(*c);
}
}
pub fn parse_object(&mut self) -> Result<Value, SerDeJsonError> {
self.reader.next();
let mut final_value = HashMap::new();
loop {
match self.skip_whitespaces()? {
'"' => (),
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
}
let key = self.parse_string()?;
match self.skip_whitespaces()? {
':' => {
self.reader.next();
}
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
}
let c = self.skip_whitespaces()?;
let value = self.parse_value(c)?;
if final_value.insert(key.clone(), value).is_some() {
return Err(SerDeJsonError::DupplicateKey {
key,
index: self.index,
});
}
match self.skip_whitespaces()? {
',' => {
self.reader.next();
continue;
}
'}' => break,
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
}
}
self.reader.next();
Ok(Value::Object(final_value))
}
pub fn parse_array(&mut self) -> Result<Value, SerDeJsonError> {
self.reader.next();
let mut final_value = Vec::new();
loop {
let c = self.skip_whitespaces()?;
let value = self.parse_value(c)?;
final_value.push(value);
match self.skip_whitespaces()? {
',' => {
self.reader.next();
continue;
}
']' => break,
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
}
}
self.reader.next();
Ok(Value::Array(final_value))
}
pub fn parse_value(&mut self, next_char: char) -> Result<Value, SerDeJsonError> {
let value = match next_char {
'"' => Value::String(self.parse_string()?),
'-' | '0'..='9' => self.parse_number()?,
'{' => self.parse_object()?,
'[' => self.parse_array()?,
't' => self.parse_ident(Ident::True)?,
'f' => self.parse_ident(Ident::False)?,
'n' => self.parse_ident(Ident::Null)?,
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
};
Ok(value)
}
pub fn parse_number(&mut self) -> Result<Value, SerDeJsonError> {
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
let (c, is_positive) = if *c == '-' {
self.reader.next();
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
(c, false)
} else {
(c, true)
};
let full_number = match c {
'0' => {
self.reader.next();
'0'.to_string()
}
'1'..='9' => self.parse_integer()?,
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
};
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
let (full_number, is_decimal) = match *c {
'.' => {
self.reader.next();
(full_number + &self.parse_integer()?, true)
}
_ => (full_number, false),
};
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
let final_number = match *c {
'e' | 'E' => {
let full_number: f64 = match full_number.parse() {
Ok(full_number) => full_number,
Err(e) => {
return Err(SerDeJsonError::NumberError {
number: full_number,
index: self.index,
error: e.to_string(),
})
}
};
self.reader.next();
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
let mut full_exponent_part = String::new();
let c = *c;
if c == '+' || c == '-' {
self.reader.next();
full_exponent_part.push(c);
}
let full_exponent_part = full_exponent_part + &self.parse_integer()?;
let full_exponent_part: i32 = match full_exponent_part.parse() {
Ok(full_exponent_part) => full_exponent_part,
Err(e) => {
return Err(SerDeJsonError::NumberError {
number: full_exponent_part,
index: self.index,
error: e.to_string(),
})
}
};
let final_number = full_number * 10f64.powi(full_exponent_part);
Number::Decimal(final_number)
}
_ => {
if is_decimal {
let nb: f64 = match full_number.parse() {
Ok(nb) => nb,
Err(e) => {
return Err(SerDeJsonError::NumberError {
number: full_number,
index: self.index,
error: e.to_string(),
})
}
};
Number::Decimal(nb)
} else {
if is_positive {
let nb: u128 = match full_number.parse() {
Ok(nb) => nb,
Err(e) => {
return Err(SerDeJsonError::NumberError {
number: full_number,
index: self.index,
error: e.to_string(),
})
}
};
Number::Integer(nb)
} else {
let nb: i128 = match full_number.parse() {
Ok(nb) => nb,
Err(e) => {
return Err(SerDeJsonError::NumberError {
number: full_number,
index: self.index,
error: e.to_string(),
})
}
};
Number::SignedInteger(nb)
}
}
}
};
Ok(Value::Number(final_number))
}
fn parse_integer(&mut self) -> Result<String, SerDeJsonError> {
let mut integer_part = String::new();
loop {
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
let c = *c;
match c {
'0'..='9' => {
self.reader.next();
integer_part.push(c);
}
_ => break,
}
}
if integer_part.is_empty() {
return Err(SerDeJsonError::InvalidJson { index: self.index });
}
Ok(integer_part)
}
pub fn parse_string(&mut self) -> Result<String, SerDeJsonError> {
self.reader.next();
let mut chars: Vec<char> = Vec::new();
loop {
let Some((i, c)) = self.reader.next() else {
return Err(SerDeJsonError::InvalidJson { index: self.index });
};
self.index = i;
match c {
'"' => break,
'\\' => {
let Some((i, c)) = self.reader.next() else {
return Err(SerDeJsonError::InvalidJson { index: self.index });
};
self.index = i;
let c = match c {
'"' => '\"',
'\\' => '\\',
'n' => '\n',
'r' => '\r',
't' => '\t',
'u' => {
let mut hex_digits = String::new();
for _ in 0..4 {
let Some((i, c)) = self.reader.next() else {
return Err(SerDeJsonError::InvalidJson { index: self.index });
};
self.index = i;
hex_digits.push(c);
}
let code_point = u32::from_str_radix(&hex_digits, 16).unwrap();
match char::from_u32(code_point) {
Some(c) => c,
None => {
return Err(SerDeJsonError::InvalidJson { index: self.index })
}
}
}
_ => return Err(SerDeJsonError::InvalidJson { index: self.index }),
};
chars.push(c);
}
c => chars.push(c),
}
}
Ok(String::from_iter(chars))
}
pub fn parse_ident(&mut self, ident: Ident) -> Result<Value, SerDeJsonError> {
let (value, ident) = match ident {
Ident::True => (Value::Boolean(true), "true"),
Ident::False => (Value::Boolean(false), "false"),
Ident::Null => (Value::Null, "null"),
};
for c_in_pattern in ident.chars() {
let Some((i, c)) = self.reader.peek() else {
return Err(SerDeJsonError::UnexpectedEnd { index: self.index });
};
self.index = *i;
if *c == ',' || c.is_ascii_whitespace() {
break;
}
if *c != c_in_pattern {
return Err(SerDeJsonError::InvalidJson { index: self.index });
}
self.reader.next();
}
Ok(value)
}
}
#[cfg(test)]
mod tests {
use crate::{error::SerDeJsonError, Value};
#[test]
fn test() {
let truc = r#"[
{
"_id": "666895f3d593468af0ab2235",
"index": 0,
"guid": "d1f9ebea-c276-4617-90aa-3cd30edc3ae9",
"isActive": true,
"balance": "$2,310.49",
"picture": "http://placehold.it/32x32",
"age": 29,
"eyeColor": "green",
"name": "Kidd Sykes",
"gender": "male",
"company": "TRASOLA",
"email": "kiddsykes@trasola.com",
"phone": "+1 (823) 468-2410",
"address": "778 Alton Place, Allamuchy, Delaware, 6398",
"about": "Labore consequat laborum nisi deserunt nisi nisi dolore fugiat commodo voluptate minim est qui dolore. Aliqua elit est nostrud eu ad excepteur. Esse incididunt laboris enim culpa commodo.\r\n",
"registered": "2022-08-31T07:11:46 -02:00",
"latitude": 29.07863,
"longitude": -118.387919,
"tags": [
"nulla",
"voluptate",
"ut",
"voluptate",
"sunt",
"labore",
"sunt"
],
"friends": [
{
"id": 0,
"name": "Rosario Britt"
},
{
"id": 1,
"name": "Maribel Fowler"
},
{
"id": 2,
"name": "Jenkins Church"
}
],
"greeting": "Hello, Kidd Sykes! You have 9 unread messages.",
"favoriteFruit": "strawberry"
},
{
"_id": "666895f371fbd3e96171e666",
"index": 1,
"guid": "da698537-f194-43b5-b270-bceb89a793dc",
"isActive": false,
"balance": "$3,446.47",
"picture": "http://placehold.it/32x32",
"age": 34,
"eyeColor": "brown",
"name": "Tyler Frank",
"gender": "male",
"company": "BITENDREX",
"email": "tylerfrank@bitendrex.com",
"phone": "+1 (835) 435-2740",
"address": "548 Bergen Street, Downsville, American Samoa, 2917",
"about": "Occaecat et Lorem magna ea. Sit in ullamco commodo qui et est in duis mollit sunt exercitation aute aliquip. Occaecat laboris incididunt anim esse ea id magna. Cupidatat eu do enim cupidatat esse amet elit in aliqua. Enim duis cupidatat proident eu adipisicing amet tempor non ullamco aute nostrud excepteur cupidatat.\r\n",
"registered": "2022-07-18T09:13:24 -02:00",
"latitude": -31.405638,
"longitude": 113.128241,
"tags": [
"officia",
"qui",
"eiusmod",
"magna",
"velit",
"commodo",
"officia"
],
"friends": [
{
"id": 0,
"name": "Saundra Grant"
},
{
"id": 1,
"name": "Burt Craft"
},
{
"id": 2,
"name": "Vinson Vega"
}
],
"greeting": "Hello, Tyler Frank! You have 2 unread messages.",
"favoriteFruit": "banana"
}
]"#;
let value: Value = match crate::from_str(truc) {
Ok(value) => value,
Err(e) => match e {
SerDeJsonError::InvalidJson { index }
| SerDeJsonError::UnexpectedEnd { index }
| SerDeJsonError::DupplicateKey { index, .. }
| SerDeJsonError::NumberError { index, .. } => {
let begin = index - 10;
let end = index + 10;
let char = truc.get(index..=index).unwrap();
let truc_extract = truc.get(begin..=end).unwrap();
panic!(
"From index {begin} to index {end} : `{}`, character `{char}` : {e:?}",
truc_extract
);
}
_ => unimplemented!(),
},
};
println!("{value:?}\n\n\n{}", value.to_string());
}
}