aleo_struct_parser/
lib.rs

1use 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
39// parse aleo struct to json value, assuming the input is valid
40pub 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        // println!("{:#?}", parsed_struct);
250        // println!("{}", serde_json::to_string_pretty(&parsed_struct).unwrap());
251
252        assert_eq!(
253            expect.trim().replace(' ', ""),
254            serde_json::to_string_pretty(&parsed_struct)
255                .unwrap()
256                .trim()
257                .replace(' ', "")
258        );
259    }
260}