json/
json.rs

1use pom::char_class::hex_digit;
2use pom::parser::*;
3
4use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
5use std::collections::HashMap;
6use std::str::{self, FromStr};
7
8#[derive(Debug, PartialEq)]
9pub enum JsonValue {
10	Null,
11	Bool(bool),
12	Str(String),
13	Num(f64),
14	Array(Vec<JsonValue>),
15	Object(HashMap<String, JsonValue>),
16}
17
18fn space<'a>() -> Parser<'a, u8, ()> {
19	one_of(b" \t\r\n").repeat(0..).discard()
20}
21
22fn number<'a>() -> Parser<'a, u8, f64> {
23	let integer = one_of(b"123456789") - one_of(b"0123456789").repeat(0..) | sym(b'0');
24	let frac = sym(b'.') + one_of(b"0123456789").repeat(1..);
25	let exp = one_of(b"eE") + one_of(b"+-").opt() + one_of(b"0123456789").repeat(1..);
26	let number = sym(b'-').opt() + integer + frac.opt() + exp.opt();
27	number.collect().convert(str::from_utf8).convert(f64::from_str)
28}
29
30fn string<'a>() -> Parser<'a, u8, String> {
31	let special_char = sym(b'\\') | sym(b'/') | sym(b'"')
32		| sym(b'b').map(|_|b'\x08') | sym(b'f').map(|_|b'\x0C')
33		| sym(b'n').map(|_|b'\n') | sym(b'r').map(|_|b'\r') | sym(b't').map(|_|b'\t');
34	let escape_sequence = sym(b'\\') * special_char;
35	let char_string = (none_of(b"\\\"") | escape_sequence).repeat(1..).convert(String::from_utf8);
36	let utf16_char = seq(b"\\u") * is_a(hex_digit).repeat(4).convert(String::from_utf8).convert(|digits|u16::from_str_radix(&digits, 16));
37	let utf16_string = utf16_char.repeat(1..).map(|chars|decode_utf16(chars).map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)).collect::<String>());
38	let string = sym(b'"') * (char_string | utf16_string).repeat(0..) - sym(b'"');
39	string.map(|strings| strings.concat())
40}
41
42fn array<'a>() -> Parser<'a, u8, Vec<JsonValue>> {
43	let elems = list(call(value), sym(b',') * space());
44	sym(b'[') * space() * elems - sym(b']')
45}
46
47fn object<'a>() -> Parser<'a, u8, HashMap<String, JsonValue>> {
48	let member = string() - space() - sym(b':') - space() + call(value);
49	let members = list(member, sym(b',') * space());
50	let obj = sym(b'{') * space() * members - sym(b'}');
51	obj.map(|members| members.into_iter().collect::<HashMap<_, _>>())
52}
53
54fn value<'a>() -> Parser<'a, u8, JsonValue> {
55	( seq(b"null").map(|_|JsonValue::Null)
56	| seq(b"true").map(|_|JsonValue::Bool(true))
57	| seq(b"false").map(|_|JsonValue::Bool(false))
58	| number().map(|num|JsonValue::Num(num))
59	| string().map(|text|JsonValue::Str(text))
60	| array().map(|arr|JsonValue::Array(arr))
61	| object().map(|obj|JsonValue::Object(obj))
62	) - space()
63}
64
65pub fn json<'a>() -> Parser<'a, u8, JsonValue> {
66	space() * value() - end()
67}
68
69#[allow(dead_code)]
70fn main() {
71	let input = br#"
72	{
73        "Image": {
74            "Width":  800,
75            "Height": 600,
76            "Title":  "View from 15th Floor",
77            "Thumbnail": {
78                "Url":    "http://www.example.com/image/481989943",
79                "Height": 125,
80                "Width":  100
81            },
82            "Animated" : false,
83            "IDs": [116, 943, 234, 38793]
84        },
85        "escaped characters": "\u2192\uD83D\uDE00\"\t\uD834\uDD1E"
86    }"#;
87
88	println!("{:?}", json().parse(input));
89}