Skip to content

Commit

Permalink
Implement Debug for collection types (#647)
Browse files Browse the repository at this point in the history
  • Loading branch information
itegulov authored Dec 10, 2021
1 parent 1a37d85 commit b40b845
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 39 deletions.
Binary file modified examples/fungible-token/res/fungible_token.wasm
Binary file not shown.
Binary file modified examples/non-fungible-token/res/non_fungible_token.wasm
Binary file not shown.
30 changes: 30 additions & 0 deletions near-sdk/src/collections/lazy_option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ where
}
}

impl<T> std::fmt::Debug for LazyOption<T>
where
T: std::fmt::Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if cfg!(feature = "expensive-debug") {
self.get().fmt(f)
} else {
f.debug_struct("LazyOption").field("storage_key", &self.storage_key).finish()
}
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -173,4 +186,21 @@ mod tests {
assert!(a.is_some());
assert_eq!(a.get(), Some(42));
}

#[test]
pub fn test_debug() {
let mut lazy_option = LazyOption::new(b"m", None);
if cfg!(feature = "expensive-debug") {
assert_eq!(format!("{:?}", lazy_option), "None");
} else {
assert_eq!(format!("{:?}", lazy_option), "LazyOption { storage_key: [109] }");
}

lazy_option.set(&1u64);
if cfg!(feature = "expensive-debug") {
assert_eq!(format!("{:?}", lazy_option), "Some(1)");
} else {
assert_eq!(format!("{:?}", lazy_option), "LazyOption { storage_key: [109] }");
}
}
}
20 changes: 20 additions & 0 deletions near-sdk/src/collections/lookup_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ where
}
}

impl<K, V> std::fmt::Debug for LookupMap<K, V>
where
K: std::fmt::Debug + BorshSerialize,
V: std::fmt::Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LookupMap").field("key_prefix", &self.key_prefix).finish()
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -284,4 +294,14 @@ mod tests {
assert_eq!(map.get(&key).unwrap(), value);
}
}

#[test]
fn test_debug() {
let map: LookupMap<u64, u64> = LookupMap::new(b"m");

assert_eq!(
format!("{:?}", map),
format!("LookupMap {{ key_prefix: {:?} }}", map.key_prefix)
);
}
}
19 changes: 19 additions & 0 deletions near-sdk/src/collections/lookup_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ where
}
}

impl<T> std::fmt::Debug for LookupSet<T>
where
T: std::fmt::Debug + BorshSerialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LookupSet").field("element_prefix", &self.element_prefix).finish()
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -204,4 +213,14 @@ mod tests {
assert!(set.contains(&key));
}
}

#[test]
fn test_debug() {
let set: LookupSet<u64> = LookupSet::new(b"m");

assert_eq!(
format!("{:?}", set),
format!("LookupSet {{ element_prefix: {:?} }}", set.element_prefix)
);
}
}
69 changes: 36 additions & 33 deletions near-sdk/src/collections/tree_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct TreeMap<K, V> {
tree: Vector<Node<K>>,
}

#[derive(Clone, BorshSerialize, BorshDeserialize)]
#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub struct Node<K> {
id: u64,
key: K, // key stored in a node
Expand Down Expand Up @@ -580,6 +580,16 @@ where
}
}

impl<K, V> std::fmt::Debug for TreeMap<K, V>
where
K: std::fmt::Debug + Ord + Clone + BorshSerialize + BorshDeserialize,
V: std::fmt::Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TreeMap").field("root", &self.root).field("tree", &self.tree).finish()
}
}

