/ console / program / src / data / future / parse.rs
parse.rs
  1  // Copyright (c) 2019-2025 Alpha-Delta Network Inc.
  2  // This file is part of the alphavm library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  use super::*;
 17  
 18  impl<N: Network> Parser for Future<N> {
 19      /// Parses a string into a future value.
 20      #[inline]
 21      fn parse(string: &str) -> ParserResult<Self> {
 22          // Parse the future from the string.
 23          Self::parse_internal(string, 0)
 24      }
 25  }
 26  
 27  impl<N: Network> Future<N> {
 28      /// Parses an array of future arguments: `[arg_0, ..., arg_1]`, while tracking the depth of the data.
 29      fn parse_arguments(string: &str, depth: usize) -> ParserResult<Vec<Argument<N>>> {
 30          // Parse the whitespace and comments from the string.
 31          let (string, _) = Sanitizer::parse(string)?;
 32          // Parse the "[" from the string.
 33          let (string, _) = tag("[")(string)?;
 34          // Parse the whitespace from the string.
 35          let (string, _) = Sanitizer::parse(string)?;
 36          // Parse the members.
 37          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          // Parse the whitespace and comments from the string.
 45          let (string, _) = Sanitizer::parse(string)?;
 46          // Parse the ']' from the string.
 47          let (string, _) = tag("]")(string)?;
 48          // Output the plaintext.
 49          Ok((string, arguments))
 50      }
 51  
 52      /// Parses a string into a future value, while tracking the depth of the data.
 53      #[inline]
 54      fn parse_internal(string: &str, depth: usize) -> ParserResult<Self> {
 55          // Ensure that the depth is within the maximum limit.
 56          // Note: `N::MAX_DATA_DEPTH` is an upper bound on the number of nested futures.
 57          //  The true maximum is defined by `Transaction::<N>::MAX_TRANSITIONS`, however, that object is not accessible in this crate.
 58          //  In practice, `MAX_DATA_DEPTH` is 32, while `MAX_TRANSITIONS` is 31.
 59          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          // Parse the whitespace and comments from the string.
 65          let (string, _) = Sanitizer::parse(string)?;
 66          // Parse the "{" from the string.
 67          let (string, _) = tag("{")(string)?;
 68  
 69          // Parse the whitespace and comments from the string.
 70          let (string, _) = Sanitizer::parse(string)?;
 71          // Parse the "program_id" from the string.
 72          let (string, _) = tag("program_id")(string)?;
 73          // Parse the whitespace from the string.
 74          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 75          // Parse the ":" from the string.
 76          let (string, _) = tag(":")(string)?;
 77          // Parse the whitespace from the string.
 78          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 79          // Parse the program ID from the string.
 80          let (string, program_id) = ProgramID::parse(string)?;
 81          // Parse the whitespace from the string.
 82          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 83          // Parse the "," from the string.
 84          let (string, _) = tag(",")(string)?;
 85  
 86          // Parse the whitespace and comments from the string.
 87          let (string, _) = Sanitizer::parse(string)?;
 88          // Parse the "function_name" from the string.
 89          let (string, _) = tag("function_name")(string)?;
 90          // Parse the whitespace from the string.
 91          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 92          // Parse the ":" from the string.
 93          let (string, _) = tag(":")(string)?;
 94          // Parse the whitespace from the string.
 95          let (string, _) = Sanitizer::parse_whitespaces(string)?;
 96          // Parse the function name from the string.
 97          let (string, function_name) = Identifier::parse(string)?;
 98          // Parse the whitespace from the string.
 99          let (string, _) = Sanitizer::parse_whitespaces(string)?;
100          // Parse the "," from the string.
101          let (string, _) = tag(",")(string)?;
102  
103          // Parse the whitespace and comments from the string.
104          let (string, _) = Sanitizer::parse(string)?;
105          // Parse the "arguments" from the string.
106          let (string, _) = tag("arguments")(string)?;
107          // Parse the whitespace from the string.
108          let (string, _) = Sanitizer::parse_whitespaces(string)?;
109          // Parse the ":" from the string.
110          let (string, _) = tag(":")(string)?;
111          // Parse the whitespace from the string.
112          let (string, _) = Sanitizer::parse_whitespaces(string)?;
113          // Parse the arguments from the string.
114          let (string, arguments) = Self::parse_arguments(string, depth)?;
115  
116          // Parse the whitespace and comments from the string.
117          let (string, _) = Sanitizer::parse(string)?;
118          // Parse the "}" from the string.
119          let (string, _) = tag("}")(string)?;
120  
121          Ok((string, Self::new(program_id, function_name, arguments)))
122      }
123  }
124  
125  impl<N: Network> FromStr for Future<N> {
126      type Err = Error;
127  
128      /// Returns a future from a string literal.
129      fn from_str(string: &str) -> Result<Self> {
130          match Self::parse(string) {
131              Ok((remainder, object)) => {
132                  // Ensure the remainder is empty.
133                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
134                  // Return the object.
135                  Ok(object)
136              }
137              Err(error) => bail!("Failed to parse string. {error}"),
138          }
139      }
140  }
141  
142  impl<N: Network> Debug for Future<N> {
143      /// Prints the future as a string.
144      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
145          Display::fmt(self, f)
146      }
147  }
148  
149  impl<N: Network> Display for Future<N> {
150      /// Prints the future as a string.
151      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
152          self.fmt_internal(f, 0)
153      }
154  }
155  
156  impl<N: Network> Future<N> {
157      /// Prints the future with the given indentation depth.
158      fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
159          /// The number of spaces to indent.
160          const INDENT: usize = 2;
161  
162          // Print the opening brace.
163          write!(f, "{{")?;
164  
165          // Print the program ID.
166          write!(
167              f,
168              "\n{:indent$}program_id: {program_id},",
169              "",
170              indent = (depth + 1) * INDENT,
171              program_id = self.program_id()
172          )?;
173          // Print the function name.
174          write!(
175              f,
176              "\n{:indent$}function_name: {function_name},",
177              "",
178              indent = (depth + 1) * INDENT,
179              function_name = self.function_name()
180          )?;
181          // Print the arguments.
182          // If the arguments are empty, print an empty array.
183          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                              // Print the last argument without a comma.
192                              write!(
193                                  f,
194                                  "\n{:indent$}{plaintext}",
195                                  "",
196                                  indent = (depth + 2) * INDENT,
197                                  plaintext = plaintext
198                              )
199                          }
200                          // Print the argument with a comma.
201                          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                          // Print a newline.
213                          write!(f, "\n{:indent$}", "", indent = (depth + 2) * INDENT)?;
214                          // Print the argument.
215                          future.fmt_internal(f, depth + 2)?;
216                          // Print the closing brace.
217                          match i == self.arguments.len() - 1 {
218                              // Print the last member without a comma.
219                              true => write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT),
220                              // Print the member with a comma.
221                              false => write!(f, ","),
222                          }
223                      }
224                  }
225              })?;
226              // Print the closing bracket.
227              write!(f, "\n{:indent$}]", "", indent = (depth + 1) * INDENT)?;
228          }
229  
230          // Print the closing brace.
231          write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
232      }
233  }
234  
235  #[cfg(test)]
236  mod tests {
237      use super::*;
238      use alphavm_console_network::MainnetV0;
239  
240      type CurrentNetwork = MainnetV0;
241  
242      #[test]
243      fn test_parse_future() -> Result<()> {
244          // No argument case.
245          let expected = r"{
246    program_id: credits.alpha,
247    function_name: transfer,
248    arguments: []
249  }";
250          let (remainder, candidate) =
251              Future::<CurrentNetwork>::parse("{ program_id: credits.alpha, function_name: transfer, arguments: [] }")?;
252          assert!(remainder.is_empty());
253          assert_eq!(expected, candidate.to_string());
254          assert_eq!("", remainder);
255  
256          // Literal arguments.
257          let expected = r"{
258    program_id: credits.alpha,
259    function_name: transfer_public_to_private,
260    arguments: [
261      ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w,
262      100000000u64
263    ]
264  }";
265          let (remainder, candidate) = Future::<CurrentNetwork>::parse(
266              "{ program_id: credits.alpha, function_name: transfer_public_to_private, arguments: [ ax150w2lvhdzychwvzu54ys5zas7tm5s0ycdyw563pms83g9u0vucgqe5fs5w, 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          // A helper function to iteratively create a deeply nested future.
278          fn create_nested_future(depth: usize) -> String {
279              // Define the base case.
280              let root = r"{
281                  program_id: foo.alpha,
282                  function_name: bar,
283                  arguments: []
284              }";
285              // Define the prefix and suffix for the nested future.
286              let prefix = r"{
287                  program_id: foo.alpha,
288                  function_name: bar,
289                  arguments: ["
290                  .repeat(depth);
291              let suffix = r"]}".repeat(depth);
292              // Concatenate the prefix, root, and suffix to create the nested future.
293              format!("{prefix}{root}{suffix}")
294          }
295  
296          // A helper function to test the parsing of a deeply nested future.
297          fn run_test(depth: usize, expected_error: bool) {
298              // Create the nested future string.
299              let nested_future_string = create_nested_future(depth);
300              // Parse the nested future.
301              let result = Future::<CurrentNetwork>::parse(&nested_future_string);
302              // Check if the result is an error.
303              match expected_error {
304                  true => {
305                      assert!(result.is_err());
306                      return;
307                  }
308                  false => assert!(result.is_ok()),
309              };
310              // Unwrap the result.
311              let (remainder, candidate) = result.unwrap();
312              // Ensure the remainder is empty.
313              assert!(
314                  remainder.is_empty(),
315                  "Failed to parse deeply nested future. Found invalid character in: \"{remainder}\""
316              );
317              // Strip the expected string of whitespace.
318              let expected = nested_future_string.replace("\n", "").replace(" ", "").replace("\t", "");
319              // Strip the candidate string of whitespace.
320              let candidate_str = candidate.to_string().replace("\n", "").replace(" ", "").replace("\t", "");
321              // Ensure the expected and candidate strings are equal.
322              assert_eq!(expected, candidate_str, "Expected: {expected}, Candidate: {candidate_str}");
323          }
324  
325          // Initialize a set of depths to test.
326          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 each depth, test the parsing of a deeply nested future.
332          for depth in depths {
333              run_test(depth, depth > CurrentNetwork::MAX_DATA_DEPTH);
334          }
335      }
336  }