use super::*;
impl<N: Network> Parser for DynamicRecord<N> {
#[inline]
fn parse(string: &str) -> ParserResult<Self> {
let (string, _) = Sanitizer::parse(string)?;
let (string, _) = tag("{")(string)?;
let (string, _) = Sanitizer::parse(string)?;
let (string, _) = tag("owner")(string)?;
let (string, _) = Sanitizer::parse_whitespaces(string)?;
let (string, _) = tag(":")(string)?;
let (string, _) = Sanitizer::parse(string)?;
let (string, owner) = Address::parse(string)?;
let (string, _) = tag(",")(string)?;
let (string, _) = Sanitizer::parse(string)?;
let (string, _) = tag("_root")(string)?;
let (string, _) = Sanitizer::parse_whitespaces(string)?;
let (string, _) = tag(":")(string)?;
let (string, _) = Sanitizer::parse(string)?;
let (string, root) = Field::parse(string)?;
let (string, _) = tag(",")(string)?;
let (string, _) = Sanitizer::parse(string)?;
let (string, _) = tag("_nonce")(string)?;
let (string, _) = Sanitizer::parse_whitespaces(string)?;
let (string, _) = tag(":")(string)?;
let (string, _) = Sanitizer::parse(string)?;
let (string, nonce) = Group::parse(string)?;
let string = match opt(tag(","))(string)? {
(string, Some(_)) => string,
(string, None) => string,
};
let (string, _) = Sanitizer::parse(string)?;
let (string, version) = match opt(tag("_version"))(string)? {
(string, None) => (string, U8::zero()),
(string, Some(_)) => {
let (string, _) = Sanitizer::parse_whitespaces(string)?;
let (string, _) = tag(":")(string)?;
let (string, _) = Sanitizer::parse(string)?;
U8::parse(string)?
}
};
let (string, _) = Sanitizer::parse(string)?;
let (string, _) = tag("}")(string)?;
Ok((string, DynamicRecord::new_unchecked(owner, root, nonce, version, None)))
}
}
impl<N: Network> FromStr for DynamicRecord<N> {
type Err = Error;
fn from_str(string: &str) -> Result<Self> {
match Self::parse(string) {
Ok((remainder, object)) => {
ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
Ok(object)
}
Err(error) => bail!("Failed to parse string. {error}"),
}
}
}
impl<N: Network> Debug for DynamicRecord<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Display::fmt(self, f)
}
}
impl<N: Network> Display for DynamicRecord<N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.fmt_internal(f, 0)
}
}
impl<N: Network> DynamicRecord<N> {
fn fmt_internal(&self, f: &mut Formatter, depth: usize) -> fmt::Result {
const INDENT: usize = 2;
write!(f, "{{")?;
write!(f, "\n{:indent$}owner: {},", "", self.owner, indent = (depth + 1) * INDENT)?;
write!(f, "\n{:indent$}_root: {},", "", self.root, indent = (depth + 1) * INDENT)?;
write!(f, "\n{:indent$}_nonce: {},", "", self.nonce, indent = (depth + 1) * INDENT)?;
write!(f, "\n{:indent$}_version: {}", "", self.version, indent = (depth + 1) * INDENT)?;
write!(f, "\n{:indent$}}}", "", indent = depth * INDENT)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Entry, Literal, Owner, Record};
use snarkvm_console_network::MainnetV0;
use snarkvm_console_types::U64;
use snarkvm_utilities::{TestRng, Uniform};
use core::str::FromStr;
type CurrentNetwork = MainnetV0;
#[test]
fn test_parse_display_roundtrip() {
let rng = &mut TestRng::default();
let data = indexmap::indexmap! {
Identifier::from_str("amount").unwrap() => Entry::Private(Plaintext::from(Literal::U64(U64::rand(rng)))),
};
let owner = Owner::Public(Address::rand(rng));
let record = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::from_plaintext(
owner,
data,
Group::rand(rng),
U8::new(0),
)
.unwrap();
let expected = DynamicRecord::from_record(&record).unwrap();
let expected_string = expected.to_string();
let candidate = DynamicRecord::<CurrentNetwork>::from_str(&expected_string).unwrap();
assert_eq!(expected.owner(), candidate.owner());
assert_eq!(expected.root(), candidate.root());
assert_eq!(expected.nonce(), candidate.nonce());
assert_eq!(expected.version(), candidate.version());
}
#[test]
fn test_parse() {
let string = "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah, _root: 0field, _nonce: 0group, _version: 0u8 }";
let (remainder, candidate) = DynamicRecord::<CurrentNetwork>::parse(string).unwrap();
assert!(remainder.is_empty());
assert_eq!(
*candidate.owner(),
Address::from_str("aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah").unwrap()
);
assert_eq!(*candidate.root(), Field::from_u64(0));
assert_eq!(*candidate.nonce(), Group::zero());
assert_eq!(*candidate.version(), U8::new(0));
}
#[test]
fn test_parse_without_version() {
let string = "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah, _root: 123field, _nonce: 0group }";
let (remainder, candidate) = DynamicRecord::<CurrentNetwork>::parse(string).unwrap();
assert!(remainder.is_empty());
assert_eq!(*candidate.version(), U8::new(0));
}
#[test]
fn test_display() {
let rng = &mut TestRng::default();
let owner = Owner::Public(Address::rand(rng));
let record = Record::<CurrentNetwork, Plaintext<CurrentNetwork>>::from_plaintext(
owner,
indexmap::IndexMap::new(),
Group::rand(rng),
U8::new(1),
)
.unwrap();
let dynamic = DynamicRecord::from_record(&record).unwrap();
let display = dynamic.to_string();
assert!(display.contains("owner:"));
assert!(display.contains("_root:"));
assert!(display.contains("_nonce:"));
assert!(display.contains("_version:"));
}
}