impl<'a, K, V> IntoIterator for &'a TreeMap<K, V>
where
K: Ord + Clone + BorshSerialize + BorshDeserialize,
Expand Down Expand Up @@ -733,8 +743,6 @@ mod tests {
use quickcheck::QuickCheck;
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::fmt::Formatter;
use std::fmt::{Debug, Result};

/// Return height of the tree - number of nodes on the longest path starting from the root node.
fn height<K, V>(tree: &TreeMap<K, V>) -> u64
Expand Down Expand Up @@ -771,34 +779,6 @@ mod tests {
h.ceil() as u64
}

impl<K> Debug for Node<K>
where
K: Ord + Clone + Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("Node")
.field("id", &self.id)
.field("key", &self.key)
.field("lft", &self.lft)
.field("rgt", &self.rgt)
.field("ht", &self.ht)
.finish()
}
}

impl<K, V> Debug for TreeMap<K, V>
where
K: Ord + Clone + Debug + BorshSerialize + BorshDeserialize,
V: Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("TreeMap")
.field("root", &self.root)
.field("tree", &self.tree.iter().collect::<Vec<Node<K>>>())
.finish()
}
}

#[test]
fn test_empty() {
let map: TreeMap<u8, u8> = TreeMap::new(b't');
Expand Down Expand Up @@ -1682,8 +1662,8 @@ mod tests {

fn is_balanced<K, V>(map: &TreeMap<K, V>, root: u64) -> bool
where
K: Debug + Ord + Clone + BorshSerialize + BorshDeserialize,
V: Debug + BorshSerialize + BorshDeserialize,
K: std::fmt::Debug + Ord + Clone + BorshSerialize + BorshDeserialize,
V: std::fmt::Debug + BorshSerialize + BorshDeserialize,
{
let node = map.node(root).unwrap();
let balance = map.get_balance(&node);
Expand Down Expand Up @@ -1777,4 +1757,27 @@ mod tests {

QuickCheck::new().tests(300).quickcheck(prop as Prop);
}

#[test]
fn test_debug() {
let mut map = TreeMap::new(b"m");
map.insert(&1, &100);
map.insert(&3, &300);
map.insert(&2, &200);

if cfg!(feature = "expensive-debug") {
let node1 = "Node { id: 0, key: 1, lft: None, rgt: None, ht: 1 }";
let node2 = "Node { id: 2, key: 2, lft: Some(0), rgt: Some(1), ht: 2 }";
let node3 = "Node { id: 1, key: 3, lft: None, rgt: None, ht: 1 }";
assert_eq!(
format!("{:?}", map),
format!("TreeMap {{ root: 2, tree: [{}, {}, {}] }}", node1, node3, node2)
);
} else {
assert_eq!(
format!("{:?}", map),
"TreeMap { root: 2, tree: Vector { len: 3, prefix: [109, 110] } }"
);
}
}
}
36 changes: 36 additions & 0 deletions near-sdk/src/collections/unordered_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,20 @@ where
}
}

impl<K, V> std::fmt::Debug for UnorderedMap<K, V>
where
K: std::fmt::Debug + BorshSerialize + BorshDeserialize,
V: std::fmt::Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UnorderedMap")
.field("key_index_prefix", &self.key_index_prefix)
.field("keys", &self.keys)
.field("values", &self.values)
.finish()
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -442,4 +456,26 @@ mod tests {
let actual: HashMap<u64, u64> = map.iter().collect();
assert_eq!(actual, key_to_value);
}

#[test]
fn test_debug() {
let mut map = UnorderedMap::new(b"m");
map.insert(&1u64, &100u64);
map.insert(&3u64, &300u64);
map.insert(&2u64, &200u64);

if cfg!(feature = "expensive-debug") {
assert_eq!(
format!("{:?}", map),
"UnorderedMap { key_index_prefix: [109, 105], keys: [1, 3, 2], values: [100, 300, 200] }"
);
} else {
assert_eq!(
format!("{:?}", map),
"UnorderedMap { key_index_prefix: [109, 105], \
keys: Vector { len: 3, prefix: [109, 107] }, \
values: Vector { len: 3, prefix: [109, 118] } }"
);
}
}
}
32 changes: 32 additions & 0 deletions near-sdk/src/collections/unordered_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,18 @@ where
}
}

