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 PlaintextType<N> {
 19      /// Parses a string into a plaintext type.
 20      #[inline]
 21      fn parse(string: &str) -> ParserResult<Self> {
 22          // Parse to determine the plaintext type (order matters).
 23          alt((
 24              map(ArrayType::parse, |type_| Self::Array(type_)),
 25              map(Identifier::parse, |identifier| Self::Struct(identifier)),
 26              map(LiteralType::parse, |type_| Self::Literal(type_)),
 27          ))(string)
 28      }
 29  }
 30  
 31  impl<N: Network> FromStr for PlaintextType<N> {
 32      type Err = Error;
 33  
 34      /// Returns a plaintext type from a string literal.
 35      fn from_str(string: &str) -> Result<Self> {
 36          match Self::parse(string) {
 37              Ok((remainder, object)) => {
 38                  // Ensure the remainder is empty.
 39                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
 40                  // Return the object.
 41                  Ok(object)
 42              }
 43              Err(error) => bail!("Failed to parse string. {error}"),
 44          }
 45      }
 46  }
 47  
 48  impl<N: Network> Debug for PlaintextType<N> {
 49      /// Prints the plaintext type as a string.
 50      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 51          Display::fmt(self, f)
 52      }
 53  }
 54  
 55  impl<N: Network> Display for PlaintextType<N> {
 56      /// Prints the plaintext type as a string.
 57      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 58          match self {
 59              // Prints the literal, i.e. field
 60              Self::Literal(literal) => Display::fmt(literal, f),
 61              // Prints the struct, i.e. signature
 62              Self::Struct(struct_) => Display::fmt(struct_, f),
 63              // Prints the array type, i.e. [field; 2u32]
 64              Self::Array(array) => Display::fmt(array, f),
 65          }
 66      }
 67  }
 68  
 69  #[cfg(test)]
 70  mod tests {
 71      use super::*;
 72      use alphavm_console_network::MainnetV0;
 73  
 74      type CurrentNetwork = MainnetV0;
 75  
 76      #[test]
 77      fn test_parse() -> Result<()> {
 78          assert_eq!(
 79              PlaintextType::parse("field"),
 80              Ok(("", PlaintextType::<CurrentNetwork>::Literal(LiteralType::Field)))
 81          );
 82          assert_eq!(
 83              PlaintextType::parse("signature"),
 84              Ok(("", PlaintextType::<CurrentNetwork>::Literal(LiteralType::Signature)))
 85          );
 86          assert_eq!(
 87              PlaintextType::parse("foo"),
 88              Ok(("", PlaintextType::<CurrentNetwork>::Struct(Identifier::from_str("foo")?)))
 89          );
 90          assert_eq!(
 91              PlaintextType::parse("u8jdsklaj"),
 92              Ok(("", PlaintextType::<CurrentNetwork>::Struct(Identifier::from_str("u8jdsklaj")?)))
 93          );
 94          assert_eq!(
 95              PlaintextType::parse("[field; 1u32]"),
 96              Ok(("", PlaintextType::<CurrentNetwork>::Array(ArrayType::from_str("[field; 1u32]")?)))
 97          );
 98          Ok(())
 99      }
100  
101      #[test]
102      fn test_parse_fails() -> Result<()> {
103          // Literal type must not contain visibility.
104          assert_eq!(
105              Ok((".constant", PlaintextType::<CurrentNetwork>::from_str("field")?)),
106              PlaintextType::<CurrentNetwork>::parse("field.constant")
107          );
108          assert_eq!(
109              Ok((".public", PlaintextType::<CurrentNetwork>::from_str("field")?)),
110              PlaintextType::<CurrentNetwork>::parse("field.public")
111          );
112          assert_eq!(
113              Ok((".private", PlaintextType::<CurrentNetwork>::from_str("field")?)),
114              PlaintextType::<CurrentNetwork>::parse("field.private")
115          );
116  
117          // Struct type must not contain visibility.
118          assert_eq!(
119              Ok((".constant", Identifier::<CurrentNetwork>::from_str("foo")?)),
120              Identifier::<CurrentNetwork>::parse("foo.constant")
121          );
122          assert_eq!(
123              Ok((".public", Identifier::<CurrentNetwork>::from_str("foo")?)),
124              Identifier::<CurrentNetwork>::parse("foo.public")
125          );
126          assert_eq!(
127              Ok((".private", Identifier::<CurrentNetwork>::from_str("foo")?)),
128              Identifier::<CurrentNetwork>::parse("foo.private")
129          );
130  
131          // Array type must not contain visibility.
132          assert_eq!(
133              Ok((".constant", PlaintextType::<CurrentNetwork>::from_str("[field; 1u32]")?)),
134              PlaintextType::<CurrentNetwork>::parse("[field; 1u32].constant")
135          );
136          assert_eq!(
137              Ok((".public", PlaintextType::<CurrentNetwork>::from_str("[field; 1u32]")?)),
138              PlaintextType::<CurrentNetwork>::parse("[field; 1u32].public")
139          );
140          assert_eq!(
141              Ok((".private", PlaintextType::<CurrentNetwork>::from_str("[field; 1u32]")?)),
142              PlaintextType::<CurrentNetwork>::parse("[field; 1u32].private")
143          );
144  
145          // Must be non-empty.
146          assert!(PlaintextType::<CurrentNetwork>::parse("").is_err());
147          assert!(PlaintextType::<CurrentNetwork>::parse("{}").is_err());
148  
149          // Invalid characters.
150          assert!(PlaintextType::<CurrentNetwork>::parse("_").is_err());
151          assert!(PlaintextType::<CurrentNetwork>::parse("__").is_err());
152          assert!(PlaintextType::<CurrentNetwork>::parse("___").is_err());
153          assert!(PlaintextType::<CurrentNetwork>::parse("-").is_err());
154          assert!(PlaintextType::<CurrentNetwork>::parse("--").is_err());
155          assert!(PlaintextType::<CurrentNetwork>::parse("---").is_err());
156          assert!(PlaintextType::<CurrentNetwork>::parse("*").is_err());
157          assert!(PlaintextType::<CurrentNetwork>::parse("**").is_err());
158          assert!(PlaintextType::<CurrentNetwork>::parse("***").is_err());
159  
160          // Must not start with a number.
161          assert!(PlaintextType::<CurrentNetwork>::parse("1").is_err());
162          assert!(PlaintextType::<CurrentNetwork>::parse("2").is_err());
163          assert!(PlaintextType::<CurrentNetwork>::parse("3").is_err());
164          assert!(PlaintextType::<CurrentNetwork>::parse("1foo").is_err());
165          assert!(PlaintextType::<CurrentNetwork>::parse("12").is_err());
166          assert!(PlaintextType::<CurrentNetwork>::parse("111").is_err());
167  
168          // Struct types must fit within the data capacity of a base field element.
169          let struct_ = PlaintextType::<CurrentNetwork>::parse(
170              "foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy",
171          );
172          assert!(struct_.is_err());
173  
174          Ok(())
175      }
176  
177      #[test]
178      fn test_display() -> Result<()> {
179          assert_eq!(PlaintextType::<CurrentNetwork>::Literal(LiteralType::Boolean).to_string(), "boolean");
180          assert_eq!(PlaintextType::<CurrentNetwork>::Literal(LiteralType::Field).to_string(), "field");
181          assert_eq!(PlaintextType::<CurrentNetwork>::Literal(LiteralType::Signature).to_string(), "signature");
182          assert_eq!(PlaintextType::<CurrentNetwork>::Struct(Identifier::from_str("foo")?).to_string(), "foo");
183          assert_eq!(PlaintextType::<CurrentNetwork>::Struct(Identifier::from_str("bar")?).to_string(), "bar");
184          assert_eq!(
185              PlaintextType::<CurrentNetwork>::Array(ArrayType::from_str("[field; 8u32]")?).to_string(),
186              "[field; 8u32]"
187          );
188          Ok(())
189      }
190  }