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  }