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 }