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) -> 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 parse_literal,
46 parse_struct,
48 parse_array,
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) -> ParserResult<(Plaintext<N>, Mode)> {
59 alt((
60 map(pair(Literal::parse, tag(".constant")), |(literal, _)| (Plaintext::from(literal), Mode::Constant)),
61 map(pair(Literal::parse, tag(".public")), |(literal, _)| (Plaintext::from(literal), Mode::Public)),
62 map(pair(Literal::parse, tag(".private")), |(literal, _)| (Plaintext::from(literal), Mode::Private)),
63 ))(string)
64 }
65
66 fn parse_struct<N: Network>(string: &str) -> ParserResult<(Plaintext<N>, Mode)> {
69 let (string, _) = Sanitizer::parse(string)?;
71 let (string, _) = tag("{")(string)?;
73 let (string, _) = Sanitizer::parse_whitespaces(string)?;
75 let (string, (members, mode)) = map_res(separated_list1(tag(","), parse_pair), |members: Vec<_>| {
77 if has_duplicates(members.iter().map(|(name, ..)| name)) {
79 return Err(error("Duplicate member in struct"));
80 }
81 let mode = members.iter().map(|(_, _, mode)| mode).dedup().collect::<Vec<_>>();
83 let mode = match mode.len() == 1 {
84 true => *mode[0],
85 false => return Err(error("Members of struct in entry have different visibilities")),
86 };
87 match members.len() <= N::MAX_STRUCT_ENTRIES {
89 true => Ok((members.into_iter().map(|(i, p, _)| (i, p)).collect::<Vec<_>>(), mode)),
91 false => Err(error(format!("Found a struct that exceeds size ({})", members.len()))),
92 }
93 })(string)?;
94 let (string, _) = Sanitizer::parse(string)?;
96 let (string, _) = tag("}")(string)?;
98 Ok((string, (Plaintext::Struct(IndexMap::from_iter(members), Default::default()), mode)))
100 }
101
102 fn parse_array<N: Network>(string: &str) -> ParserResult<(Plaintext<N>, Mode)> {
105 let (string, _) = Sanitizer::parse(string)?;
107 let (string, _) = tag("[")(string)?;
109 let (string, _) = Sanitizer::parse_whitespaces(string)?;
111 let (string, (elements, mode)) = map_res(
113 separated_list1(
114 pair(Sanitizer::parse_whitespaces, pair(tag(","), Sanitizer::parse_whitespaces)),
115 alt((parse_literal, parse_struct, parse_array)),
116 ),
117 |members: Vec<(Plaintext<N>, Mode)>| {
118 let mode = members.iter().map(|(_, mode)| mode).dedup().collect::<Vec<_>>();
120 let mode = match mode.len() == 1 {
121 true => *mode[0],
122 false => return Err(error("Members of an array have different visibilities")),
123 };
124 match members.len() <= N::MAX_ARRAY_ELEMENTS {
126 true => Ok((members.into_iter().map(|(p, _)| p).collect::<Vec<_>>(), mode)),
128 false => Err(error(format!("Found an array that exceeds size ({})", members.len()))),
129 }
130 },
131 )(string)?;
132 let (string, _) = Sanitizer::parse(string)?;
134 let (string, _) = tag("]")(string)?;
136 Ok((string, (Plaintext::Array(elements, Default::default()), mode)))
138 }
139
140 let (string, _) = Sanitizer::parse_whitespaces(string)?;
142 let (string, (plaintext, mode)) = alt((
144 parse_literal,
146 parse_struct,
148 parse_array,
150 ))(string)?;
151
152 match mode {
154 Mode::Constant => Ok((string, Entry::Constant(plaintext))),
155 Mode::Public => Ok((string, Entry::Public(plaintext))),
156 Mode::Private => Ok((string, Entry::Private(plaintext))),
157 }
158 }
159}
160
161impl<N: Network> FromStr for Entry<N, Plaintext<N>> {
162 type Err = Error;
163
164 fn from_str(string: &str) -> Result<Self> {
166 match Self::parse(string) {
167 Ok((remainder, object)) => {
168 ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
170 Ok(object)
172 }
173 Err(error) => bail!("Failed to parse string. {error}"),
174 }
175 }
176}
177
178impl<N: Network> Debug for Entry<N, Plaintext<N>> {
179 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
181 Display::fmt(self, f)
182 }
183}
184
185impl<N: Network> Display for Entry<N, Plaintext<N>> {
186 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
188 self.fmt_internal(f, 0)
189 }
190}
191
192impl<N: Network> Entry<N, Plaintext<N>> {
193 pub(in crate::data::record) fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
195 const INDENT: usize = 2;
197
198 let (plaintext, visibility) = match self {
199 Self::Constant(constant) => (constant, "constant"),
200 Self::Public(public) => (public, "public"),
201 Self::Private(private) => (private, "private"),
202 };
203
204 match plaintext {
205 Plaintext::Literal(literal, ..) => {
207 write!(f, "{:indent$}{literal}.{visibility}", "", indent = depth * INDENT)
208 }
209 Plaintext::Struct(struct_, ..) => {
211 write!(f, "{{")?;
213 struct_.iter().enumerate().try_for_each(|(i, (name, plaintext))| {
215 match plaintext {
216 #[rustfmt::skip]
217 Plaintext::Literal(literal, ..) => match i == struct_.len() - 1 {
218 true => {
219 write!(f, "\n{:indent$}{name}: {literal}.{visibility}", "", indent = (depth + 1) * INDENT)?;
221 write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
223 }
224 false => write!(f, "\n{:indent$}{name}: {literal}.{visibility},", "", indent = (depth + 1) * INDENT),
226 },
227 Plaintext::Struct(..) | Plaintext::Array(..) => {
228 write!(f, "\n{:indent$}{name}: ", "", indent = (depth + 1) * INDENT)?;
230 match self {
232 Self::Constant(..) => Self::Constant(plaintext.clone()).fmt_internal(f, depth + 1)?,
233 Self::Public(..) => Self::Public(plaintext.clone()).fmt_internal(f, depth + 1)?,
234 Self::Private(..) => Self::Private(plaintext.clone()).fmt_internal(f, depth + 1)?,
235 }
236 match i == struct_.len() - 1 {
238 true => write!(f, "\n{:indent$}}}", "", indent = depth * INDENT),
240 false => write!(f, ","),
242 }
243 },
244 }
245 })
246 }
247 Plaintext::Array(array, ..) => {
249 write!(f, "[")?;
251 array.iter().enumerate().try_for_each(|(i, plaintext)| {
253 match plaintext {
254 #[rustfmt::skip]
255 Plaintext::Literal(literal, ..) => match i == array.len() - 1 {
256 true => {
257 write!(f, "\n{:indent$}{literal}.{visibility}", "", indent = (depth + 1) * INDENT)?;
259 write!(f, "\n{:indent$}]", "", indent = depth * INDENT)
261 }
262 false => write!(f, "\n{:indent$}{literal}.{visibility},", "", indent = (depth + 1) * INDENT),
264 },
265 Plaintext::Struct(..) | Plaintext::Array(..) => {
266 write!(f, "\n{:indent$}", "", indent = (depth + 1) * INDENT)?;
268 match self {
270 Self::Constant(..) => Self::Constant(plaintext.clone()).fmt_internal(f, depth + 1)?,
271 Self::Public(..) => Self::Public(plaintext.clone()).fmt_internal(f, depth + 1)?,
272 Self::Private(..) => Self::Private(plaintext.clone()).fmt_internal(f, depth + 1)?,
273 }
274 match i == array.len() - 1 {
276 true => write!(f, "\n{:indent$}]", "", indent = depth * INDENT),
278 false => write!(f, ","),
280 }
281 },
282 }
283 })
284 }
285 }
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292 use snarkvm_console_network::MainnetV0;
293
294 type CurrentNetwork = MainnetV0;
295
296 #[test]
297 fn test_parse() -> Result<()> {
298 let expected = r"{
300 foo: 5u8.private
301}";
302 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse("{ foo: 5u8.private }")?;
303 assert_eq!(expected, candidate.to_string());
304 assert_eq!("", remainder);
305
306 let expected = r"{
307 foo: 5u8.public,
308 bar: {
309 baz: 10field.public,
310 qux: {
311 quux: {
312 corge: {
313 grault: {
314 garply: {
315 waldo: {
316 fred: {
317 plugh: {
318 xyzzy: {
319 thud: true.public
320 }
321 }
322 }
323 }
324 }
325 }
326 }
327 }
328 }
329 }
330}";
331 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(
332 "{ foo: 5u8.public, bar: { baz: 10field.public, qux: {quux:{corge :{grault: {garply:{waldo:{fred:{plugh:{xyzzy: { thud: true.public}} }}} }}}}}}",
333 )?;
334 println!("\nExpected: {expected}\n\nFound: {candidate}\n");
335 assert_eq!(expected, candidate.to_string());
336 assert_eq!("", remainder);
337
338 let expected = r"[
340 5u8.private,
341 10u8.private,
342 15u8.private
343]";
344 let (remainder, candidate) =
345 Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse("[ 5u8.private, 10u8.private, 15u8.private ]")?;
346 assert_eq!(expected, candidate.to_string());
347 assert_eq!("", remainder);
348
349 let expected = r"[
351 {
352 foo: 5u8.public
353 },
354 {
355 bar: 10u8.public
356 },
357 {
358 baz: 15u8.public
359 }
360]";
361 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(
362 "[ { foo: 5u8.public }, { bar: 10u8.public }, { baz: 15u8.public } ]",
363 )?;
364 assert_eq!(expected, candidate.to_string());
365 assert_eq!("", remainder);
366
367 let expected = r"{
369 foo: [
370 5u8.public,
371 10u8.public,
372 15u8.public
373 ],
374 bar: [
375 {
376 foo: 5u8.public
377 },
378 {
379 bar: 10u8.public
380 },
381 {
382 baz: 15u8.public
383 }
384 ]
385}";
386 let (remainder, candidate) = Entry::<CurrentNetwork, Plaintext<CurrentNetwork>>::parse(
387 "{ foo: [ 5u8.public, 10u8.public, 15u8.public ], bar: [ { foo: 5u8.public }, { bar: 10u8.public }, { baz: 15u8.public } ] }",
388 )?;
389 assert_eq!(expected, candidate.to_string());
390 assert_eq!("", remainder);
391
392 Ok(())
393 }
394}