/ console / program / src / data / access / parse.rs
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 Access<N> {
 19      fn parse(string: &str) -> ParserResult<Self> {
 20          alt((
 21              map(pair(tag("["), pair(U32::parse, tag("]"))), |(_, (index, _))| Self::Index(index)),
 22              map(pair(tag("."), Identifier::parse), |(_, identifier)| Self::Member(identifier)),
 23          ))(string)
 24      }
 25  }
 26  
 27  impl<N: Network> FromStr for Access<N> {
 28      type Err = Error;
 29  
 30      /// Parses an identifier into an access.
 31      #[inline]
 32      fn from_str(string: &str) -> Result<Self> {
 33          match Self::parse(string) {
 34              Ok((remainder, object)) => {
 35                  // Ensure the remainder is empty.
 36                  ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
 37                  // Return the object.
 38                  Ok(object)
 39              }
 40              Err(error) => bail!("Failed to parse string. {error}"),
 41          }
 42      }
 43  }
 44  
 45  impl<N: Network> Debug for Access<N> {
 46      /// Prints the access as a string.
 47      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 48          Display::fmt(self, f)
 49      }
 50  }
 51  
 52  impl<N: Network> Display for Access<N> {
 53      /// Prints the access as a string.
 54      fn fmt(&self, f: &mut Formatter) -> fmt::Result {
 55          match self {
 56              // Prints the access member, i.e. `.foo`
 57              Self::Member(identifier) => write!(f, ".{identifier}"),
 58              // Prints the access index, i.e. `[0u32]`
 59              Self::Index(index) => write!(f, "[{index}]"),
 60          }
 61      }
 62  }
 63  
 64  #[cfg(test)]
 65  mod tests {
 66      use super::*;
 67      use alphavm_console_network::MainnetV0;
 68  
 69      type CurrentNetwork = MainnetV0;
 70  
 71      #[test]
 72      fn test_parse() -> Result<()> {
 73          assert_eq!(Access::parse(".data"), Ok(("", Access::<CurrentNetwork>::Member(Identifier::from_str("data")?))));
 74          assert_eq!(Access::parse("[0u32]"), Ok(("", Access::<CurrentNetwork>::Index(U32::new(0)))));
 75          Ok(())
 76      }
 77  
 78      #[test]
 79      fn test_parse_fails() -> Result<()> {
 80          // Must be non-empty.
 81          assert!(Access::<CurrentNetwork>::parse("").is_err());
 82          assert!(Access::<CurrentNetwork>::parse(".").is_err());
 83          assert!(Access::<CurrentNetwork>::parse("[]").is_err());
 84  
 85          // Invalid accesses.
 86          assert!(Access::<CurrentNetwork>::parse(".0").is_err());
 87          assert!(Access::<CurrentNetwork>::parse("[index]").is_err());
 88          assert!(Access::<CurrentNetwork>::parse("[0.0]").is_err());
 89          assert!(Access::<CurrentNetwork>::parse("[999999999999]").is_err());
 90  
 91          // Must fit within the data capacity of a base field element.
 92          let access =
 93              Access::<CurrentNetwork>::parse(".foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy");
 94          assert!(access.is_err());
 95  
 96          Ok(())
 97      }
 98  
 99      #[test]
100      fn test_display() -> Result<()> {
101          assert_eq!(Access::<CurrentNetwork>::Member(Identifier::from_str("foo")?).to_string(), ".foo");
102          assert_eq!(Access::<CurrentNetwork>::Index(U32::new(0)).to_string(), "[0u32]");
103          Ok(())
104      }
105  }