snarkvm_console_program/data/access/
parse.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM 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
16use super::*;
17
18impl<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
27impl<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
45impl<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
52impl<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)]
65mod tests {
66    use super::*;
67    use snarkvm_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}