/ console / types / string / src / 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<E: Environment> Parser for StringType<E> {
 19      /// Parses a string into a string type.
 20      #[inline]
 21      fn parse(string: &str) -> ParserResult<Self> {
 22          // Parse the starting and ending quote '"' keyword from the string.
 23          let (string, value) = string_parser::parse_string(string)?;
 24  
 25          Ok((string, StringType::new(&value)))
 26      }
 27  }
 28  
 29  impl<E: Environment> FromStr for StringType<E> {
 30      type Err = Error;
 31  
 32      /// Parses a string into a string type.
 33      #[inline]
 34      fn from_str(string: &str) -> Result<Self> {
 35          match Self::parse(string) {
 36              Ok((remainder, object)) => {
 37                  // Ensure the remainder is empty.
 38                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
 39                  // Return the object.
 40                  Ok(object)
 41              }
 42              Err(error) => bail!("Failed to parse string. {error}"),
 43          }
 44      }
 45  }
 46  
 47  impl<E: Environment> Debug for StringType<E> {
 48      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 49          Display::fmt(self, f)
 50      }
 51  }
 52  
 53  impl<E: Environment> Display for StringType<E> {
 54      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 55          write!(f, "\"{}\"", self.string)
 56      }
 57  }
 58  
 59  #[cfg(test)]
 60  mod tests {
 61      use super::*;
 62      use alphavm_console_network_environment::Console;
 63  
 64      type CurrentEnvironment = Console;
 65  
 66      const ITERATIONS: u32 = 100;
 67  
 68      #[test]
 69      fn test_display() -> Result<()> {
 70          // Ensure type and empty value fails.
 71          assert!(StringType::<CurrentEnvironment>::parse(StringType::<CurrentEnvironment>::type_name()).is_err());
 72          assert!(StringType::<CurrentEnvironment>::parse("").is_err());
 73  
 74          // Ensure empty string succeeds.
 75          assert!(StringType::<CurrentEnvironment>::parse("\"\"").is_ok());
 76  
 77          let rng = &mut TestRng::default();
 78  
 79          for _ in 0..ITERATIONS {
 80              // Sample a random string. Take 1/4th to ensure we fit for all code points.
 81              let expected = rng.next_string(CurrentEnvironment::MAX_STRING_BYTES / 4, false);
 82              let expected_num_bytes = expected.len();
 83              assert!(expected_num_bytes <= CurrentEnvironment::MAX_STRING_BYTES as usize);
 84  
 85              let candidate = StringType::<CurrentEnvironment>::new(&expected);
 86              assert_eq!(format!("\"{expected}\""), format!("{candidate}"));
 87  
 88              let candidate_recovered = StringType::<CurrentEnvironment>::from_str(&format!("{candidate}")).unwrap();
 89              assert_eq!(candidate, candidate_recovered);
 90          }
 91          Ok(())
 92      }
 93  
 94      #[test]
 95      fn test_parse_unsupported_code_points() -> Result<()> {
 96          const UNSUPPORTED_CODE_POINTS: [&str; 9] = [
 97              "\u{202a}", "\u{202b}", "\u{202c}", "\u{202d}", "\u{202e}", "\u{2066}", "\u{2067}", "\u{2068}", "\u{2069}",
 98          ];
 99  
100          // Ensure that the invalid code point is not allowed in the string.
101          for unsupported_code_point in UNSUPPORTED_CODE_POINTS {
102              assert!(StringType::<CurrentEnvironment>::parse(unsupported_code_point).is_err());
103          }
104  
105          Ok(())
106      }
107  }