1use super::*;
17
18impl<N: Network> Parser for Plaintext<N> {
19 #[inline]
21 fn parse(string: &str) -> ParserResult<Self> {
22 Self::parse_internal(string, 0)
24 }
25}
26
27impl<N: Network> Plaintext<N> {
28 fn parse_pair(string: &str, depth: usize) -> ParserResult<(Identifier<N>, Self)> {
30 let (string, _) = Sanitizer::parse(string)?;
32 let (string, identifier) = Identifier::parse(string)?;
34 let (string, _) = Sanitizer::parse_whitespaces(string)?;
36 let (string, _) = tag(":")(string)?;
38 let (string, plaintext) = Self::parse_internal(string, depth + 1)?;
40 let (string, _) = Sanitizer::parse_whitespaces(string)?;
42 Ok((string, (identifier, plaintext)))
44 }
45
46 fn parse_struct(string: &str, depth: usize) -> ParserResult<Self> {
48 let (string, _) = Sanitizer::parse(string)?;
50 let (string, _) = tag("{")(string)?;
52 let (string, members) =
54 map_res(separated_list1(tag(","), |input| Self::parse_pair(input, depth)), |members: Vec<_>| {
55 if has_duplicates(members.iter().map(|(name, ..)| name)) {
57 return Err(error("Duplicate member in struct"));
58 }
59 match members.len() <= N::MAX_STRUCT_ENTRIES {
61 true => Ok(members),
62 false => Err(error(format!("Found a plaintext that exceeds size ({})", members.len()))),
63 }
64 })(string)?;
65 let (string, _) = Sanitizer::parse(string)?;
67 let (string, _) = tag("}")(string)?;
69 Ok((string, Self::Struct(IndexMap::from_iter(members), Default::default())))
71 }
72
73 fn parse_array(string: &str, depth: usize) -> ParserResult<Self> {
75 let (string, _) = Sanitizer::parse(string)?;
77 let (string, _) = tag("[")(string)?;
79 let (string, members) = separated_list1(tag(","), |input| Self::parse_internal(input, depth + 1))(string)?;
81 let (string, _) = Sanitizer::parse(string)?;
83 let (string, _) = tag("]")(string)?;
85 Ok((string, Self::Array(members, Default::default())))
87 }
88
89 fn parse_internal(string: &str, depth: usize) -> ParserResult<Self> {
91 if depth > N::MAX_DATA_DEPTH {
93 return map_res(take(0usize), |_| {
94 Err(error(format!("Found a plaintext that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH)))
95 })(string);
96 }
97 let (string, _) = Sanitizer::parse(string)?;
99 alt((
102 map(Literal::parse, |literal| Self::Literal(literal, Default::default())),
104 |input| Self::parse_struct(input, depth),
106 |input| Self::parse_array(input, depth),
108 ))(string)
109 }
110}
111
112impl<N: Network> FromStr for Plaintext<N> {
113 type Err = Error;
114
115 fn from_str(string: &str) -> Result<Self> {
117 match Self::parse(string) {
118 Ok((remainder, object)) => {
119 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
121 Ok(object)
123 }
124 Err(error) => bail!("Failed to parse string. {error}"),
125 }
126 }
127}
128
129impl<N: Network> Debug for Plaintext<N> {
130 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
132 Display::fmt(self, f)
133 }
134}
135
136impl<N: Network> Display for Plaintext<N> {
137 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
139 self.fmt_internal(f, 0)
140 }
141}
142
143impl<N: Network> Plaintext<N> {
144 fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
146 const INDENT: usize = 2;
148
149 match self {
150 Self::Literal(literal, ..) => write!(f, "{:indent$}{literal}", "", indent = depth * INDENT),
152 Self::Struct(struct_, ..) => {
154 write!(f, "{{")?;
156 struct_.iter().enumerate().try_for_each(|(i, (name, plaintext))| {
158 match plaintext {
159 Self::Literal(literal, ..) => match i == struct_.len() - 1 {
160 true => {
161 write!(f, "\n{:indent$}{name}: {literal}", "", indent = (depth + 1) * INDENT)?;
163 write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
165 }
166 false => write!(f, "\n{:indent$}{name}: {literal},", "", indent = (depth + 1) * INDENT),
168 },
169 Self::Struct(..) | Self::Array(..) => {
170 write!(f, "\n{:indent$}{name}: ", "", indent = (depth + 1) * INDENT)?;
172 plaintext.fmt_internal(f, depth + 1)?;
174 match i == struct_.len() - 1 {
176 true => write!(f, "\n{:indent$}}}", "", indent = depth * INDENT),
178 false => write!(f, ","),
180 }
181 }
182 }
183 })
184 }
185 Self::Array(array, ..) => {
187 write!(f, "[")?;
189 array.iter().enumerate().try_for_each(|(i, plaintext)| {
191 match plaintext {
192 Self::Literal(literal, ..) => match i == array.len() - 1 {
193 true => {
194 write!(f, "\n{:indent$}{literal}", "", indent = (depth + 1) * INDENT)?;
196 write!(f, "\n{:indent$}]", "", indent = depth * INDENT)
198 }
199 false => write!(f, "\n{:indent$}{literal},", "", indent = (depth + 1) * INDENT),
201 },
202 Self::Struct(..) | Self::Array(..) => {
203 write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT)?;
205 plaintext.fmt_internal(f, depth + 1)?;
207 match i == array.len() - 1 {
209 true => write!(f, "\n{:indent$}]", "", indent = depth * INDENT),
211 false => write!(f, ","),
213 }
214 }
215 }
216 })
217 }
218 }
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use snarkvm_console_network::MainnetV0;
226
227 type CurrentNetwork = MainnetV0;
228
229 #[test]
230 fn test_parse_literal() -> Result<()> {
231 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse("5u8")?;
233 assert_eq!("5u8", candidate.to_string());
234 assert_eq!("", remainder);
235
236 Ok(())
237 }
238
239 #[test]
240 fn test_parse_struct() -> Result<()> {
241 let expected = r"{
243 foo: 5u8
244}";
245 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse("{ foo: 5u8 }")?;
246 assert_eq!(expected, candidate.to_string());
247 assert_eq!("", remainder);
248
249 let expected = r"{
250 foo: 5u8,
251 bar: {
252 baz: 10field,
253 qux: {
254 quux: {
255 corge: {
256 grault: {
257 garply: {
258 waldo: {
259 fred: {
260 plugh: {
261 xyzzy: {
262 thud: true
263 }
264 }
265 }
266 }
267 }
268 }
269 }
270 }
271 }
272 }
273}";
274 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(
275 "{ foo: 5u8, bar: { baz: 10field, qux: {quux:{corge :{grault: {garply:{waldo:{fred:{plugh:{xyzzy: { thud: true}} }}} }}}}}}",
276 )?;
277 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
278 assert_eq!(expected, candidate.to_string());
279 assert_eq!("", remainder);
280
281 Ok(())
282 }
283
284 #[test]
285 fn test_parse_fails() {
286 assert!(Plaintext::<CurrentNetwork>::parse("").is_err());
288 assert!(Plaintext::<CurrentNetwork>::parse("{}").is_err());
289
290 assert!(Plaintext::<CurrentNetwork>::parse("_").is_err());
292 assert!(Plaintext::<CurrentNetwork>::parse("__").is_err());
293 assert!(Plaintext::<CurrentNetwork>::parse("___").is_err());
294 assert!(Plaintext::<CurrentNetwork>::parse("-").is_err());
295 assert!(Plaintext::<CurrentNetwork>::parse("--").is_err());
296 assert!(Plaintext::<CurrentNetwork>::parse("---").is_err());
297 assert!(Plaintext::<CurrentNetwork>::parse("*").is_err());
298 assert!(Plaintext::<CurrentNetwork>::parse("**").is_err());
299 assert!(Plaintext::<CurrentNetwork>::parse("***").is_err());
300
301 assert!(Plaintext::<CurrentNetwork>::parse("1").is_err());
303 assert!(Plaintext::<CurrentNetwork>::parse("2").is_err());
304 assert!(Plaintext::<CurrentNetwork>::parse("3").is_err());
305 assert!(Plaintext::<CurrentNetwork>::parse("1foo").is_err());
306 assert!(Plaintext::<CurrentNetwork>::parse("12").is_err());
307 assert!(Plaintext::<CurrentNetwork>::parse("111").is_err());
308
309 let plaintext =
311 Plaintext::<CurrentNetwork>::parse("foo_bar_baz_qux_quux_quuz_corge_grault_garply_waldo_fred_plugh_xyzzy");
312 assert!(plaintext.is_err());
313 }
314
315 #[test]
316 fn test_nested_structs1() {
317 let expected = r"{
318 r1: {
319 c1: 1u8,
320 c2: 2u8,
321 c3: 1u8
322 },
323 r2: {
324 c1: 2u8,
325 c2: 2u8,
326 c3: 1u8
327 },
328 r3: {
329 c1: 1u8,
330 c2: 2u8,
331 c3: 1u8
332 }
333}";
334
335 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
336 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
337 assert_eq!(expected, candidate.to_string());
338 assert_eq!("", remainder);
339 }
340
341 #[test]
342 fn test_nested_structs2() {
343 let expected = r"{
344 foo: {
345 bar: {
346 baz: 1u8
347 },
348 qux: {
349 quux: 2u8
350 }
351 }
352}";
353
354 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
355 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
356 assert_eq!(expected, candidate.to_string());
357 assert_eq!("", remainder);
358 }
359
360 #[test]
361 fn test_nested_structs3() {
362 let expected = r"{
363 c: {
364 a: 0u8,
365 b: 1u8
366 },
367 d: {
368 a: 0u8,
369 b: 1u8
370 }
371}";
372
373 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
374 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
375 assert_eq!(expected, candidate.to_string());
376 assert_eq!("", remainder);
377 }
378
379 #[test]
380 fn test_array() {
381 let expected = r"[
383 1u8,
384 2u8,
385 3u8
386]";
387 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
388 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
389 assert_eq!(expected, candidate.to_string());
390 assert_eq!("", remainder);
391
392 let expected = r"[
394 {
395 foo: 1u8,
396 bar: 2u8
397 },
398 {
399 foo: 3u8,
400 bar: 4u8
401 },
402 {
403 foo: 5u8,
404 bar: 6u8
405 }
406]";
407 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
408 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
409 assert_eq!(expected, candidate.to_string());
410 assert_eq!("", remainder);
411 }
412
413 #[test]
414 fn test_struct_with_arrays() {
415 let expected = r"{
416 foo: [
417 1u8,
418 2u8,
419 3u8
420 ],
421 bar: [
422 4u8,
423 5u8,
424 6u8
425 ]
426}";
427 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
428 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
429 assert_eq!(expected, candidate.to_string());
430 assert_eq!("", remainder);
431 }
432
433 #[test]
434 fn test_struct_with_array_of_structs() {
435 let expected = r"{
436 foo: [
437 {
438 foo: 1u8,
439 bar: 2u8
440 },
441 {
442 foo: 3u8,
443 bar: 4u8
444 },
445 {
446 foo: 5u8,
447 bar: 6u8
448 }
449 ],
450 bar: [
451 {
452 foo: [
453 1u8,
454 2u8,
455 3u8
456 ],
457 bar: [
458 4u8,
459 5u8,
460 6u8
461 ]
462 },
463 {
464 foo: [
465 7u8,
466 8u8,
467 9u8
468 ],
469 bar: [
470 10u8,
471 11u8,
472 12u8
473 ]
474 },
475 {
476 foo: [
477 13u8,
478 14u8,
479 15u8
480 ],
481 bar: [
482 16u8,
483 17u8,
484 18u8
485 ]
486 }
487 ]
488}";
489 let (remainder, candidate) = Plaintext::<CurrentNetwork>::parse(expected).unwrap();
490 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
491 assert_eq!(expected, candidate.to_string());
492 assert_eq!("", remainder);
493 }
494
495 fn get_depth(plaintext: &Plaintext<CurrentNetwork>) -> usize {
497 match plaintext {
498 Plaintext::Literal(_, _) => 0,
499 Plaintext::Struct(members, _) => members.values().map(get_depth).max().unwrap_or(0) + 1,
500 Plaintext::Array(elements, _) => elements.iter().map(get_depth).max().unwrap_or(0) + 1,
501 }
502 }
503
504 #[test]
505 fn test_deeply_nested_plaintext() {
506 fn create_nested_array(depth: usize, root: impl Display) -> String {
508 let prefix = if depth == 0 { "".to_string() } else { "[".repeat(depth) };
510 let suffix = if depth == 0 { "".to_string() } else { "]".repeat(depth) };
511 format!("{prefix}{root}{suffix}")
513 }
514
515 fn create_nested_struct(depth: usize, root: impl Display) -> String {
517 let prefix = if depth == 0 { "".to_string() } else { "{inner:".repeat(depth) };
519 let suffix = if depth == 0 { "".to_string() } else { "}".repeat(depth) };
520 format!("{prefix}{root}{suffix}")
522 }
523
524 fn create_alternated_nested(depth: usize, root: impl Display) -> String {
526 let prefix = (0..depth).map(|i| if i % 2 == 0 { "[" } else { "{inner:" }).collect::<String>();
527 let suffix = (0..depth).map(|i| if i % 2 == 0 { "]" } else { "}" }).rev().collect::<String>();
528 format!("{prefix}{root}{suffix}")
529 }
530
531 fn run_test(expected_depth: usize, input: String, expected_error: bool) {
533 let result = Plaintext::<CurrentNetwork>::parse(&input);
535 match expected_error {
537 true => {
538 assert!(result.is_err());
539 return;
540 }
541 false => assert!(result.is_ok()),
542 };
543 let (remainder, candidate) = result.unwrap();
545 assert!(remainder.is_empty());
547 assert_eq!(input, candidate.to_string().replace("\n", "").replace(" ", ""));
549 assert_eq!(get_depth(&candidate), expected_depth);
551 }
552
553 let mut depths = (0usize..100).collect_vec();
555 depths.extend((100..1000).step_by(100));
556 depths.extend((1000..10000).step_by(1000));
557 depths.extend((10000..100000).step_by(10000));
558
559 for i in depths.iter().copied() {
561 run_test(i, create_nested_array(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
562 run_test(i, create_nested_array(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
563 run_test(i, create_nested_array(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
564 run_test(i, create_nested_array(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
565 }
566
567 for i in depths.iter().copied() {
569 run_test(i, create_nested_struct(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
570 run_test(i, create_nested_struct(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
571 run_test(i, create_nested_struct(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
572 run_test(i, create_nested_struct(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
573 }
574
575 for i in depths.iter().copied() {
577 run_test(i, create_alternated_nested(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
578 run_test(i, create_alternated_nested(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
579 run_test(i, create_alternated_nested(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
580 run_test(i, create_alternated_nested(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
581 }
582 }
583}