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}