impl<T> std::fmt::Debug for UnorderedSet<T>
where
T: std::fmt::Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UnorderedSet")
.field("element_index_prefix", &self.element_index_prefix)
.field("elements", &self.elements)
.finish()
}
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -330,4 +342,24 @@ mod tests {
let actual: HashSet<u64> = set.iter().collect();
assert_eq!(actual, keys);
}

#[test]
fn test_debug() {
let mut set = UnorderedSet::new(b"m");
set.insert(&1u64);
set.insert(&3u64);
set.insert(&2u64);

if cfg!(feature = "expensive-debug") {
assert_eq!(
format!("{:?}", set),
"UnorderedSet { element_index_prefix: [109, 105], elements: [1, 3, 2] }"
);
} else {
assert_eq!(
format!("{:?}", set),
"UnorderedSet { element_index_prefix: [109, 105], elements: Vector { len: 3, prefix: [109, 101] } }"
);
}
}
}
15 changes: 9 additions & 6 deletions near-sdk/src/collections/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ fn expect_consistent_state<T>(val: Option<T>) -> T {
/// An iterable implementation of vector that stores its content on the trie.
/// Uses the following map: index -> element.
#[derive(BorshSerialize, BorshDeserialize)]
#[cfg_attr(not(feature = "expensive-debug"), derive(Debug))]
pub struct Vector<T> {
len: u64,
prefix: Vec<u8>,
Expand Down Expand Up @@ -236,6 +235,13 @@ impl<T: std::fmt::Debug + BorshDeserialize> std::fmt::Debug for Vector<T> {
}
}

#[cfg(not(feature = "expensive-debug"))]
impl<T: std::fmt::Debug + BorshDeserialize> std::fmt::Debug for Vector<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Vector").field("len", &self.len).field("prefix", &self.prefix).finish()
}
}

/// An iterator over raw serialized bytes of each element in the [`Vector`].
pub struct RawIter<'a, T> {
vec: &'a Vector<T>,
Expand Down Expand Up @@ -474,7 +480,7 @@ mod tests {
} else {
assert_eq!(
format!("{:?}", vec),
format!("Vector {{ len: 5, prefix: {:?}, el: PhantomData }}", vec.prefix)
format!("Vector {{ len: 5, prefix: {:?} }}", vec.prefix)
);
}

Expand All @@ -489,10 +495,7 @@ mod tests {
} else {
assert_eq!(
format!("{:?}", deserialize_only_vec),
format!(
"Vector {{ len: 5, prefix: {:?}, el: PhantomData }}",
deserialize_only_vec.prefix
)
format!("Vector {{ len: 5, prefix: {:?} }}", deserialize_only_vec.prefix)
);
}
}
Expand Down
13 changes: 13 additions & 0 deletions near-sdk/src/store/lazy_option/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,16 @@ where
Self::get_mut(self)
}
}

impl<T> std::fmt::Debug for LazyOption<T>
where
T: std::fmt::Debug + BorshSerialize + BorshDeserialize,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if cfg!(feature = "expensive-debug") {
self.get().fmt(f)
} else {
f.debug_struct("LazyOption").field("storage_key", &self.storage_key).finish()
}
}
}
17 changes: 17 additions & 0 deletions near-sdk/src/store/lazy_option/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,21 @@ mod tests {
drop(a);
assert!(!env::storage_has_key(b"a"));
}

#[test]
pub fn test_debug() {
let mut lazy_option = LazyOption::new(b"m", None);
if cfg!(feature = "expensive-debug") {
assert_eq!(format!("{:?}", lazy_option), "None");
} else {
assert_eq!(format!("{:?}", lazy_option), "LazyOption { storage_key: [109] }");
}

lazy_option.set(Some(1u64));
if cfg!(feature = "expensive-debug") {
assert_eq!(format!("{:?}", lazy_option), "Some(1)");
} else {
assert_eq!(format!("{:?}", lazy_option), "LazyOption { storage_key: [109] }");
}
}
}

0 comments on commit b40b845

Please sign in to comment.