parse.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphavm library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 use super::*; 20 21 impl<E: Environment> Parser for StringType<E> { 22 /// Parses a string into a string type. 23 #[inline] 24 fn parse(string: &str) -> ParserResult<'_, Self> { 25 // Parse the starting and ending quote '"' keyword from the string. 26 let (string, value) = string_parser::parse_string(string)?; 27 28 Ok((string, StringType::new(&value))) 29 } 30 } 31 32 impl<E: Environment> FromStr for StringType<E> { 33 type Err = Error; 34 35 /// Parses a string into a string type. 36 #[inline] 37 fn from_str(string: &str) -> Result<Self> { 38 match Self::parse(string) { 39 Ok((remainder, object)) => { 40 // Ensure the remainder is empty. 41 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 42 // Return the object. 43 Ok(object) 44 } 45 Err(error) => bail!("Failed to parse string. {error}"), 46 } 47 } 48 } 49 50 impl<E: Environment> Debug for StringType<E> { 51 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 52 Display::fmt(self, f) 53 } 54 } 55 56 impl<E: Environment> Display for StringType<E> { 57 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 58 write!(f, "\"{}\"", self.string) 59 } 60 } 61 62 #[cfg(test)] 63 mod tests { 64 use super::*; 65 use alphavm_console_network_environment::Console; 66 67 type CurrentEnvironment = Console; 68 69 const ITERATIONS: u32 = 100; 70 71 #[test] 72 fn test_display() -> Result<()> { 73 // Ensure type and empty value fails. 74 assert!(StringType::<CurrentEnvironment>::parse(StringType::<CurrentEnvironment>::type_name()).is_err()); 75 assert!(StringType::<CurrentEnvironment>::parse("").is_err()); 76 77 // Ensure empty string succeeds. 78 assert!(StringType::<CurrentEnvironment>::parse("\"\"").is_ok()); 79 80 let rng = &mut TestRng::default(); 81 82 for _ in 0..ITERATIONS { 83 // Sample a random string. Take 1/4th to ensure we fit for all code points. 84 let expected = rng.next_string(CurrentEnvironment::MAX_STRING_BYTES / 4, false); 85 let expected_num_bytes = expected.len(); 86 assert!(expected_num_bytes <= CurrentEnvironment::MAX_STRING_BYTES as usize); 87 88 let candidate = StringType::<CurrentEnvironment>::new(&expected); 89 assert_eq!(format!("\"{expected}\""), format!("{candidate}")); 90 91 let candidate_recovered = StringType::<CurrentEnvironment>::from_str(&format!("{candidate}")).unwrap(); 92 assert_eq!(candidate, candidate_recovered); 93 } 94 Ok(()) 95 } 96 97 #[test] 98 fn test_parse_unsupported_code_points() -> Result<()> { 99 const UNSUPPORTED_CODE_POINTS: [&str; 9] = [ 100 "\u{202a}", "\u{202b}", "\u{202c}", "\u{202d}", "\u{202e}", "\u{2066}", "\u{2067}", "\u{2068}", "\u{2069}", 101 ]; 102 103 // Ensure that the invalid code point is not allowed in the string. 104 for unsupported_code_point in UNSUPPORTED_CODE_POINTS { 105 assert!(StringType::<CurrentEnvironment>::parse(unsupported_code_point).is_err()); 106 } 107 108 Ok(()) 109 } 110 }