1use crate::value::Value;
2use std::char;
3use std::collections::HashMap;
4
5pub fn consume_ws(dat: &str) -> &str {
6 dat.trim_start()
7}
8
9pub fn parse_string(dat: &str) -> Option<(String, &str)> {
10 let mut ret = String::with_capacity(dat.len());
12 let mut cur = &dat[1..];
13 while !cur.is_empty() {
14 if let Some(i) = cur.find('\\') {
15 ret.push_str(&cur[..i]);
16 let chr = cur.as_bytes()[i + 1];
17 if chr == b'u' {
18 let hex = &cur[i + 2..i + 6];
19 if hex.len() != 4 {
20 return None;
21 }
22 if let Ok(v) = u16::from_str_radix(hex, 16) {
23 ret.push(char::from_u32(v as u32)?);
24 cur = &cur[i + 6..];
25 } else {
26 return None;
27 }
28 } else {
29 let parsed = match chr {
30 b'"' => '"',
31 b'\\' => '\\',
32 b'/' => '/',
33 b'b' => '\x08',
34 b'f' => '\x0c',
35 b'n' => '\n',
36 b'r' => '\r',
37 b't' => '\t',
38 _ => return None,
39 };
40 ret.push(parsed);
41 cur = &cur[i + 2..];
42 }
43 } else {
44 let v = cur.find('"')?;
45 ret.push_str(&cur[..v]);
46 return Some((ret, &cur[v + 1..]));
47 }
48 }
49 None
50}
51
52pub fn parse_bool(dat: &str) -> Option<(bool, &str)> {
53 if dat.starts_with("true") {
54 return Some((true, &dat[4..]));
55 } else if dat.starts_with("false") {
56 return Some((false, &dat[5..]));
57 }
58 None
59}
60
61pub fn parse_null(dat: &str) -> Option<((), &str)> {
62 if dat.starts_with("null") {
63 return Some(((), &dat[4..]));
64 }
65 None
66}
67
68pub fn parse_int_or_float(dat: &str) -> Option<(Value, &str)> {
69 let mut end = dat.len();
70 let dat_bytes = dat.as_bytes();
71 let mut is_float = false;
72 for (i, v) in dat_bytes.iter().enumerate() {
73 match v {
74 b'0'..=b'9' | b'-' | b'+' => {}
75 b'e' | b'.' => {
76 is_float = true;
77 }
78 _ => {
79 end = i;
80 break;
81 }
82 };
83 }
84 return Some((
85 if is_float {
86 Value::Float(dat[..end].parse().ok()?)
87 } else {
88 Value::Integer(dat[..end].parse().ok()?)
89 }, &dat[end..]
90 ));
91}
92
93pub fn parse_object(dat: &str) -> Option<(HashMap<String, Value>, &str)> {
94 let mut cur = consume_ws(&dat[1..]);
96 let mut ret = HashMap::<String, Value>::new();
97 if *cur.as_bytes().get(0)? == b'}' {
98 return Some((ret, &cur[1..]));
99 }
100 while !cur.is_empty() {
101 let (key, rest) = parse_string(cur)?;
102 cur = consume_ws(rest);
103 if *cur.as_bytes().get(0)? != b':' {
104 return None;
105 }
106 let (val, remainder) = parse_element(&cur[1..])?;
107 ret.insert(key, val);
108 cur = remainder;
109 match *cur.as_bytes().get(0)? {
110 b',' => {
111 cur = consume_ws(&cur[1..]);
112 }
113 b'}' => return Some((ret, &cur[1..])),
114 _ => return None,
115 }
116 }
117 None
118}
119
120pub fn parse_array(dat: &str) -> Option<(Vec<Value>, &str)> {
121 let mut cur = consume_ws(&dat[1..]);
123 let mut ret = Vec::<Value>::new();
124 if *cur.as_bytes().get(0)? == b']' {
125 return Some((ret, &cur[1..]));
126 }
127 while !cur.is_empty() {
128 let (val, rest) = parse_element(cur)?;
129 ret.push(val);
130 match *rest.as_bytes().get(0)? {
131 b',' => {
132 cur = consume_ws(&rest[1..]);
133 }
134 b']' => {
135 cur = &rest[1..];
136 break;
137 }
138 _ => return None,
139 };
140 }
141 Some((ret, cur))
142}
143
144macro_rules! do_fst {
145 (|$name:pat| $body:expr) => {
146 |($name, snd)| ($body, snd)
147 };
148 ($func:path) => {
149 |(fst, snd)| ($func(fst), snd)
150 };
151}
152
153pub fn parse_value(dat: &str) -> Option<(Value, &str)> {
154 match dat.as_bytes()[0] {
155 b'{' => parse_object(dat).map(do_fst!(Value::Object)),
156 b'-' | b'0'..=b'9' => parse_int_or_float(dat),
157 b'"' => parse_string(dat).map(do_fst!(Value::String)),
158 b't' | b'f' => parse_bool(dat).map(do_fst!(Value::Boolean)),
159 b'n' => parse_null(dat).map(do_fst!(|_| Value::Null)),
160 b'[' => parse_array(dat).map(do_fst!(Value::Array)),
161 _ => None,
162 }
163}
164
165pub fn parse_element(dat: &str) -> Option<(Value, &str)> {
166 let trimmed = consume_ws(dat);
167 let (val, rest) = parse_value(trimmed)?;
168 Some((val, consume_ws(rest)))
169}