aleo_struct_parser/
lib.rs1use serde_json::Map;
2
3struct Cursor<'a> {
4 ref_str: &'a str,
5 start: usize,
6 end: usize,
7}
8
9impl<'a> Cursor<'a> {
10 fn new(ref_str: &str) -> Cursor {
11 Cursor {
12 ref_str,
13 start: 0,
14 end: 0,
15 }
16 }
17
18 fn push(&mut self, idx: usize) {
19 if self.start == 0 {
20 self.start = idx;
21 }
22 self.end = idx + 1;
23 }
24
25 fn clear(&mut self) {
26 self.start = 0;
27 self.end = 0;
28 }
29
30 fn is_empty(&self) -> bool {
31 self.end == 0
32 }
33
34 fn get_str(&self) -> &'a str {
35 &self.ref_str[self.start..self.end]
36 }
37}
38
39pub fn parse_struct(input: &str) -> serde_json::Value {
41 let mut self_map: Map<String, serde_json::Value> = Map::new();
42 let mut depth = 0;
43 let mut current_key = Cursor::new(input);
44 let mut current_child = Cursor::new(input);
45 let mut current_child_stack = 0;
46 let mut is_key = true;
47
48 for (idx, token) in input.char_indices() {
49 match token {
50 '{' => {
51 depth += 1;
52 if depth != 1 {
53 current_child.push(idx);
54 current_child_stack += 1;
55 }
56 }
57 '}' => {
58 depth -= 1;
59 if depth == 0 {
60 break;
61 } else {
62 current_child.push(idx);
63 current_child_stack -= 1;
64 if current_child_stack == 0 {
65 let current_child_str = current_child.get_str();
66 let current_key_str = current_key.get_str();
67 self_map
68 .insert(current_key_str.to_owned(), parse_struct(current_child_str));
69 current_key.clear();
70 current_child.clear();
71 is_key = true;
72 }
73 }
74 }
75 '[' => {
76 depth += 1;
77 current_child.push(idx);
78 current_child_stack += 1;
79 if depth == 1 {
80 is_key = false;
81 }
82 }
83 ']' => {
84 depth -= 1;
85 current_child.push(idx);
86 current_child_stack -= 1;
87 if current_child_stack == 0 {
88 let current_key_str = current_key.get_str();
89 let current_child_str = current_child.get_str();
90 self_map.insert(
91 current_key_str.to_owned(),
92 serde_json::Value::Array(parse_array(current_child_str)),
93 );
94 current_key.clear();
95 current_child.clear();
96 }
97 }
98 ':' => {
99 if depth == 1 {
100 is_key = false;
101 } else {
102 current_child.push(idx);
103 }
104 }
105 '\n' | ' ' | '\r' => {}
106 ',' => {
107 if depth == 1 {
108 if !current_key.is_empty() {
109 let current_key_str = current_key.get_str();
110 let current_child_str = current_child.get_str();
111 self_map.insert(
112 current_key_str.to_owned(),
113 serde_json::Value::String(current_child_str.to_owned()),
114 );
115 }
116 current_key.clear();
117 current_child.clear();
118 is_key = true;
119 } else {
120 current_child.push(idx);
121 }
122 }
123 _ => {
124 if depth == 1 {
125 if is_key {
126 current_key.push(idx);
127 } else {
128 current_child.push(idx);
129 }
130 } else {
131 current_child.push(idx);
132 }
133 }
134 }
135 }
136
137 if !current_key.is_empty() {
138 self_map.insert(
139 current_key.get_str().to_owned(),
140 serde_json::Value::String(current_child.get_str().to_owned()),
141 );
142 }
143
144 serde_json::Value::Object(self_map)
145}
146
147fn parse_array(input: &str) -> Vec<serde_json::Value> {
148 let mut self_vec: Vec<serde_json::Value> = Vec::new();
149 let mut depth = 0;
150 let mut current_item = Cursor::new(input);
151 let mut current_item_stack = 0;
152
153 let mut current_object: Option<serde_json::Value> = None;
154
155 for (idx, token) in input.char_indices() {
156 match token {
157 '{' => {
158 depth += 1;
159 current_item.push(idx);
160 current_item_stack += 1;
161 }
162 '}' => {
163 depth -= 1;
164 current_item.push(idx);
165 current_item_stack -= 1;
166 if current_item_stack == 0 {
167 current_object = Some(parse_struct(current_item.get_str()));
168 }
169 }
170 '[' => {
171 depth += 1;
172 if depth != 1 {
173 current_item.push(idx);
174 current_item_stack += 1;
175 }
176 }
177 ']' => {
178 depth -= 1;
179 if depth == 0 {
180 if let Some(obj) = current_object.take() {
181 self_vec.push(obj);
182 current_object = None;
183 } else {
184 self_vec.push(serde_json::Value::String(current_item.get_str().to_owned()));
185 current_item.clear();
186 current_item_stack = 0;
187 }
188 } else {
189 current_item.push(idx);
190 current_item_stack -= 1;
191 if current_item_stack == 0 {
192 current_object = Some(serde_json::Value::Array(parse_array(
193 current_item.get_str(),
194 )));
195 }
196 }
197 }
198 ':' => {
199 current_item.push(idx);
200 }
201 '\n' | ' ' | '\r' => {}
202 ',' => {
203 if depth == 1 {
204 if let Some(obj) = current_object.take() {
205 self_vec.push(obj);
206 current_object = None;
207 } else {
208 self_vec.push(serde_json::Value::String(current_item.get_str().to_owned()));
209 current_item.clear();
210 }
211 } else {
212 current_item.push(idx);
213 }
214 }
215 _ => {
216 current_item.push(idx);
217 }
218 }
219 }
220
221 self_vec
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn test_parse_struct() {
230 let input = r#"
231 {
232 program_id: puzzle_arcade_ticket_v002.aleo,
233 function_name: mint,
234 arguments: [
235 aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl
236 ]
237 }
238 "#;
239 let expect = r#"
240 {
241 "program_id": "puzzle_arcade_ticket_v002.aleo",
242 "function_name": "mint",
243 "arguments": [
244 "aleo13dn2lyphtrn8mujxcqt4vm2rc567k0s3gnnks985p0hhyvfc9yqqy6rdsl"
245 ]
246 }
247 "#;
248 let parsed_struct = parse_struct(input);
249 assert_eq!(
253 expect.trim().replace(' ', ""),
254 serde_json::to_string_pretty(&parsed_struct)
255 .unwrap()
256 .trim()
257 .replace(' ', "")
258 );
259 }
260}