1use crate::util::parse::*;
26
27const RED: &[u8] = b"red";
28
29struct Result {
30 next: usize,
31 ignore: bool,
32 value: i32,
33}
34
35pub fn parse(input: &str) -> &str {
36 input
37}
38
39pub fn part1(input: &str) -> i32 {
40 input.iter_signed::<i32>().sum()
41}
42
43pub fn part2(input: &str) -> i32 {
44 parse_json(input.as_bytes(), 0).value
45}
46
47fn parse_json(input: &[u8], start: usize) -> Result {
49 match input[start] {
50 b'[' => parse_array(input, start),
51 b'{' => parse_object(input, start),
52 b'"' => parse_string(input, start),
53 _ => parse_number(input, start),
54 }
55}
56
57fn parse_array(input: &[u8], start: usize) -> Result {
59 let mut index = start;
60 let mut total = 0;
61
62 while input[index] != b']' {
63 let Result { next, value, .. } = parse_json(input, index + 1);
64 index = next;
65 total += value;
66 }
67
68 Result { next: index + 1, ignore: false, value: total }
69}
70
71fn parse_object(input: &[u8], start: usize) -> Result {
73 let mut index = start;
74 let mut total = 0;
75 let mut ignore = false;
76
77 while input[index] != b'}' {
78 let Result { next: first, .. } = parse_string(input, index + 1);
79 let Result { next: second, ignore: red, value } = parse_json(input, first + 1);
80 index = second;
81 total += value;
82 ignore |= red;
83 }
84
85 Result { next: index + 1, ignore: false, value: if ignore { 0 } else { total } }
86}
87
88fn parse_string(input: &[u8], start: usize) -> Result {
90 let start = start + 1;
91 let end = start + input[start..].iter().position(|&b| b == b'"').unwrap();
92
93 Result { next: end + 1, ignore: &input[start..end] == RED, value: 0 }
94}
95
96fn parse_number(input: &[u8], start: usize) -> Result {
98 let neg = input[start] == b'-';
99 let mut end = start + usize::from(neg);
100 let mut acc = 0;
101
102 while input[end].is_ascii_digit() {
103 acc = 10 * acc + (input[end] - b'0') as i32;
104 end += 1;
105 }
106
107 Result { next: end, ignore: false, value: if neg { -acc } else { acc } }
108}