snarkvm_console_types_string/
parse.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM 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
16use super::*;
17
18impl<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
29impl<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
47impl<E: Environment> Debug for StringType<E> {
48    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
49        Display::fmt(self, f)
50    }
51}
52
53impl<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)]
60mod tests {
61    use super::*;
62    use snarkvm_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}