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_json(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 mut end = start;
92
93 while input[end] != b'"' {
94 end += 1;
95 }
96
97 Result { next: end + 1, ignore: &input[start..end] == RED, value: 0 }
98}
99
100fn parse_number(input: &[u8], start: usize) -> Result {
102 let mut end = start;
103 let mut neg = false;
104 let mut acc = 0;
105
106 if input[end] == b'-' {
107 neg = true;
108 end += 1;
109 }
110
111 while input[end].is_ascii_digit() {
112 acc = 10 * acc + (input[end] - b'0') as i32;
113 end += 1;
114 }
115
116 Result { next: end, ignore: false, value: if neg { -acc } else { acc } }
117}