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<N: Network> Parser for RegisterType<N> { 19 /// Parses a string into a register type. 20 #[inline] 21 fn parse(string: &str) -> ParserResult<Self> { 22 // Parse the mode from the string (ordering matters). 23 alt(( 24 map(pair(Locator::parse, tag(".future")), |(locator, _)| Self::Future(locator)), 25 map(pair(Locator::parse, tag(".record")), |(locator, _)| Self::ExternalRecord(locator)), 26 map(pair(Identifier::parse, tag(".record")), |(identifier, _)| Self::Record(identifier)), 27 map(PlaintextType::parse, |plaintext_type| Self::Plaintext(plaintext_type)), 28 ))(string) 29 } 30 } 31 32 impl<N: Network> FromStr for RegisterType<N> { 33 type Err = Error; 34 35 /// Returns a register type from a string literal. 36 fn from_str(string: &str) -> Result<Self> { 37 match Self::parse(string) { 38 Ok((remainder, object)) => { 39 // Ensure the remainder is empty. 40 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\""); 41 // Return the object. 42 Ok(object) 43 } 44 Err(error) => bail!("Failed to parse string. {error}"), 45 } 46 } 47 } 48 49 impl<N: Network> Debug for RegisterType<N> { 50 /// Prints the register type as a string. 51 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 52 Display::fmt(self, f) 53 } 54 } 55 56 impl<N: Network> Display for RegisterType<N> { 57 /// Prints the register type as a string. 58 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 59 match self { 60 // Prints the plaintext type, i.e. signature 61 Self::Plaintext(plaintext_type) => write!(f, "{plaintext_type}"), 62 // Prints the record name, i.e. token.record 63 Self::Record(record_name) => write!(f, "{record_name}.record"), 64 // Prints the locator, i.e. token.alpha/token.record 65 Self::ExternalRecord(locator) => write!(f, "{locator}.record"), 66 // Prints the future type, i.e. future 67 Self::Future(locator) => write!(f, "{locator}.future"), 68 } 69 } 70 } 71 72 #[cfg(test)] 73 mod tests { 74 use super::*; 75 use alphavm_console_network::MainnetV0; 76 77 type CurrentNetwork = MainnetV0; 78 79 #[test] 80 fn test_parse() -> Result<()> { 81 // Literal type. 82 assert_eq!( 83 Ok(("", RegisterType::<CurrentNetwork>::Plaintext(PlaintextType::from_str("field")?))), 84 RegisterType::<CurrentNetwork>::parse("field") 85 ); 86 87 // Struct type. 88 assert_eq!( 89 Ok(("", RegisterType::<CurrentNetwork>::Plaintext(PlaintextType::from_str("signature")?))), 90 RegisterType::<CurrentNetwork>::parse("signature") 91 ); 92 assert_eq!( 93 Ok(("", RegisterType::<CurrentNetwork>::Plaintext(PlaintextType::from_str("u8kldsafj")?))), 94 RegisterType::<CurrentNetwork>::parse("u8kldsafj") 95 ); 96 97 // Record type. 98 assert_eq!( 99 Ok(("", RegisterType::<CurrentNetwork>::Record(Identifier::from_str("token")?))), 100 RegisterType::<CurrentNetwork>::parse("token.record") 101 ); 102 103 // ExternalRecord type. 104 assert_eq!( 105 Ok(("", RegisterType::<CurrentNetwork>::ExternalRecord(Locator::from_str("token.alpha/token")?))), 106 RegisterType::<CurrentNetwork>::parse("token.alpha/token.record") 107 ); 108 109 Ok(()) 110 } 111 112 #[test] 113 fn test_parse_fails() -> Result<()> { 114 // Must be non-empty. 115 assert!(RegisterType::<CurrentNetwork>::parse("").is_err()); 116 117 // Invalid characters. 118 assert!(RegisterType::<CurrentNetwork>::parse("{}").is_err()); 119 assert!(RegisterType::<CurrentNetwork>::parse("_").is_err()); 120 assert!(RegisterType::<CurrentNetwork>::parse("__").is_err()); 121 assert!(RegisterType::<CurrentNetwork>::parse("___").is_err()); 122 assert!(RegisterType::<CurrentNetwork>::parse("-").is_err()); 123 assert!(RegisterType::<CurrentNetwork>::parse("--").is_err()); 124 assert!(RegisterType::<CurrentNetwork>::parse("---").is_err()); 125 assert!(RegisterType::<CurrentNetwork>::parse("*").is_err()); 126 assert!(RegisterType::<CurrentNetwork>::parse("**").is_err()); 127 assert!(RegisterType::<CurrentNetwork>::parse("***").is_err()); 128 129 // Must not start with a number. 130 assert!(RegisterType::<CurrentNetwork>::parse("1").is_err()); 131 assert!(RegisterType::<CurrentNetwork>::parse("2").is_err()); 132 assert!(RegisterType::<CurrentNetwork>::parse("3").is_err()); 133 assert!(RegisterType::<CurrentNetwork>::parse("1foo").is_err()); 134 assert!(RegisterType::<CurrentNetwork>::parse("12").is_err()); 135 assert!(RegisterType::<CurrentNetwork>::parse("111").is_err()); 136 137 // Must fit within the data capacity of a base field element. 138 let struct_ = RegisterType::<CurrentNetwork>::parse( 139 "foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy.private", 140 ); 141 assert!(struct_.is_err()); 142 143 Ok(()) 144 } 145 146 #[test] 147 fn test_display() -> Result<()> { 148 assert_eq!(RegisterType::<CurrentNetwork>::from_str("field")?.to_string(), "field"); 149 assert_eq!(RegisterType::<CurrentNetwork>::from_str("signature")?.to_string(), "signature"); 150 assert_eq!(RegisterType::<CurrentNetwork>::from_str("token.record")?.to_string(), "token.record"); 151 assert_eq!( 152 RegisterType::<CurrentNetwork>::from_str("token.alpha/token.record")?.to_string(), 153 "token.alpha/token.record" 154 ); 155 Ok(()) 156 } 157 }