1use super::*;
17
18impl<N: Network> Parser for Record<N, Plaintext<N>> {
19 #[inline]
21 fn parse(string: &str) -> ParserResult<Self> {
22 #[allow(clippy::type_complexity)]
24 fn parse_pair<N: Network>(string: &str) -> ParserResult<(Identifier<N>, Entry<N, Plaintext<N>>)> {
25 let (string, _) = Sanitizer::parse(string)?;
27 let (string, identifier) = Identifier::parse(string)?;
29 let (string, _) = Sanitizer::parse_whitespaces(string)?;
31 let (string, _) = tag(":")(string)?;
33 let (string, _) = Sanitizer::parse(string)?;
35 let (string, entry) = Entry::parse(string)?;
37 let (string, _) = Sanitizer::parse_whitespaces(string)?;
39 Ok((string, (identifier, entry)))
41 }
42
43 let (string, _) = Sanitizer::parse(string)?;
45 let (string, _) = tag("{")(string)?;
47
48 let (string, _) = Sanitizer::parse(string)?;
50 let (string, _) = tag("owner")(string)?;
52 let (string, _) = Sanitizer::parse_whitespaces(string)?;
54 let (string, _) = tag(":")(string)?;
56 let (string, _) = Sanitizer::parse(string)?;
58 let (string, owner) = alt((
60 map(pair(Address::parse, tag(".public")), |(owner, _)| Owner::Public(owner)),
61 map(pair(Address::parse, tag(".private")), |(owner, _)| {
62 Owner::Private(Plaintext::from(Literal::Address(owner)))
63 }),
64 ))(string)?;
65 let (string, _) = tag(",")(string)?;
67
68 let (string, entries) = map_res(separated_list0(tag(","), parse_pair), |entries: Vec<_>| {
70 let reserved = [Identifier::from_str("owner").map_err(|e| error(e.to_string()))?];
72 if has_duplicates(entries.iter().map(|(identifier, _)| identifier).chain(reserved.iter())) {
74 return Err(error("Duplicate entry type found in record"));
75 }
76 match entries.len() <= N::MAX_DATA_ENTRIES {
78 true => Ok(entries),
79 false => Err(error(format!("Found a record that exceeds size ({})", entries.len()))),
80 }
81 })(string)?;
82
83 let string = match !entries.is_empty() {
85 true => tag(",")(string)?.0,
87 false => string,
88 };
89
90 let (string, _) = Sanitizer::parse(string)?;
92 let (string, _) = tag("_nonce")(string)?;
94 let (string, _) = tag(":")(string)?;
96 let (string, _) = Sanitizer::parse(string)?;
98 let (string, (nonce, _)) = pair(Group::parse, tag(".public"))(string)?;
100
101 let string = match opt(tag(","))(string)? {
103 (string, Some(_)) => string,
105 (string, None) => string,
107 };
108
109 let (string, _) = Sanitizer::parse(string)?;
111 let (string, version) = match opt(tag("_version"))(string)? {
113 (string, None) => (string, U8::zero()),
115 (string, Some(_)) => {
117 let (string, _) = Sanitizer::parse(string)?;
119 let (string, _) = tag(":")(string)?;
121 let (string, _) = Sanitizer::parse(string)?;
123 terminated(U8::parse, tag(".public"))(string)?
125 }
126 };
127
128 let (string, _) = Sanitizer::parse(string)?;
130 let (string, _) = tag("}")(string)?;
132 Ok((string, Record { owner, data: IndexMap::from_iter(entries), nonce, version }))
134 }
135}
136
137impl<N: Network> FromStr for Record<N, Plaintext<N>> {
138 type Err = Error;
139
140 fn from_str(string: &str) -> Result<Self> {
142 match Self::parse(string) {
143 Ok((remainder, object)) => {
144 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
146 Ok(object)
148 }
149 Err(error) => bail!("Failed to parse string. {error}"),
150 }
151 }
152}
153
154impl<N: Network> Debug for Record<N, Plaintext<N>> {
155 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
157 Display::fmt(self, f)
158 }
159}
160
161impl<N: Network> Display for Record<N, Plaintext<N>> {
162 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
164 self.fmt_internal(f, 0)
165 }
166}
167
168impl<N: Network> Record<N, Plaintext<N>> {
169 fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
171 const INDENT: usize = 2;
173
174 write!(f, "{{")?;
176 write!(f, "\n{:indent$}owner: {},", "", self.owner, indent = (depth + 1) * INDENT)?;
178 for (identifier, entry) in self.data.iter() {
180 write!(f, "\n{:indent$}{identifier}: ", "", indent = (depth + 1) * INDENT)?;
182 match entry {
184 Entry::Constant(Plaintext::Literal(..))
186 | Entry::Public(Plaintext::Literal(..))
187 | Entry::Private(Plaintext::Literal(..)) => write!(f, "{entry}")?,
188 Entry::Constant(Plaintext::Struct(..))
190 | Entry::Public(Plaintext::Struct(..))
191 | Entry::Private(Plaintext::Struct(..))
192 | Entry::Constant(Plaintext::Array(..))
193 | Entry::Public(Plaintext::Array(..))
194 | Entry::Private(Plaintext::Array(..)) => entry.fmt_internal(f, depth + 1)?,
195 }
196 write!(f, ",")?;
198 }
199 write!(f, "\n{:indent$}_nonce: {}.public,", "", self.nonce, indent = (depth + 1) * INDENT)?;
201 write!(f, "\n{:indent$}_version: {}.public", "", self.version, indent = (depth + 1) * INDENT)?;
203 write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use snarkvm_console_network::MainnetV0;
212
213 type CurrentNetwork = MainnetV0;
214
215 #[test]
216 fn test_parse_without_version() -> Result<()> {
217 let expected = r"{
219 owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private,
220 _nonce: 0group.public,
221 _version: 0u8.public
222}";
223 let given =
224 "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private, _nonce: 0group.public }";
225 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
226 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
227 assert_eq!(expected, candidate.to_string());
228 assert_eq!("", remainder);
229 Ok(())
230 }
231
232 #[test]
233 fn test_parse_with_version() -> Result<()> {
234 let expected = r"{
236 owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private,
237 _nonce: 0group.public,
238 _version: 0u8.public
239}";
240 let given = "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private, _nonce: 0group.public, _version: 0u8.public }";
241 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
242 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
243 assert_eq!(expected, candidate.to_string());
244 assert_eq!("", remainder);
245
246 let expected = r"{
248 owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private,
249 _nonce: 0group.public,
250 _version: 1u8.public
251}";
252 let given = "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private, _nonce: 0group.public, _version: 1u8.public }";
253 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
254 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
255 assert_eq!(expected, candidate.to_string());
256 assert_eq!("", remainder);
257 Ok(())
258 }
259
260 #[test]
261 fn test_parse_without_data_entries() -> Result<()> {
262 let expected = r"{
264 owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private,
265 _nonce: 0group.public,
266 _version: 0u8.public
267}";
268 let given =
269 "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.private, _nonce: 0group.public }";
270 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
271 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
272 assert_eq!(expected, candidate.to_string());
273 assert_eq!("", remainder);
274 Ok(())
275 }
276
277 #[test]
278 fn test_parse_with_literal_entry() -> Result<()> {
279 let expected = r"{
280 owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.public,
281 foo: 5u8.constant,
282 _nonce: 0group.public,
283 _version: 0u8.public
284}";
285 let given = "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.public, foo: 5u8.constant, _nonce: 0group.public }";
286 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(given)?;
287 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
288 assert_eq!(expected, candidate.to_string());
289 assert_eq!("", remainder);
290 Ok(())
291 }
292
293 #[test]
294 fn test_parse_with_struct_entry() -> Result<()> {
295 let expected = r"{
296 owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.public,
297 foo: 5u8.public,
298 bar: {
299 baz: 6u8.constant,
300 qux: 7u8.constant
301 },
302 quux: 8u8.private,
303 corge: {
304 grault: 9u8.constant,
305 garply: {
306 waldo: 10u8.constant,
307 fred: 11u8.constant
308 }
309 },
310 xyzzy: {
311 thud: 12u8.public
312 },
313 _nonce: 2293253577170800572742339369209137467208538700597121244293392265726446806023group.public,
314 _version: 0u8.public
315}";
316 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
317 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
318 assert_eq!(expected, candidate.to_string());
319 assert_eq!("", remainder);
320
321 let expected = r"{
322 owner: aleo1lhcpfumagern97esytsgdva2ytme043zydlzyprhejsd0gw5vypqqz0zkw.private,
323 foo: {
324 bar: 0u128.private
325 },
326 baz: {
327 quine: {
328 flop: 0u64.private
329 },
330 slice: 0u16.private,
331 flag: true.private,
332 square: {
333 first: 0u128.private,
334 second: 1u128.private,
335 third: 2u128.private,
336 fourth: 3u128.private
337 }
338 },
339 _nonce: 0group.public,
340 _version: 0u8.public
341}";
342 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
343 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
344 assert_eq!(expected, candidate.to_string());
345 assert_eq!("", remainder);
346
347 let expected = r"{
348 owner: aleo18ttcegpydcs95yw4je0u400j3u7r26yqr9h8evqps3qa9slrvyrsqjwt9l.private,
349 c: {
350 c: {
351 a: 0u8.private,
352 b: 1u8.private
353 },
354 d: {
355 a: 0u8.private,
356 b: 1u8.private
357 }
358 },
359 d: {
360 c: {
361 a: 0u8.private,
362 b: 1u8.private
363 },
364 d: {
365 a: 0u8.private,
366 b: 1u8.private
367 }
368 },
369 _nonce: 8102307625287186026775464343238779600702564007094834161216556016558567413871group.public,
370 _version: 0u8.public
371}";
372 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
373 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
374 assert_eq!(expected, candidate.to_string());
375 assert_eq!("", remainder);
376
377 Ok(())
378 }
379
380 #[test]
381 fn test_parse_with_array_entry() -> Result<()> {
382 let expected = r"{
383 owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.public,
384 foo: 5u8.public,
385 bar: [
386 6u8.private,
387 7u8.private,
388 8u8.private
389 ],
390 _nonce: 0group.public,
391 _version: 0u8.public
392}";
393 let (remainder, candidate) = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(expected)?;
394 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
395 assert_eq!(expected, candidate.to_string());
396 assert_eq!("", remainder);
397 Ok(())
398 }
399
400 #[test]
401 fn test_parse_fails() -> Result<()> {
402 let expected = "{ foo: 5u8.private, _nonce: 0group.public }";
404 assert!(Plaintext::<CurrentNetwork>::parse(expected).is_err());
405
406 let expected =
408 "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah.public, foo: 5u8.private }";
409 assert!(Plaintext::<CurrentNetwork>::parse(expected).is_err());
410
411 let expected = r"{
413 owner: aleo14tlamssdmg3d0p5zmljma573jghe2q9n6wz29qf36re2glcedcpqfg4add.private,
414 a: true.private,
415 b: 123456789field.private,
416 c: 0group.private,
417 d: {
418 e: true.private,
419 f: 123456789field.public,
420 g: 0group.private
421 },
422 _nonce: 0group.public,
423 _version: 0u8.public
424}";
425 assert!(Plaintext::<CurrentNetwork>::parse(expected).is_err());
426 Ok(())
427 }
428}