aleo_struct_parser/
lib.rs

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