parse.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the deltavm 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 Group<E> { 19 /// Parses a string into a group 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 group from the string. 27 let (string, group): (&str, Self) = map_res(tag(Self::type_name()), |_| { 28 let x_coordinate = primitive.replace('_', "").parse()?; 29 // Recover and negate the group element if the negative sign was present. 30 match negation { 31 true => Ok(-Group::from_x_coordinate(Field::new(x_coordinate))?), 32 false => Group::from_x_coordinate(Field::new(x_coordinate)), 33 } 34 })(string)?; 35 36 Ok((string, group)) 37 } 38 } 39 40 impl<E: Environment> FromStr for Group<E> { 41 type Err = Error; 42 43 /// Parses a string into a group. 44 #[inline] 45 fn from_str(string: &str) -> Result<Self> { 46 match Self::parse(string) { 47 Ok((remainder, object)) => { 48 // Ensure the remainder is empty. 49 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 50 // Return the object. 51 Ok(object) 52 } 53 Err(error) => bail!("Failed to parse string. {error}"), 54 } 55 } 56 } 57 58 impl<E: Environment> Debug for Group<E> { 59 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 60 Display::fmt(self, f) 61 } 62 } 63 64 impl<E: Environment> Display for Group<E> { 65 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 66 write!(f, "{}{}", self.group.to_affine().to_x_coordinate(), Self::type_name()) 67 } 68 } 69 70 #[cfg(test)] 71 mod tests { 72 use super::*; 73 use deltavm_console_network_environment::Console; 74 75 type CurrentEnvironment = Console; 76 77 const ITERATIONS: u64 = 1_000; 78 79 #[test] 80 fn test_parse() -> Result<()> { 81 let rng = &mut TestRng::default(); 82 83 // Ensure empty value fails. 84 assert!(Group::<CurrentEnvironment>::parse(Group::<CurrentEnvironment>::type_name()).is_err()); 85 assert!(Group::<CurrentEnvironment>::parse("").is_err()); 86 87 for _ in 0..ITERATIONS { 88 // Sample a random value. 89 let group: <CurrentEnvironment as Environment>::Affine = Uniform::rand(rng); 90 91 let expected = format!("{}{}", group.to_x_coordinate(), Group::<CurrentEnvironment>::type_name()); 92 let (remainder, candidate) = Group::<CurrentEnvironment>::parse(&expected).unwrap(); 93 assert_eq!(format!("{expected}"), candidate.to_string()); 94 assert_eq!("", remainder); 95 } 96 Ok(()) 97 } 98 99 #[test] 100 fn test_display() { 101 /// Attempts to construct a group from the given element, 102 /// format it in display mode, and recover a group from it. 103 fn check_display<E: Environment>(element: E::Affine) { 104 let candidate = Group::<E>::new(element); 105 assert_eq!(format!("{}{}", element.to_x_coordinate(), Group::<E>::type_name()), format!("{candidate}")); 106 107 let candidate_recovered = Group::<E>::from_str(&format!("{candidate}")).unwrap(); 108 assert_eq!(candidate, candidate_recovered); 109 } 110 111 let mut rng = TestRng::default(); 112 113 for _ in 0..ITERATIONS { 114 let element = Uniform::rand(&mut rng); 115 116 check_display::<CurrentEnvironment>(element); 117 } 118 } 119 120 #[test] 121 fn test_display_zero() { 122 let zero = <CurrentEnvironment as Environment>::Affine::zero(); 123 124 let candidate = Group::<CurrentEnvironment>::new(zero); 125 assert_eq!("0group", &format!("{candidate}")); 126 } 127 }