json.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. use std::collections::BTreeMap;
  2. use std::fmt::{Display, Formatter};
  3. #[derive(Debug, Clone, PartialEq, Eq)]
  4. pub enum JsonValue {
  5. Null,
  6. Bool(bool),
  7. Number(i64),
  8. String(String),
  9. Array(Vec<JsonValue>),
  10. Object(BTreeMap<String, JsonValue>),
  11. }
  12. #[derive(Debug, Clone, PartialEq, Eq)]
  13. pub struct JsonError {
  14. message: String,
  15. }
  16. impl JsonError {
  17. #[must_use]
  18. pub fn new(message: impl Into<String>) -> Self {
  19. Self {
  20. message: message.into(),
  21. }
  22. }
  23. }
  24. impl Display for JsonError {
  25. fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
  26. write!(f, "{}", self.message)
  27. }
  28. }
  29. impl std::error::Error for JsonError {}
  30. impl JsonValue {
  31. #[must_use]
  32. pub fn render(&self) -> String {
  33. match self {
  34. Self::Null => "null".to_string(),
  35. Self::Bool(value) => value.to_string(),
  36. Self::Number(value) => value.to_string(),
  37. Self::String(value) => render_string(value),
  38. Self::Array(values) => {
  39. let rendered = values
  40. .iter()
  41. .map(Self::render)
  42. .collect::<Vec<_>>()
  43. .join(",");
  44. format!("[{rendered}]")
  45. }
  46. Self::Object(entries) => {
  47. let rendered = entries
  48. .iter()
  49. .map(|(key, value)| format!("{}:{}", render_string(key), value.render()))
  50. .collect::<Vec<_>>()
  51. .join(",");
  52. format!("{{{rendered}}}")
  53. }
  54. }
  55. }
  56. pub fn parse(source: &str) -> Result<Self, JsonError> {
  57. let mut parser = Parser::new(source);
  58. let value = parser.parse_value()?;
  59. parser.skip_whitespace();
  60. if parser.is_eof() {
  61. Ok(value)
  62. } else {
  63. Err(JsonError::new("unexpected trailing content"))
  64. }
  65. }
  66. #[must_use]
  67. pub fn as_object(&self) -> Option<&BTreeMap<String, JsonValue>> {
  68. match self {
  69. Self::Object(value) => Some(value),
  70. _ => None,
  71. }
  72. }
  73. #[must_use]
  74. pub fn as_array(&self) -> Option<&[JsonValue]> {
  75. match self {
  76. Self::Array(value) => Some(value),
  77. _ => None,
  78. }
  79. }
  80. #[must_use]
  81. pub fn as_str(&self) -> Option<&str> {
  82. match self {
  83. Self::String(value) => Some(value),
  84. _ => None,
  85. }
  86. }
  87. #[must_use]
  88. pub fn as_bool(&self) -> Option<bool> {
  89. match self {
  90. Self::Bool(value) => Some(*value),
  91. _ => None,
  92. }
  93. }
  94. #[must_use]
  95. pub fn as_i64(&self) -> Option<i64> {
  96. match self {
  97. Self::Number(value) => Some(*value),
  98. _ => None,
  99. }
  100. }
  101. }
  102. fn render_string(value: &str) -> String {
  103. let mut rendered = String::with_capacity(value.len() + 2);
  104. rendered.push('"');
  105. for ch in value.chars() {
  106. match ch {
  107. '"' => rendered.push_str("\\\""),
  108. '\\' => rendered.push_str("\\\\"),
  109. '\n' => rendered.push_str("\\n"),
  110. '\r' => rendered.push_str("\\r"),
  111. '\t' => rendered.push_str("\\t"),
  112. '\u{08}' => rendered.push_str("\\b"),
  113. '\u{0C}' => rendered.push_str("\\f"),
  114. control if control.is_control() => push_unicode_escape(&mut rendered, control),
  115. plain => rendered.push(plain),
  116. }
  117. }
  118. rendered.push('"');
  119. rendered
  120. }
  121. fn push_unicode_escape(rendered: &mut String, control: char) {
  122. const HEX: &[u8; 16] = b"0123456789abcdef";
  123. rendered.push_str("\\u");
  124. let value = u32::from(control);
  125. for shift in [12_u32, 8, 4, 0] {
  126. let nibble = ((value >> shift) & 0xF) as usize;
  127. rendered.push(char::from(HEX[nibble]));
  128. }
  129. }
  130. struct Parser<'a> {
  131. chars: Vec<char>,
  132. index: usize,
  133. _source: &'a str,
  134. }
  135. impl<'a> Parser<'a> {
  136. fn new(source: &'a str) -> Self {
  137. Self {
  138. chars: source.chars().collect(),
  139. index: 0,
  140. _source: source,
  141. }
  142. }
  143. fn parse_value(&mut self) -> Result<JsonValue, JsonError> {
  144. self.skip_whitespace();
  145. match self.peek() {
  146. Some('n') => self.parse_literal("null", JsonValue::Null),
  147. Some('t') => self.parse_literal("true", JsonValue::Bool(true)),
  148. Some('f') => self.parse_literal("false", JsonValue::Bool(false)),
  149. Some('"') => self.parse_string().map(JsonValue::String),
  150. Some('[') => self.parse_array(),
  151. Some('{') => self.parse_object(),
  152. Some('-' | '0'..='9') => self.parse_number().map(JsonValue::Number),
  153. Some(other) => Err(JsonError::new(format!("unexpected character: {other}"))),
  154. None => Err(JsonError::new("unexpected end of input")),
  155. }
  156. }
  157. fn parse_literal(&mut self, expected: &str, value: JsonValue) -> Result<JsonValue, JsonError> {
  158. for expected_char in expected.chars() {
  159. if self.next() != Some(expected_char) {
  160. return Err(JsonError::new(format!(
  161. "invalid literal: expected {expected}"
  162. )));
  163. }
  164. }
  165. Ok(value)
  166. }
  167. fn parse_string(&mut self) -> Result<String, JsonError> {
  168. self.expect('"')?;
  169. let mut value = String::new();
  170. while let Some(ch) = self.next() {
  171. match ch {
  172. '"' => return Ok(value),
  173. '\\' => value.push(self.parse_escape()?),
  174. plain => value.push(plain),
  175. }
  176. }
  177. Err(JsonError::new("unterminated string"))
  178. }
  179. fn parse_escape(&mut self) -> Result<char, JsonError> {
  180. match self.next() {
  181. Some('"') => Ok('"'),
  182. Some('\\') => Ok('\\'),
  183. Some('/') => Ok('/'),
  184. Some('b') => Ok('\u{08}'),
  185. Some('f') => Ok('\u{0C}'),
  186. Some('n') => Ok('\n'),
  187. Some('r') => Ok('\r'),
  188. Some('t') => Ok('\t'),
  189. Some('u') => self.parse_unicode_escape(),
  190. Some(other) => Err(JsonError::new(format!("invalid escape sequence: {other}"))),
  191. None => Err(JsonError::new("unexpected end of input in escape sequence")),
  192. }
  193. }
  194. fn parse_unicode_escape(&mut self) -> Result<char, JsonError> {
  195. let mut value = 0_u32;
  196. for _ in 0..4 {
  197. let Some(ch) = self.next() else {
  198. return Err(JsonError::new("unexpected end of input in unicode escape"));
  199. };
  200. value = (value << 4)
  201. | ch.to_digit(16)
  202. .ok_or_else(|| JsonError::new("invalid unicode escape"))?;
  203. }
  204. char::from_u32(value).ok_or_else(|| JsonError::new("invalid unicode scalar value"))
  205. }
  206. fn parse_array(&mut self) -> Result<JsonValue, JsonError> {
  207. self.expect('[')?;
  208. let mut values = Vec::new();
  209. loop {
  210. self.skip_whitespace();
  211. if self.try_consume(']') {
  212. break;
  213. }
  214. values.push(self.parse_value()?);
  215. self.skip_whitespace();
  216. if self.try_consume(']') {
  217. break;
  218. }
  219. self.expect(',')?;
  220. }
  221. Ok(JsonValue::Array(values))
  222. }
  223. fn parse_object(&mut self) -> Result<JsonValue, JsonError> {
  224. self.expect('{')?;
  225. let mut entries = BTreeMap::new();
  226. loop {
  227. self.skip_whitespace();
  228. if self.try_consume('}') {
  229. break;
  230. }
  231. let key = self.parse_string()?;
  232. self.skip_whitespace();
  233. self.expect(':')?;
  234. let value = self.parse_value()?;
  235. entries.insert(key, value);
  236. self.skip_whitespace();
  237. if self.try_consume('}') {
  238. break;
  239. }
  240. self.expect(',')?;
  241. }
  242. Ok(JsonValue::Object(entries))
  243. }
  244. fn parse_number(&mut self) -> Result<i64, JsonError> {
  245. let mut value = String::new();
  246. if self.try_consume('-') {
  247. value.push('-');
  248. }
  249. while let Some(ch @ '0'..='9') = self.peek() {
  250. value.push(ch);
  251. self.index += 1;
  252. }
  253. if value.is_empty() || value == "-" {
  254. return Err(JsonError::new("invalid number"));
  255. }
  256. value
  257. .parse::<i64>()
  258. .map_err(|_| JsonError::new("number out of range"))
  259. }
  260. fn expect(&mut self, expected: char) -> Result<(), JsonError> {
  261. match self.next() {
  262. Some(actual) if actual == expected => Ok(()),
  263. Some(actual) => Err(JsonError::new(format!(
  264. "expected '{expected}', found '{actual}'"
  265. ))),
  266. None => Err(JsonError::new(format!(
  267. "expected '{expected}', found end of input"
  268. ))),
  269. }
  270. }
  271. fn try_consume(&mut self, expected: char) -> bool {
  272. if self.peek() == Some(expected) {
  273. self.index += 1;
  274. true
  275. } else {
  276. false
  277. }
  278. }
  279. fn skip_whitespace(&mut self) {
  280. while matches!(self.peek(), Some(' ' | '\n' | '\r' | '\t')) {
  281. self.index += 1;
  282. }
  283. }
  284. fn peek(&self) -> Option<char> {
  285. self.chars.get(self.index).copied()
  286. }
  287. fn next(&mut self) -> Option<char> {
  288. let ch = self.peek()?;
  289. self.index += 1;
  290. Some(ch)
  291. }
  292. fn is_eof(&self) -> bool {
  293. self.index >= self.chars.len()
  294. }
  295. }
  296. #[cfg(test)]
  297. mod tests {
  298. use super::{render_string, JsonValue};
  299. use std::collections::BTreeMap;
  300. #[test]
  301. fn renders_and_parses_json_values() {
  302. let mut object = BTreeMap::new();
  303. object.insert("flag".to_string(), JsonValue::Bool(true));
  304. object.insert(
  305. "items".to_string(),
  306. JsonValue::Array(vec![
  307. JsonValue::Number(4),
  308. JsonValue::String("ok".to_string()),
  309. ]),
  310. );
  311. let rendered = JsonValue::Object(object).render();
  312. let parsed = JsonValue::parse(&rendered).expect("json should parse");
  313. assert_eq!(parsed.as_object().expect("object").len(), 2);
  314. }
  315. #[test]
  316. fn escapes_control_characters() {
  317. assert_eq!(render_string("a\n\t\"b"), "\"a\\n\\t\\\"b\"");
  318. }
  319. }