1use super::*;
17
18impl<N: Network> Parser for Entry<N, Plaintext<N>> {
19 #[inline]
21 fn parse(string: &str) -> ParserResult<Self> {
22 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
24 enum Mode {
25 Constant,
26 Public,
27 Private,
28 }
29
30 fn parse_pair<N: Network>(string: &str, depth: usize) -> ParserResult<(Identifier<N>, Plaintext<N>, Mode)> {
32 let (string, _) = Sanitizer::parse(string)?;
34 let (string, identifier) = Identifier::parse(string)?;
36 let (string, _) = Sanitizer::parse_whitespaces(string)?;
38 let (string, _) = tag(":")(string)?;
40 let (string, _) = Sanitizer::parse_whitespaces(string)?;
42 let (string, (plaintext, mode)) = alt((
44 |input| parse_literal(input, depth),
46 |input| parse_struct(input, depth),
48 |input| parse_array(input, depth),
50 ))(string)?;
51 let (string, _) = Sanitizer::parse_whitespaces(string)?;
53 Ok((string, (identifier, plaintext, mode)))
55 }
56
57 fn parse_literal<N: Network>(string: &str, depth: usize) -> ParserResult<(Plaintext<N>, Mode)> {
59 if depth > N::MAX_DATA_DEPTH {
61 return map_res(take(0usize), |_| {
62 Err(error(format!("Found an entry future that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH)))
63 })(string);
64 }
65 alt((
66 map(pair(Literal::parse, tag(".constant")), |(literal, _)| (Plaintext::from(literal), Mode::Constant)),
67 map(pair(Literal::parse, tag(".public")), |(literal, _)| (Plaintext::from(literal), Mode::Public)),
68 map(pair(Literal::parse, tag(".private")), |(literal, _)| (Plaintext::from(literal), Mode::Private)),
69 ))(string)
70 }
71
72 fn parse_struct<N: Network>(string: &str, depth: usize) -> ParserResult<(Plaintext<N>, Mode)> {
75 if depth > N::MAX_DATA_DEPTH {
77 return map_res(take(0usize), |_| {
78 Err(error(format!("Found an entry that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH)))
79 })(string);
80 }
81 let (string, _) = Sanitizer::parse(string)?;
83 let (string, _) = tag("{")(string)?;
85 let (string, _) = Sanitizer::parse_whitespaces(string)?;
87 let (string, (members, mode)) =
89 map_res(separated_list1(tag(","), |input| parse_pair(input, depth + 1)), |members: Vec<_>| {
90 if has_duplicates(members.iter().map(|(name, ..)| name)) {
92 return Err(error("Duplicate member in struct"));
93 }
94 let mode = members.iter().map(|(_, _, mode)| mode).dedup().collect::<Vec<_>>();
96 let mode = match mode.len() == 1 {
97 true => *mode[0],
98 false => return Err(error("Members of struct in entry have different visibilities")),
99 };
100 match members.len() <= N::MAX_STRUCT_ENTRIES {
102 true => Ok((members.into_iter().map(|(i, p, _)| (i, p)).collect::<Vec<_>>(), mode)),
104 false => Err(error(format!("Found a struct that exceeds size ({})", members.len()))),
105 }
106 })(string)?;
107 let (string, _) = Sanitizer::parse(string)?;
109 let (string, _) = tag("}")(string)?;
111 Ok((string, (Plaintext::Struct(IndexMap::from_iter(members), Default::default()), mode)))
113 }
114
115 fn parse_array<N: Network>(string: &str, depth: usize) -> ParserResult<(Plaintext<N>, Mode)> {
118 if depth > N::MAX_DATA_DEPTH {
120 return map_res(take(0usize), |_| {
121 Err(error(format!("Found an entry future that exceeds maximum data depth ({})", N::MAX_DATA_DEPTH)))
122 })(string);
123 }
124 let (string, _) = Sanitizer::parse(string)?;
126 let (string, _) = tag("[")(string)?;
128 let (string, _) = Sanitizer::parse_whitespaces(string)?;
130 let (string, (elements, mode)) = map_res(
132 separated_list1(
133 pair(Sanitizer::parse_whitespaces, pair(tag(","), Sanitizer::parse_whitespaces)),
134 alt((
135 |input| parse_literal(input, depth + 1),
136 |input| parse_struct(input, depth + 1),
137 |input| parse_array(input, depth + 1),
138 )),
139 ),
140 |members: Vec<(Plaintext<N>, Mode)>| {
141 let mode = members.iter().map(|(_, mode)| mode).dedup().collect::<Vec<_>>();
143 let mode = match mode.len() == 1 {
144 true => *mode[0],
145 false => return Err(error("Members of an array have different visibilities")),
146 };
147 match members.len() <= N::MAX_ARRAY_ELEMENTS {
149 true => Ok((members.into_iter().map(|(p, _)| p).collect::<Vec<_>>(), mode)),
151 false => Err(error(format!("Found an array that exceeds size ({})", members.len()))),
152 }
153 },
154 )(string)?;
155 let (string, _) = Sanitizer::parse(string)?;
157 let (string, _) = tag("]")(string)?;
159 Ok((string, (Plaintext::Array(elements, Default::default()), mode)))
161 }
162
163 let (string, _) = Sanitizer::parse_whitespaces(string)?;
165 let (string, (plaintext, mode)) = alt((
167 |input| parse_literal(input, 0),
169 |input| parse_struct(input, 0),
171 |input| parse_array(input, 0),
173 ))(string)?;
174
175 match mode {
177 Mode::Constant => Ok((string, Entry::Constant(plaintext))),
178 Mode::Public => Ok((string, Entry::Public(plaintext))),
179 Mode::Private => Ok((string, Entry::Private(plaintext))),
180 }
181 }
182}
183
184impl<N: Network> FromStr for Entry<N, Plaintext<N>> {
185 type Err = Error;
186
187 fn from_str(string: &str) -> Result<Self> {
189 match Self::parse(string) {
190 Ok((remainder, object)) => {
191 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
193 Ok(object)
195 }
196 Err(error) => bail!("Failed to parse string. {error}"),
197 }
198 }
199}
200
201impl<N: Network> Debug for Entry<N, Plaintext<N>> {
202 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
204 Display::fmt(self, f)
205 }
206}
207
208impl<N: Network> Display for Entry<N, Plaintext<N>> {
209 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
211 self.fmt_internal(f, 0)
212 }
213}
214
215impl<N: Network> Entry<N, Plaintext<N>> {
216 pub(in crate::data::record) fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
218 const INDENT: usize = 2;
220
221 let (plaintext, visibility) = match self {
222 Self::Constant(constant) => (constant, "constant"),
223 Self::Public(public) => (public, "public"),
224 Self::Private(private) => (private, "private"),
225 };
226
227 match plaintext {
228 Plaintext::Literal(literal, ..) => {
230 write!(f, "{:indent$}{literal}.{visibility}", "", indent = depth * INDENT)
231 }
232 Plaintext::Struct(struct_, ..) => {
234 write!(f, "{{")?;
236 struct_.iter().enumerate().try_for_each(|(i, (name, plaintext))| {
238 match plaintext {
239 #[rustfmt::skip]
240 Plaintext::Literal(literal, ..) => match i == struct_.len() - 1 {
241 true => {
242 write!(f, "\n{:indent$}{name}: {literal}.{visibility}", "", indent = (depth + 1) * INDENT)?;
244 write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
246 }
247 false => write!(f, "\n{:indent$}{name}: {literal}.{visibility},", "", indent = (depth + 1) * INDENT),
249 },
250 Plaintext::Struct(..) | Plaintext::Array(..) => {
251 write!(f, "\n{:indent$}{name}: ", "", indent = (depth + 1) * INDENT)?;
253 match self {
255 Self::Constant(..) => Self::Constant(plaintext.clone()).fmt_internal(f, depth + 1)?,
256 Self::Public(..) => Self::Public(plaintext.clone()).fmt_internal(f, depth + 1)?,
257 Self::Private(..) => Self::Private(plaintext.clone()).fmt_internal(f, depth + 1)?,
258 }
259 match i == struct_.len() - 1 {
261 true => write!(f, "\n{:indent$}}}", "", indent = depth * INDENT),
263 false => write!(f, ","),
265 }
266 },
267 }
268 })
269 }
270 Plaintext::Array(array, ..) => {
272 write!(f, "[")?;
274 array.iter().enumerate().try_for_each(|(i, plaintext)| {
276 match plaintext {
277 #[rustfmt::skip]
278 Plaintext::Literal(literal, ..) => match i == array.len() - 1 {
279 true => {
280 write!(f, "\n{:indent$}{literal}.{visibility}", "", indent = (depth + 1) * INDENT)?;
282 write!(f, "\n{:indent$}]", "", indent = depth * INDENT)
284 }
285 false => write!(f, "\n{:indent$}{literal}.{visibility},", "", indent = (depth + 1) * INDENT),
287 },
288 Plaintext::Struct(..) | Plaintext::Array(..) => {
289 write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT)?;
291 match self {
293 Self::Constant(..) => Self::Constant(plaintext.clone()).fmt_internal(f, depth + 1)?,
294 Self::Public(..) => Self::Public(plaintext.clone()).fmt_internal(f, depth + 1)?,
295 Self::Private(..) => Self::Private(plaintext.clone()).fmt_internal(f, depth + 1)?,
296 }
297 match i == array.len() - 1 {
299 true => write!(f, "\n{:indent$}]", "", indent = depth * INDENT),
301 false => write!(f, ","),
303 }
304 },
305 }
306 })
307 }
308 }
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315 use snarkvm_console_network::MainnetV0;
316
317 type CurrentNetwork = MainnetV0;
318
319 #[test]
320 fn test_parse() -> Result<()> {
321 let expected = r"{
323 foo: 5u8.private
324}";
325 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse("{ foo: 5u8.private }")?;
326 assert_eq!(expected, candidate.to_string());
327 assert_eq!("", remainder);
328
329 let expected = r"{
330 foo: 5u8.public,
331 bar: {
332 baz: 10field.public,
333 qux: {
334 quux: {
335 corge: {
336 grault: {
337 garply: {
338 waldo: {
339 fred: {
340 plugh: {
341 xyzzy: {
342 thud: true.public
343 }
344 }
345 }
346 }
347 }
348 }
349 }
350 }
351 }
352 }
353}";
354 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(
355 "{ foo: 5u8.public, bar: { baz: 10field.public, qux: {quux:{corge :{grault: {garply:{waldo:{fred:{plugh:{xyzzy: { thud: true.public}} }}} }}}}}}",
356 )?;
357 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
358 assert_eq!(expected, candidate.to_string());
359 assert_eq!("", remainder);
360
361 let expected = r"[
363 5u8.private,
364 10u8.private,
365 15u8.private
366]";
367 let (remainder, candidate) =
368 Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse("[ 5u8.private, 10u8.private, 15u8.private ]")?;
369 assert_eq!(expected, candidate.to_string());
370 assert_eq!("", remainder);
371
372 let expected = r"[
374 {
375 foo: 5u8.public
376 },
377 {
378 bar: 10u8.public
379 },
380 {
381 baz: 15u8.public
382 }
383]";
384 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(
385 "[ { foo: 5u8.public }, { bar: 10u8.public }, { baz: 15u8.public } ]",
386 )?;
387 assert_eq!(expected, candidate.to_string());
388 assert_eq!("", remainder);
389
390 let expected = r"{
392 foo: [
393 5u8.public,
394 10u8.public,
395 15u8.public
396 ],
397 bar: [
398 {
399 foo: 5u8.public
400 },
401 {
402 bar: 10u8.public
403 },
404 {
405 baz: 15u8.public
406 }
407 ]
408}";
409 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(
410 "{ foo: [ 5u8.public, 10u8.public, 15u8.public ], bar: [ { foo: 5u8.public }, { bar: 10u8.public }, { baz: 15u8.public } ] }",
411 )?;
412 assert_eq!(expected, candidate.to_string());
413 assert_eq!("", remainder);
414
415 Ok(())
416 }
417
418 fn get_depth(plaintext: &Plaintext<CurrentNetwork>) -> usize {
420 match plaintext {
421 Plaintext::Literal(_, _) => 0,
422 Plaintext::Struct(members, _) => members.values().map(get_depth).max().unwrap_or(0) + 1,
423 Plaintext::Array(elements, _) => elements.iter().map(get_depth).max().unwrap_or(0) + 1,
424 }
425 }
426
427 #[test]
428 fn test_deeply_nested_entry() {
429 fn create_nested_array(depth: usize, root: impl Display) -> String {
431 let prefix = if depth == 0 { "".to_string() } else { "[".repeat(depth) };
433 let suffix = if depth == 0 { "".to_string() } else { "]".repeat(depth) };
434 format!("{prefix}{root}{suffix}")
436 }
437
438 fn create_nested_struct(depth: usize, root: impl Display) -> String {
440 let prefix = if depth == 0 { "".to_string() } else { "{inner:".repeat(depth) };
442 let suffix = if depth == 0 { "".to_string() } else { "}".repeat(depth) };
443 format!("{prefix}{root}{suffix}")
445 }
446
447 fn create_alternated_nested(depth: usize, root: impl Display) -> String {
449 let prefix = (0..depth).map(|i| if i % 2 == 0 { "[" } else { "{inner:" }).collect::<String>();
450 let suffix = (0..depth).map(|i| if i % 2 == 0 { "]" } else { "}" }).rev().collect::<String>();
451 format!("{prefix}{root}{suffix}")
452 }
453
454 fn run_test(expected_depth: usize, input: String, expected_error: bool) {
456 println!("Testing input: {input} with expected error: {expected_error}");
457 let result = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(&input);
459 match expected_error {
461 true => {
462 assert!(result.is_err());
463 return;
464 }
465 false => assert!(result.is_ok()),
466 };
467 let (remainder, candidate) = result.unwrap();
469 assert!(remainder.is_empty());
471 assert_eq!(input, candidate.to_string().replace("\n", "").replace(" ", ""));
473 match candidate {
475 Entry::Constant(plaintext) => {
476 assert_eq!(get_depth(&plaintext), expected_depth);
477 }
478 Entry::Public(plaintext) => {
479 assert_eq!(get_depth(&plaintext), expected_depth);
480 }
481 Entry::Private(plaintext) => {
482 assert_eq!(get_depth(&plaintext), expected_depth);
483 }
484 }
485 }
486
487 let mut depths = (0usize..100).collect_vec();
489 depths.extend((100..1000).step_by(100));
490 depths.extend((1000..10000).step_by(1000));
491 depths.extend((10000..100000).step_by(10000));
492
493 for i in depths.iter().copied() {
495 run_test(i, create_nested_array(i, "false.constant"), i > CurrentNetwork::MAX_DATA_DEPTH);
496 run_test(i, create_nested_array(i, "1u8.public"), i > CurrentNetwork::MAX_DATA_DEPTH);
497 run_test(i, create_nested_array(i, "0u128.private"), i > CurrentNetwork::MAX_DATA_DEPTH);
498 run_test(i, create_nested_array(i, "10field.constant"), i > CurrentNetwork::MAX_DATA_DEPTH);
499 }
500
501 for i in depths.iter().copied() {
503 run_test(i, create_nested_struct(i, "false.public"), i > CurrentNetwork::MAX_DATA_DEPTH);
504 run_test(i, create_nested_struct(i, "1u8.private"), i > CurrentNetwork::MAX_DATA_DEPTH);
505 run_test(i, create_nested_struct(i, "0u128.constant"), i > CurrentNetwork::MAX_DATA_DEPTH);
506 run_test(i, create_nested_struct(i, "10field.public"), i > CurrentNetwork::MAX_DATA_DEPTH);
507 }
508
509 for i in depths.iter().copied() {
511 run_test(i, create_alternated_nested(i, "false.private"), i > CurrentNetwork::MAX_DATA_DEPTH);
512 run_test(i, create_alternated_nested(i, "1u8.constant"), i > CurrentNetwork::MAX_DATA_DEPTH);
513 run_test(i, create_alternated_nested(i, "0u128.public"), i > CurrentNetwork::MAX_DATA_DEPTH);
514 run_test(i, create_alternated_nested(i, "10field.private"), i > CurrentNetwork::MAX_DATA_DEPTH);
515 }
516 }
517}