snarkvm_console_types_field/
parse.rs

1// Copyright (c) 2019-2025 Provable Inc.
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 Field<E> {
19    /// Parses a string into a field circuit.
20    #[inline]
21    fn parse(string: &str) -> ParserResult<Self> {
22        // Parse the optional negative sign '-' from the string.
23        let (string, negation) = map(opt(tag("-")), |neg: Option<&str>| neg.is_some())(string)?;
24        // Parse the digits from the string.
25        let (string, primitive) = recognize(many1(terminated(one_of("0123456789"), many0(char('_')))))(string)?;
26        // Parse the value from the string.
27        let (string, value): (&str, E::Field) =
28            map_res(tag(Self::type_name()), |_| primitive.replace('_', "").parse())(string)?;
29        // Negate the value if the negative sign was present.
30        let value = match negation {
31            true => -value,
32            false => value,
33        };
34
35        Ok((string, Field::new(value)))
36    }
37}
38
39impl<E: Environment> FromStr for Field<E> {
40    type Err = Error;
41
42    /// Parses a string into a field.
43    #[inline]
44    fn from_str(string: &str) -> Result<Self> {
45        match Self::parse(string) {
46            Ok((remainder, object)) => {
47                // Ensure the remainder is empty.
48                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
49                // Return the object.
50                Ok(object)
51            }
52            Err(error) => bail!("Failed to parse string. {error}"),
53        }
54    }
55}
56
57impl<E: Environment> Debug for Field<E> {
58    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
59        Display::fmt(self, f)
60    }
61}
62
63impl<E: Environment> Display for Field<E> {
64    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
65        write!(f, "{}{}", self.field, Self::type_name())
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use snarkvm_console_network_environment::Console;
73
74    type CurrentEnvironment = Console;
75
76    const ITERATIONS: u64 = 10_000;
77
78    #[test]
79    fn test_parse() -> Result<()> {
80        let rng = &mut TestRng::default();
81
82        // Ensure empty value fails.
83        assert!(Field::<CurrentEnvironment>::parse(Field::<CurrentEnvironment>::type_name()).is_err());
84        assert!(Field::<CurrentEnvironment>::parse("").is_err());
85
86        for _ in 0..ITERATIONS {
87            // Sample a random value.
88            let field: <CurrentEnvironment as Environment>::Field = Uniform::rand(rng);
89
90            let expected = format!("{}{}", field, Field::<CurrentEnvironment>::type_name());
91            let (remainder, candidate) = Field::<CurrentEnvironment>::parse(&expected).unwrap();
92            assert_eq!(format!("{expected}"), candidate.to_string());
93            assert_eq!("", remainder);
94        }
95        Ok(())
96    }
97
98    #[test]
99    fn test_display() {
100        /// Attempts to construct a field from the given element,
101        /// format it in display mode, and recover a field from it.
102        fn check_display<E: Environment>(element: E::Field) {
103            let candidate = Field::<E>::new(element);
104            assert_eq!(format!("{element}{}", Field::<E>::type_name()), format!("{candidate}"));
105
106            let candidate_recovered = Field::<E>::from_str(&format!("{candidate}")).unwrap();
107            assert_eq!(candidate, candidate_recovered);
108        }
109
110        let mut rng = TestRng::default();
111
112        for _ in 0..ITERATIONS {
113            let element = Uniform::rand(&mut rng);
114
115            check_display::<CurrentEnvironment>(element);
116        }
117    }
118
119    #[test]
120    fn test_display_zero() {
121        let zero = <CurrentEnvironment as Environment>::Field::zero();
122
123        let candidate = Field::<CurrentEnvironment>::new(zero);
124        assert_eq!("0field", &format!("{candidate}"));
125    }
126
127    #[test]
128    fn test_display_one() {
129        let one = <CurrentEnvironment as Environment>::Field::one();
130
131        let candidate = Field::<CurrentEnvironment>::new(one);
132        assert_eq!("1field", &format!("{candidate}"));
133    }
134
135    #[test]
136    fn test_display_two() {
137        let one = <CurrentEnvironment as Environment>::Field::one();
138        let two = one + one;
139
140        let candidate = Field::<CurrentEnvironment>::new(two);
141        assert_eq!("2field", &format!("{candidate}"));
142    }
143}