snarkvm_console_program/data/identifier/
parse.rs1use super::*;
17
18impl<N: Network> Parser for Identifier<N> {
19 #[inline]
26 fn parse(string: &str) -> ParserResult<Self> {
27 map_res(recognize(pair(alpha1, many0(alt((alphanumeric1, tag("_")))))), |identifier: &str| {
29 Self::from_str(identifier)
30 })(string)
31 }
32}
33
34impl<N: Network> FromStr for Identifier<N> {
35 type Err = Error;
36
37 fn from_str(identifier: &str) -> Result<Self, Self::Err> {
39 match identifier.chars().next() {
42 Some(character) => ensure!(character.is_ascii_alphabetic(), "Identifier must start with a letter"),
43 None => bail!("Identifier cannot be empty"),
44 }
45
46 if identifier.chars().any(|character| !character.is_ascii_alphanumeric() && character != '_') {
48 bail!("Identifier '{identifier}' must consist of letters, digits, and underscores")
49 }
50
51 let max_bytes = Field::<N>::size_in_data_bits() / 8; if identifier.len() > max_bytes {
54 bail!("Identifier is too large. Identifiers must be <= {max_bytes} bytes long")
55 }
56
57 ensure!(
59 !enum_iterator::all::<crate::LiteralType>().any(|lt| lt.type_name() == identifier),
60 "Identifier '{identifier}' is a reserved literal type"
61 );
62
63 Ok(Self(
66 Field::<N>::from_bits_le(&identifier.as_bytes().to_bits_le())?,
67 u8::try_from(identifier.len()).or_halt_with::<N>("Identifier `from_str` exceeds maximum length"),
68 ))
69 }
70}
71
72impl<N: Network> Debug for Identifier<N> {
73 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
74 Display::fmt(self, f)
75 }
76}
77
78impl<N: Network> Display for Identifier<N> {
79 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
81 let bytes = self.0.to_bytes_le().map_err(|_| fmt::Error)?;
83
84 let string = String::from_utf8(bytes).map_err(|_| fmt::Error)?;
86
87 match string.split('\0').next() {
89 Some(string) => match string.len() == self.1 as usize {
91 true => write!(f, "{string}"),
93 false => Err(fmt::Error),
94 },
95 None => Err(fmt::Error),
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103 use crate::data::identifier::tests::{sample_identifier, sample_identifier_as_string};
104 use snarkvm_console_network::MainnetV0;
105
106 type CurrentNetwork = MainnetV0;
107
108 const ITERATIONS: usize = 100;
109
110 #[test]
111 fn test_parse() -> Result<()> {
112 let (remainder, candidate) = Identifier::<CurrentNetwork>::parse("foo_bar1")?;
114 assert_eq!("foo_bar1", candidate.to_string());
115 assert_eq!("", remainder);
116
117 let (remainder, candidate) = Identifier::<CurrentNetwork>::parse("foo_bar~baz")?;
119 assert_eq!("foo_bar", candidate.to_string());
120 assert_eq!("~baz", remainder);
121
122 let (remainder, candidate) = Identifier::<CurrentNetwork>::parse("foo_bar-baz")?;
124 assert_eq!("foo_bar", candidate.to_string());
125 assert_eq!("-baz", remainder);
126
127 let mut rng = TestRng::default();
128
129 for _ in 0..ITERATIONS {
131 let expected_string = sample_identifier_as_string::<CurrentNetwork>(&mut rng)?;
133 let expected_field = Field::<CurrentNetwork>::from_bits_le(&expected_string.to_bits_le())?;
135
136 let (remainder, candidate) = Identifier::<CurrentNetwork>::parse(expected_string.as_str()).unwrap();
137 assert_eq!(expected_string, candidate.to_string());
138 assert_eq!(expected_field, candidate.0);
139 assert_eq!(expected_string.len(), candidate.1 as usize);
140 assert_eq!("", remainder);
141 }
142 Ok(())
143 }
144
145 #[test]
146 fn test_parse_fails() {
147 assert!(Identifier::<CurrentNetwork>::parse("_").is_err());
149 assert!(Identifier::<CurrentNetwork>::parse("__").is_err());
150 assert!(Identifier::<CurrentNetwork>::parse("___").is_err());
151 assert!(Identifier::<CurrentNetwork>::parse("____").is_err());
152
153 assert!(Identifier::<CurrentNetwork>::parse("1").is_err());
155 assert!(Identifier::<CurrentNetwork>::parse("2").is_err());
156 assert!(Identifier::<CurrentNetwork>::parse("3").is_err());
157 assert!(Identifier::<CurrentNetwork>::parse("1foo").is_err());
158 assert!(Identifier::<CurrentNetwork>::parse("12").is_err());
159 assert!(Identifier::<CurrentNetwork>::parse("111").is_err());
160
161 let identifier =
163 Identifier::<CurrentNetwork>::parse("foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy");
164 assert!(identifier.is_err());
165 }
166
167 #[test]
168 fn test_from_str() -> Result<()> {
169 let candidate = Identifier::<CurrentNetwork>::from_str("foo_bar").unwrap();
170 assert_eq!("foo_bar", candidate.to_string());
171
172 let mut rng = TestRng::default();
173
174 for _ in 0..ITERATIONS {
175 let expected_string = sample_identifier_as_string::<CurrentNetwork>(&mut rng)?;
177 let expected_field = Field::<CurrentNetwork>::from_bits_le(&expected_string.to_bits_le())?;
179
180 let candidate = Identifier::<CurrentNetwork>::from_str(&expected_string)?;
181 assert_eq!(expected_string, candidate.to_string());
182 assert_eq!(expected_field, candidate.0);
183 assert_eq!(expected_string.len(), candidate.1 as usize);
184 }
185 Ok(())
186 }
187
188 #[test]
189 fn test_from_str_fails() {
190 assert!(Identifier::<CurrentNetwork>::from_str("").is_err());
192
193 assert!(Identifier::<CurrentNetwork>::from_str("foo_bar~baz").is_err());
195 assert!(Identifier::<CurrentNetwork>::from_str("foo_bar-baz").is_err());
196
197 assert!(Identifier::<CurrentNetwork>::from_str("_").is_err());
199 assert!(Identifier::<CurrentNetwork>::from_str("__").is_err());
200 assert!(Identifier::<CurrentNetwork>::from_str("___").is_err());
201 assert!(Identifier::<CurrentNetwork>::from_str("____").is_err());
202
203 assert!(Identifier::<CurrentNetwork>::from_str("1").is_err());
205 assert!(Identifier::<CurrentNetwork>::from_str("2").is_err());
206 assert!(Identifier::<CurrentNetwork>::from_str("3").is_err());
207 assert!(Identifier::<CurrentNetwork>::from_str("1foo").is_err());
208 assert!(Identifier::<CurrentNetwork>::from_str("12").is_err());
209 assert!(Identifier::<CurrentNetwork>::from_str("111").is_err());
210
211 assert!(Identifier::<CurrentNetwork>::from_str("_foo").is_err());
213
214 assert!(Identifier::<CurrentNetwork>::from_str("\u{03b1}").is_err()); assert!(Identifier::<CurrentNetwork>::from_str("\u{03b2}").is_err()); let identifier = Identifier::<CurrentNetwork>::from_str(
220 "foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy",
221 );
222 assert!(identifier.is_err());
223 }
224
225 #[test]
226 fn test_display() -> Result<()> {
227 let identifier = Identifier::<CurrentNetwork>::from_str("foo_bar")?;
228 assert_eq!("foo_bar", format!("{identifier}"));
229 Ok(())
230 }
231
232 #[test]
233 fn test_proxy_bits_equivalence() -> Result<()> {
234 let mut rng = TestRng::default();
235 let identifier: Identifier<CurrentNetwork> = sample_identifier(&mut rng)?;
236
237 let bytes1 = identifier.0.to_bytes_le()?;
239
240 let bits_le = identifier.0.to_bits_le();
242 let bytes2 = bits_le.chunks(8).map(u8::from_bits_le).collect::<Result<Vec<u8>, _>>()?;
243
244 assert_eq!(bytes1, bytes2);
245
246 Ok(())
247 }
248}