snarkvm_console_program/data/future/
parse.rs1use super::*;
17
18impl<N: Network> Parser for Future<N> {
19    #[inline]
21    fn parse(string: &str) -> ParserResult<Self> {
22        Self::parse_internal(string, 0)
24    }
25}
26
27impl<N: Network> Future<N> {
28    fn parse_arguments(string: &str, depth: usize) -> ParserResult<Vec<Argument<N>>> {
30        let (string, _) = Sanitizer::parse(string)?;
32        let (string, _) = tag("[")(string)?;
34        let (string, _) = Sanitizer::parse(string)?;
36        let (string, arguments) = separated_list0(
38            pair(pair(Sanitizer::parse_whitespaces, tag(",")), Sanitizer::parse),
39            alt((
40                map(|input| Self::parse_internal(input, depth + 1), Argument::Future),
41                map(Plaintext::parse, Argument::Plaintext),
42            )),
43        )(string)?;
44        let (string, _) = Sanitizer::parse(string)?;
46        let (string, _) = tag("]")(string)?;
48        Ok((string, arguments))
50    }
51
52    #[inline]
54    fn parse_internal(string: &str, depth: usize) -> ParserResult<Self> {
55        if depth > N::MAX_DATA_DEPTH {
60            return map_res(take(0usize), |_| {
61                Err(error(format!("Found a future that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH)))
62            })(string);
63        }
64        let (string, _) = Sanitizer::parse(string)?;
66        let (string, _) = tag("{")(string)?;
68
69        let (string, _) = Sanitizer::parse(string)?;
71        let (string, _) = tag("program_id")(string)?;
73        let (string, _) = Sanitizer::parse_whitespaces(string)?;
75        let (string, _) = tag(":")(string)?;
77        let (string, _) = Sanitizer::parse_whitespaces(string)?;
79        let (string, program_id) = ProgramID::parse(string)?;
81        let (string, _) = Sanitizer::parse_whitespaces(string)?;
83        let (string, _) = tag(",")(string)?;
85
86        let (string, _) = Sanitizer::parse(string)?;
88        let (string, _) = tag("function_name")(string)?;
90        let (string, _) = Sanitizer::parse_whitespaces(string)?;
92        let (string, _) = tag(":")(string)?;
94        let (string, _) = Sanitizer::parse_whitespaces(string)?;
96        let (string, function_name) = Identifier::parse(string)?;
98        let (string, _) = Sanitizer::parse_whitespaces(string)?;
100        let (string, _) = tag(",")(string)?;
102
103        let (string, _) = Sanitizer::parse(string)?;
105        let (string, _) = tag("arguments")(string)?;
107        let (string, _) = Sanitizer::parse_whitespaces(string)?;
109        let (string, _) = tag(":")(string)?;
111        let (string, _) = Sanitizer::parse_whitespaces(string)?;
113        let (string, arguments) = Self::parse_arguments(string, depth)?;
115
116        let (string, _) = Sanitizer::parse(string)?;
118        let (string, _) = tag("}")(string)?;
120
121        Ok((string, Self::new(program_id, function_name, arguments)))
122    }
123}
124
125impl<N: Network> FromStr for Future<N> {
126    type Err = Error;
127
128    fn from_str(string: &str) -> Result<Self> {
130        match Self::parse(string) {
131            Ok((remainder, object)) => {
132                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
134                Ok(object)
136            }
137            Err(error) => bail!("Failed to parse string. {error}"),
138        }
139    }
140}
141
142impl<N: Network> Debug for Future<N> {
143    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
145        Display::fmt(self, f)
146    }
147}
148
149impl<N: Network> Display for Future<N> {
150    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
152        self.fmt_internal(f, 0)
153    }
154}
155
156impl<N: Network> Future<N> {
157    fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
159        const INDENT: usize = 2;
161
162        write!(f, "{{")?;
164
165        write!(
167            f,
168            "\n{:indent$}program_id: {program_id},",
169            "",
170            indent = (depth + 1) * INDENT,
171            program_id = self.program_id()
172        )?;
173        write!(
175            f,
176            "\n{:indent$}function_name: {function_name},",
177            "",
178            indent = (depth + 1) * INDENT,
179            function_name = self.function_name()
180        )?;
181        if self.arguments.is_empty() {
184            write!(f, "\n{:indent$}arguments: []", "", indent = (depth + 1) * INDENT)?;
185        } else {
186            write!(f, "\n{:indent$}arguments: [", "", indent = (depth + 1) * INDENT)?;
187            self.arguments.iter().enumerate().try_for_each(|(i, argument)| {
188                match argument {
189                    Argument::Plaintext(plaintext) => match i == self.arguments.len() - 1 {
190                        true => {
191                            write!(
193                                f,
194                                "\n{:indent$}{plaintext}",
195                                "",
196                                indent = (depth + 2) * INDENT,
197                                plaintext = plaintext
198                            )
199                        }
200                        false => {
202                            write!(
203                                f,
204                                "\n{:indent$}{plaintext},",
205                                "",
206                                indent = (depth + 2) * INDENT,
207                                plaintext = plaintext
208                            )
209                        }
210                    },
211                    Argument::Future(future) => {
212                        write!(f, "\n{:indent$}", "", indent = (depth + 2) * INDENT)?;
214                        future.fmt_internal(f, depth + 2)?;
216                        match i == self.arguments.len() - 1 {
218                            true => write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT),
220                            false => write!(f, ","),
222                        }
223                    }
224                }
225            })?;
226            write!(f, "\n{:indent$}]", "", indent = (depth + 1) * INDENT)?;
228        }
229
230        write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
232    }
233}
234
235#[cfg(test)]
236mod tests {
237    use super::*;
238    use snarkvm_console_network::MainnetV0;
239
240    type CurrentNetwork = MainnetV0;
241
242    #[test]
243    fn test_parse_future() -> Result<()> {
244        let expected = r"{
246  program_id: credits.aleo,
247  function_name: transfer,
248  arguments: []
249}";
250        let (remainder, candidate) =
251            Future::<CurrentNetwork>::parse("{ program_id: credits.aleo, function_name: transfer, arguments: [] }")?;
252        assert!(remainder.is_empty());
253        assert_eq!(expected, candidate.to_string());
254        assert_eq!("", remainder);
255
256        let expected = r"{
258  program_id: credits.aleo,
259  function_name: transfer_public_to_private,
260  arguments: [
261    aleo1g8qul5a44vk22u9uuvaewdcjw4v6xg8wx0llru39nnjn7eu08yrscxe4e2,
262    100000000u64
263  ]
264}";
265        let (remainder, candidate) = Future::<CurrentNetwork>::parse(
266            "{ program_id: credits.aleo, function_name: transfer_public_to_private, arguments: [ aleo1g8qul5a44vk22u9uuvaewdcjw4v6xg8wx0llru39nnjn7eu08yrscxe4e2, 100000000u64 ] }",
267        )?;
268        assert!(remainder.is_empty());
269        assert_eq!(expected, candidate.to_string());
270        assert_eq!("", remainder);
271
272        Ok(())
273    }
274
275    #[test]
276    fn test_deeply_nested_future() {
277        fn create_nested_future(depth: usize) -> String {
279            let root = r"{
281                program_id: foo.aleo,
282                function_name: bar,
283                arguments: []
284            }";
285            let prefix = r"{
287                program_id: foo.aleo,
288                function_name: bar,
289                arguments: ["
290                .repeat(depth);
291            let suffix = r"]}".repeat(depth);
292            format!("{prefix}{root}{suffix}")
294        }
295
296        fn run_test(depth: usize, expected_error: bool) {
298            let nested_future_string = create_nested_future(depth);
300            let result = Future::<CurrentNetwork>::parse(&nested_future_string);
302            match expected_error {
304                true => {
305                    assert!(result.is_err());
306                    return;
307                }
308                false => assert!(result.is_ok()),
309            };
310            let (remainder, candidate) = result.unwrap();
312            assert!(
314                remainder.is_empty(),
315                "Failed to parse deeply nested future. Found invalid character in: \"{remainder}\""
316            );
317            let expected = nested_future_string.replace("\n", "").replace(" ", "").replace("\t", "");
319            let candidate_str = candidate.to_string().replace("\n", "").replace(" ", "").replace("\t", "");
321            assert_eq!(expected, candidate_str, "Expected: {expected}, Candidate: {candidate_str}");
323        }
324
325        let mut depths = (0usize..100).collect_vec();
327        depths.extend((100..1000).step_by(100));
328        depths.extend((1000..10000).step_by(1000));
329        depths.extend((10000..100000).step_by(10000));
330
331        for depth in depths {
333            run_test(depth, depth > CurrentNetwork::MAX_DATA_DEPTH);
334        }
335    }
336}