From 140ac7456484c07c138413019c8b6b336a620cc8 Mon Sep 17 00:00:00 2001 From: Declan Kelly Date: Sun, 7 Jul 2024 15:41:50 -0700 Subject: [PATCH] Split up node tests into node-specific modules --- src/nodes/representation.rs | 269 ++++++- src/nodes/representation/inner_node_256.rs | 108 +++ src/nodes/representation/inner_node_48.rs | 126 +++ .../representation/inner_node_compressed.rs | 244 ++++++ src/nodes/representation/tests.rs | 757 ------------------ 5 files changed, 744 insertions(+), 760 deletions(-) delete mode 100644 src/nodes/representation/tests.rs diff --git a/src/nodes/representation.rs b/src/nodes/representation.rs index 39ffa828..ab7c49bb 100644 --- a/src/nodes/representation.rs +++ b/src/nodes/representation.rs @@ -24,9 +24,6 @@ pub use inner_node_48::*; mod inner_node_compressed; pub use inner_node_compressed::*; -#[cfg(test)] -mod tests; - /// The representation of inner nodes #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] @@ -813,3 +810,269 @@ impl Node for LeafNode, 3>::new(Box::into_raw(Box::new( + LeafNode::new([], 3u8), + ))) + .unwrap() + .cast::(); + p0.set_data(0b001); + + #[repr(align(64))] + struct LargeAlignment; + + let mut p1 = TaggedPointer::, 3>::new(Box::into_raw( + Box::new(LeafNode::new(LargeAlignment, 2u16)), + )) + .unwrap() + .cast::(); + p1.set_data(0b011); + + let mut p2 = TaggedPointer::, 3>::new(Box::into_raw( + Box::new(LeafNode::new(1u64, LargeAlignment)), + )) + .unwrap() + .cast::(); + p2.set_data(0b111); + + unsafe { + // These tests apparently leak memory in Miri's POV unless we explicitly cast + // them back to the original type when we deallocate. The `.cast` calls + // are required, even though the tests pass under normal execution otherwise (I + // guess normal test execution doesn't care about leaked memory?) + drop(Box::from_raw( + p0.cast::>().to_ptr(), + )); + drop(Box::from_raw( + p1.cast::>().to_ptr(), + )); + drop(Box::from_raw( + p2.cast::>().to_ptr(), + )); + } + } + + #[test] + fn opaque_node_ptr_is_correct() { + let mut n4 = InnerNode4::, usize, 16>::empty(); + let mut n16 = InnerNode16::, usize, 16>::empty(); + let mut n48 = InnerNode48::, usize, 16>::empty(); + let mut n256 = InnerNode256::, usize, 16>::empty(); + + let n4_ptr = NodePtr::from(&mut n4).to_opaque(); + let n16_ptr = NodePtr::from(&mut n16).to_opaque(); + let n48_ptr = NodePtr::from(&mut n48).to_opaque(); + let n256_ptr = NodePtr::from(&mut n256).to_opaque(); + + assert!(n4_ptr.is::, usize, 16>>()); + assert!(n16_ptr.is::, usize, 16>>()); + assert!(n48_ptr.is::, usize, 16>>()); + assert!(n256_ptr.is::, usize, 16>>()); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn node_sizes() { + const DEFAULT_PREFIX_LEN: usize = 4; + const EXPECTED_HEADER_SIZE: usize = DEFAULT_PREFIX_LEN.next_multiple_of(8) + 8; + + assert_eq!( + mem::size_of::>(), + EXPECTED_HEADER_SIZE + ); + // key map: 4 * (1 byte) = 4 bytes + // child map: 4 * (8 bytes (on 64-bit platform)) = 32 + // + // 4 bytes of padding are inserted after the `keys` field to align the field to + // an 8 byte boundary. + assert_eq!( + mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), + EXPECTED_HEADER_SIZE + 40 + ); + // key map: 16 * (1 byte) = 16 bytes + // child map: 16 * (8 bytes (on 64-bit platform)) = 128 + assert_eq!( + mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), + EXPECTED_HEADER_SIZE + 144 + ); + // key map: 256 * (1 byte) = 256 bytes + // child map: 48 * (8 bytes (on 64-bit platform)) = 384 + assert_eq!( + mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), + EXPECTED_HEADER_SIZE + 640 + ); + // child & key map: 256 * (8 bytes (on 64-bit platform)) = 2048 + assert_eq!( + mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), + EXPECTED_HEADER_SIZE + 2048 + ); + + // Assert that pointer is expected size and has non-null optimization + assert_eq!( + mem::size_of::, (), DEFAULT_PREFIX_LEN>>>(), + 8 + ); + assert_eq!( + mem::size_of::, (), DEFAULT_PREFIX_LEN>>(), + 8 + ); + } + + #[test] + fn node_alignment() { + assert_eq!(mem::align_of::, u8, 16>>(), 8); + assert_eq!(mem::align_of::, u8, 16>>(), 8); + assert_eq!(mem::align_of::, u8, 16>>(), 8); + assert_eq!(mem::align_of::, u8, 16>>(), 8); + assert_eq!(mem::align_of::, u8, 16>>(), 8); + assert_eq!(mem::align_of::>(), 8); + + assert_eq!( + mem::align_of::, u8, 16>>(), + mem::align_of::() + ); + assert_eq!( + mem::align_of::, u8, 16>>(), + mem::align_of::() + ); + assert_eq!( + mem::align_of::, u8, 16>>(), + mem::align_of::() + ); + assert_eq!( + mem::align_of::, u8, 16>>(), + mem::align_of::() + ); + assert_eq!( + mem::align_of::, u8, 16>>(), + mem::align_of::() + ); + + let n4 = InnerNode4::, (), 16>::empty(); + let n16 = InnerNode4::, (), 16>::empty(); + let n48 = InnerNode4::, (), 16>::empty(); + let n256 = InnerNode4::, (), 16>::empty(); + + let n4_ptr = (&n4 as *const InnerNode4, (), 16>).addr(); + let n16_ptr = (&n16 as *const InnerNode4, (), 16>).addr(); + let n48_ptr = (&n48 as *const InnerNode4, (), 16>).addr(); + let n256_ptr = (&n256 as *const InnerNode4, (), 16>).addr(); + + // Ensure that there are 3 bits of unused space in the node pointer because of + // the alignment. + assert!(n4_ptr.trailing_zeros() >= 3); + assert!(n16_ptr.trailing_zeros() >= 3); + assert!(n48_ptr.trailing_zeros() >= 3); + assert!(n256_ptr.trailing_zeros() >= 3); + } + + pub(crate) fn inner_node_write_child_test( + mut node: impl InnerNode, Value = ()>, + num_children: usize, + ) { + let mut leaves = vec![LeafNode::new(vec![].into(), ()); num_children]; + + assert!(!node.is_full()); + { + let leaf_pointers = leaves + .iter_mut() + .map(|leaf| NodePtr::from(leaf).to_opaque()) + .collect::>(); + + for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { + node.write_child(u8::try_from(idx).unwrap(), leaf_pointer); + } + + for (idx, leaf_pointer) in leaf_pointers.into_iter().enumerate() { + assert_eq!( + node.lookup_child(u8::try_from(idx).unwrap()), + Some(leaf_pointer) + ); + } + } + + assert!(node.is_full()); + } + + pub fn inner_node_remove_child_test( + mut node: impl InnerNode, Value = ()>, + num_children: usize, + ) { + let mut leaves = vec![LeafNode::new(vec![].into(), ()); num_children]; + + assert!(!node.is_full()); + { + let leaf_pointers = leaves + .iter_mut() + .map(|leaf| NodePtr::from(leaf).to_opaque()) + .collect::>(); + + for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { + node.write_child(u8::try_from(idx).unwrap(), leaf_pointer); + } + + for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { + assert_eq!( + node.lookup_child(u8::try_from(idx).unwrap()), + Some(leaf_pointer) + ); + } + + for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { + assert_eq!( + node.remove_child(u8::try_from(idx).unwrap()), + Some(leaf_pointer) + ); + + assert_eq!(node.lookup_child(u8::try_from(idx).unwrap()), None); + } + } + assert!(!node.is_full()); + } + + pub(crate) fn inner_node_shrink_test( + mut node: impl InnerNode, Value = ()>, + num_children: usize, + ) { + let mut leaves = vec![LeafNode::new(vec![].into(), ()); num_children]; + + let leaf_pointers = leaves + .iter_mut() + .map(|leaf| NodePtr::from(leaf).to_opaque()) + .collect::>(); + + for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { + node.write_child(u8::try_from(idx).unwrap(), leaf_pointer); + } + + let shrunk_node = node.shrink(); + + for (idx, leaf_pointer) in leaf_pointers.into_iter().enumerate() { + assert_eq!( + shrunk_node.lookup_child(u8::try_from(idx).unwrap()), + Some(leaf_pointer) + ); + } + } + + // --------------------------------------- ITERATORS + // --------------------------------------- + + pub(crate) type FixtureReturn = ( + Node, + [LeafNode, (), 16>; N], + [OpaqueNodePtr, (), 16>; N], + ); +} diff --git a/src/nodes/representation/inner_node_256.rs b/src/nodes/representation/inner_node_256.rs index 1bbdce4a..9c7b47e6 100644 --- a/src/nodes/representation/inner_node_256.rs +++ b/src/nodes/representation/inner_node_256.rs @@ -310,3 +310,111 @@ impl<'a, K: AsBytes, V, const PREFIX_LEN: usize> FusedIterator for Node256Iter<'a, K, V, PREFIX_LEN> { } + +#[cfg(test)] +mod tests { + use crate::{ + nodes::representation::tests::{ + inner_node_remove_child_test, inner_node_shrink_test, inner_node_write_child_test, + FixtureReturn, + }, + LeafNode, + }; + + use super::*; + + #[test] + fn lookup() { + let mut n = InnerNode256::, (), 16>::empty(); + let mut l1 = LeafNode::new(Box::from([]), ()); + let mut l2 = LeafNode::new(Box::from([]), ()); + let mut l3 = LeafNode::new(Box::from([]), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + + assert!(n.lookup_child(123).is_none()); + + n.header.inc_num_children(); + n.header.inc_num_children(); + n.header.inc_num_children(); + + n.child_pointers[1] = Some(l1_ptr); + n.child_pointers[123] = Some(l2_ptr); + n.child_pointers[3] = Some(l3_ptr); + + assert_eq!(n.lookup_child(123), Some(l2_ptr)); + } + + #[test] + fn write_child() { + inner_node_write_child_test(InnerNode256::<_, _, 16>::empty(), 256) + } + + #[test] + #[should_panic] + fn write_child_full_panic() { + inner_node_write_child_test(InnerNode256::<_, _, 16>::empty(), 257) + } + + #[test] + fn remove_child() { + inner_node_remove_child_test(InnerNode256::<_, _, 16>::empty(), 256) + } + + #[test] + #[should_panic] + fn grow() { + let n = InnerNode256::, (), 16>::empty(); + + n.grow(); + } + + #[test] + fn shrink() { + inner_node_shrink_test(InnerNode256::<_, _, 16>::empty(), 48); + } + + #[test] + #[should_panic] + fn shrink_too_many_children_panic() { + inner_node_shrink_test(InnerNode256::<_, _, 16>::empty(), 49); + } + + fn fixture() -> FixtureReturn, (), 16>, 4> { + let mut n4 = InnerNode256::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let mut l4 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + let l4_ptr = NodePtr::from(&mut l4).to_opaque(); + + n4.write_child(3, l1_ptr); + n4.write_child(255, l2_ptr); + n4.write_child(0u8, l3_ptr); + n4.write_child(85, l4_ptr); + + (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) + } + + #[test] + fn iterate() { + let (node, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = fixture(); + + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 3 && ptr == l1_ptr)); + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 255 && ptr == l2_ptr)); + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 0u8 && ptr == l3_ptr)); + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 85 && ptr == l4_ptr)); + } +} diff --git a/src/nodes/representation/inner_node_48.rs b/src/nodes/representation/inner_node_48.rs index f8de2baf..bfd03b2c 100644 --- a/src/nodes/representation/inner_node_48.rs +++ b/src/nodes/representation/inner_node_48.rs @@ -573,3 +573,129 @@ impl<'a, K: AsBytes, V, const PREFIX_LEN: usize> FusedIterator for Node48Iter<'a, K, V, PREFIX_LEN> { } + +#[cfg(test)] +mod tests { + use crate::{ + nodes::representation::tests::{ + inner_node_remove_child_test, inner_node_shrink_test, inner_node_write_child_test, + FixtureReturn, + }, + LeafNode, + }; + + use super::*; + + #[test] + fn lookup() { + let mut n = InnerNode48::, (), 16>::empty(); + let mut l1 = LeafNode::new(Box::from([]), ()); + let mut l2 = LeafNode::new(Box::from([]), ()); + let mut l3 = LeafNode::new(Box::from([]), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + + assert!(n.lookup_child(123).is_none()); + + n.header.inc_num_children(); + n.header.inc_num_children(); + n.header.inc_num_children(); + + n.child_indices[1] = 2usize.try_into().unwrap(); + n.child_indices[3] = 0usize.try_into().unwrap(); + n.child_indices[123] = 1usize.try_into().unwrap(); + + n.child_pointers[0].write(l1_ptr); + n.child_pointers[1].write(l2_ptr); + n.child_pointers[2].write(l3_ptr); + + assert_eq!(n.lookup_child(123), Some(l2_ptr)); + } + + #[test] + fn write_child() { + inner_node_write_child_test(InnerNode48::<_, _, 16>::empty(), 48) + } + + #[test] + fn remove_child() { + inner_node_remove_child_test(InnerNode48::<_, _, 16>::empty(), 48) + } + + // #[test] + // #[should_panic] + // fn write_child_full_panic() { + // inner_node_write_child_test(InnerNode48::<_, _, 16>::empty(), 49); + // } + + #[test] + fn grow() { + let mut n48 = InnerNode48::, (), 16>::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + + n48.write_child(3, l1_ptr); + n48.write_child(123, l2_ptr); + n48.write_child(1, l3_ptr); + + let n256 = n48.grow(); + + assert_eq!(n256.lookup_child(3), Some(l1_ptr)); + assert_eq!(n256.lookup_child(123), Some(l2_ptr)); + assert_eq!(n256.lookup_child(1), Some(l3_ptr)); + assert_eq!(n256.lookup_child(4), None); + } + + #[test] + fn shrink() { + inner_node_shrink_test(InnerNode48::<_, _, 16>::empty(), 16); + } + + #[test] + #[should_panic] + fn shrink_too_many_children_panic() { + inner_node_shrink_test(InnerNode48::<_, _, 16>::empty(), 17); + } + + fn fixture() -> FixtureReturn, (), 16>, 4> { + let mut n4 = InnerNode48::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let mut l4 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + let l4_ptr = NodePtr::from(&mut l4).to_opaque(); + + n4.write_child(3, l1_ptr); + n4.write_child(255, l2_ptr); + n4.write_child(0u8, l3_ptr); + n4.write_child(85, l4_ptr); + + (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) + } + + #[test] + fn iterate() { + let (node, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = fixture(); + + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 3 && ptr == l1_ptr)); + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 255 && ptr == l2_ptr)); + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 0u8 && ptr == l3_ptr)); + assert!(node + .iter() + .any(|(key_fragment, ptr)| key_fragment == 85 && ptr == l4_ptr)); + } +} diff --git a/src/nodes/representation/inner_node_compressed.rs b/src/nodes/representation/inner_node_compressed.rs index 03627e3e..1fa7a1bb 100644 --- a/src/nodes/representation/inner_node_compressed.rs +++ b/src/nodes/representation/inner_node_compressed.rs @@ -619,3 +619,247 @@ impl InnerNode self.inner_deep_clone() } } + +#[cfg(test)] +mod tests { + use crate::{ + nodes::representation::tests::{ + inner_node_remove_child_test, inner_node_shrink_test, inner_node_write_child_test, + FixtureReturn, + }, + LeafNode, + }; + + use super::*; + + #[test] + fn node4_lookup() { + let mut n = InnerNode4::, (), 16>::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + + assert!(n.lookup_child(123).is_none()); + + n.header.inc_num_children(); + n.header.inc_num_children(); + n.header.inc_num_children(); + + n.keys[0].write(3); + n.keys[1].write(123); + n.keys[2].write(1); + + n.child_pointers[0].write(l1_ptr); + n.child_pointers[1].write(l2_ptr); + n.child_pointers[2].write(l3_ptr); + + assert_eq!(n.lookup_child(123), Some(l2_ptr)); + } + + #[test] + fn node4_write_child() { + inner_node_write_child_test(InnerNode4::<_, _, 16>::empty(), 4) + } + + #[test] + fn node4_remove_child() { + inner_node_remove_child_test(InnerNode4::<_, _, 16>::empty(), 4) + } + + // #[test] + // #[should_panic] + // fn node4_write_child_full_panic() { + // inner_node_write_child_test(InnerNode4::<_, _, 16>::empty(), 5); + // } + + #[test] + fn node4_grow() { + let mut n4 = InnerNode4::, (), 16>::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + + n4.write_child(3, l1_ptr); + n4.write_child(123, l2_ptr); + n4.write_child(1, l3_ptr); + + let n16 = n4.grow(); + + assert_eq!(n16.lookup_child(3), Some(l1_ptr)); + assert_eq!(n16.lookup_child(123), Some(l2_ptr)); + assert_eq!(n16.lookup_child(1), Some(l3_ptr)); + assert_eq!(n16.lookup_child(4), None); + } + + #[test] + #[should_panic] + fn node4_shrink() { + let n4 = InnerNode4::, (), 16>::empty(); + + n4.shrink(); + } + + #[test] + fn node16_lookup() { + let mut n = InnerNode16::, (), 16>::empty(); + let mut l1 = LeafNode::new(Box::from([]), ()); + let mut l2 = LeafNode::new(Box::from([]), ()); + let mut l3 = LeafNode::new(Box::from([]), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + + assert!(n.lookup_child(123).is_none()); + + n.header.inc_num_children(); + n.header.inc_num_children(); + n.header.inc_num_children(); + + n.keys[0].write(3); + n.keys[1].write(123); + n.keys[2].write(1); + + n.child_pointers[0].write(l1_ptr); + n.child_pointers[1].write(l2_ptr); + n.child_pointers[2].write(l3_ptr); + + assert_eq!(n.lookup_child(123), Some(l2_ptr)); + } + + #[test] + fn node16_write_child() { + inner_node_write_child_test(InnerNode16::<_, _, 16>::empty(), 16) + } + + #[test] + fn node16_remove_child() { + inner_node_remove_child_test(InnerNode16::<_, _, 16>::empty(), 16) + } + + // #[test] + // #[should_panic] + // fn node16_write_child_full_panic() { + // inner_node_write_child_test(InnerNode16::<_, _, 16>::empty(), 17); + // } + + #[test] + #[should_panic] + fn node16_grow_panic() { + let mut n16 = InnerNode16::, (), 16>::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + + n16.write_child(3, l1_ptr); + n16.write_child(123, l2_ptr); + n16.write_child(1, l3_ptr); + + let n48 = n16.grow(); + + assert_eq!(n48.lookup_child(3), Some(l1_ptr)); + assert_eq!(n48.lookup_child(123), Some(l2_ptr)); + assert_eq!(n48.lookup_child(1), Some(l3_ptr)); + assert_eq!(n48.lookup_child(4), None); + } + + #[test] + fn node16_grow() { + let mut n16 = InnerNode16::, (), 16>::empty(); + let mut v = Vec::new(); + for i in 0..16 { + let mut l = LeafNode::new(vec![].into(), ()); + let l_ptr = NodePtr::from(&mut l).to_opaque(); + v.push(l_ptr); + n16.write_child(i * 2, l_ptr); + } + + let n48 = n16.grow(); + + for i in 0..16 { + assert_eq!(n48.lookup_child(i * 2), Some(v[i as usize])); + } + } + + #[test] + fn node16_shrink() { + inner_node_shrink_test(InnerNode16::<_, _, 16>::empty(), 4); + } + + #[test] + #[should_panic] + fn node16_shrink_too_many_children_panic() { + inner_node_shrink_test(InnerNode16::<_, _, 16>::empty(), 5); + } + + fn node4_fixture() -> FixtureReturn, (), 16>, 4> { + let mut n4 = InnerNode4::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let mut l4 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + let l4_ptr = NodePtr::from(&mut l4).to_opaque(); + + n4.write_child(3, l1_ptr); + n4.write_child(255, l2_ptr); + n4.write_child(0u8, l3_ptr); + n4.write_child(85, l4_ptr); + + (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) + } + + #[test] + fn node4_iterate() { + let (n4, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = node4_fixture(); + + assert_eq!( + [(0u8, l3_ptr), (3, l1_ptr), (85, l4_ptr), (255, l2_ptr)] + .into_iter() + .collect::>(), + n4.iter().collect::>(), + "expected values did not match for range [{:?}]", + .. + ); + } + + fn node16_fixture() -> FixtureReturn, (), 16>, 4> { + let mut n4 = InnerNode16::empty(); + let mut l1 = LeafNode::new(vec![].into(), ()); + let mut l2 = LeafNode::new(vec![].into(), ()); + let mut l3 = LeafNode::new(vec![].into(), ()); + let mut l4 = LeafNode::new(vec![].into(), ()); + let l1_ptr = NodePtr::from(&mut l1).to_opaque(); + let l2_ptr = NodePtr::from(&mut l2).to_opaque(); + let l3_ptr = NodePtr::from(&mut l3).to_opaque(); + let l4_ptr = NodePtr::from(&mut l4).to_opaque(); + + n4.write_child(3, l1_ptr); + n4.write_child(255, l2_ptr); + n4.write_child(0u8, l3_ptr); + n4.write_child(85, l4_ptr); + + (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) + } + + #[test] + fn node16_iterate() { + let (node, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = node16_fixture(); + + let pairs = node.iter().collect::>(); + assert_eq!( + pairs, + &[(0u8, l3_ptr), (3, l1_ptr), (85, l4_ptr), (255, l2_ptr),] + ) + } +} diff --git a/src/nodes/representation/tests.rs b/src/nodes/representation/tests.rs deleted file mode 100644 index cc06e39f..00000000 --- a/src/nodes/representation/tests.rs +++ /dev/null @@ -1,757 +0,0 @@ -use super::*; -use std::mem; - -#[cfg(not(feature = "nightly"))] -use sptr::Strict; - -// This test is important because it verifies that we can transform a tagged -// pointer to a type with large and small alignment and back without issues. -#[test] -fn leaf_node_alignment() { - let mut p0 = TaggedPointer::, 3>::new(Box::into_raw(Box::new( - LeafNode::new([], 3u8), - ))) - .unwrap() - .cast::(); - p0.set_data(0b001); - - #[repr(align(64))] - struct LargeAlignment; - - let mut p1 = TaggedPointer::, 3>::new(Box::into_raw(Box::new( - LeafNode::new(LargeAlignment, 2u16), - ))) - .unwrap() - .cast::(); - p1.set_data(0b011); - - let mut p2 = TaggedPointer::, 3>::new(Box::into_raw(Box::new( - LeafNode::new(1u64, LargeAlignment), - ))) - .unwrap() - .cast::(); - p2.set_data(0b111); - - unsafe { - // These tests apparently leak memory in Miri's POV unless we explicitly cast - // them back to the original type when we deallocate. The `.cast` calls - // are required, even though the tests pass under normal execution otherwise (I - // guess normal test execution doesn't care about leaked memory?) - drop(Box::from_raw( - p0.cast::>().to_ptr(), - )); - drop(Box::from_raw( - p1.cast::>().to_ptr(), - )); - drop(Box::from_raw( - p2.cast::>().to_ptr(), - )); - } -} - -#[test] -fn opaque_node_ptr_is_correct() { - let mut n4 = InnerNode4::, usize, 16>::empty(); - let mut n16 = InnerNode16::, usize, 16>::empty(); - let mut n48 = InnerNode48::, usize, 16>::empty(); - let mut n256 = InnerNode256::, usize, 16>::empty(); - - let n4_ptr = NodePtr::from(&mut n4).to_opaque(); - let n16_ptr = NodePtr::from(&mut n16).to_opaque(); - let n48_ptr = NodePtr::from(&mut n48).to_opaque(); - let n256_ptr = NodePtr::from(&mut n256).to_opaque(); - - assert!(n4_ptr.is::, usize, 16>>()); - assert!(n16_ptr.is::, usize, 16>>()); - assert!(n48_ptr.is::, usize, 16>>()); - assert!(n256_ptr.is::, usize, 16>>()); -} - -#[test] -#[cfg(target_pointer_width = "64")] -fn node_sizes() { - const DEFAULT_PREFIX_LEN: usize = 4; - const EXPECTED_HEADER_SIZE: usize = DEFAULT_PREFIX_LEN.next_multiple_of(8) + 8; - - assert_eq!( - mem::size_of::>(), - EXPECTED_HEADER_SIZE - ); - // key map: 4 * (1 byte) = 4 bytes - // child map: 4 * (8 bytes (on 64-bit platform)) = 32 - // - // 4 bytes of padding are inserted after the `keys` field to align the field to - // an 8 byte boundary. - assert_eq!( - mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), - EXPECTED_HEADER_SIZE + 40 - ); - // key map: 16 * (1 byte) = 16 bytes - // child map: 16 * (8 bytes (on 64-bit platform)) = 128 - assert_eq!( - mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), - EXPECTED_HEADER_SIZE + 144 - ); - // key map: 256 * (1 byte) = 256 bytes - // child map: 48 * (8 bytes (on 64-bit platform)) = 384 - assert_eq!( - mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), - EXPECTED_HEADER_SIZE + 640 - ); - // child & key map: 256 * (8 bytes (on 64-bit platform)) = 2048 - assert_eq!( - mem::size_of::, usize, DEFAULT_PREFIX_LEN>>(), - EXPECTED_HEADER_SIZE + 2048 - ); - - // Assert that pointer is expected size and has non-null optimization - assert_eq!( - mem::size_of::, (), DEFAULT_PREFIX_LEN>>>(), - 8 - ); - assert_eq!( - mem::size_of::, (), DEFAULT_PREFIX_LEN>>(), - 8 - ); -} - -#[test] -fn node_alignment() { - assert_eq!(mem::align_of::, u8, 16>>(), 8); - assert_eq!(mem::align_of::, u8, 16>>(), 8); - assert_eq!(mem::align_of::, u8, 16>>(), 8); - assert_eq!(mem::align_of::, u8, 16>>(), 8); - assert_eq!(mem::align_of::, u8, 16>>(), 8); - assert_eq!(mem::align_of::>(), 8); - - assert_eq!( - mem::align_of::, u8, 16>>(), - mem::align_of::() - ); - assert_eq!( - mem::align_of::, u8, 16>>(), - mem::align_of::() - ); - assert_eq!( - mem::align_of::, u8, 16>>(), - mem::align_of::() - ); - assert_eq!( - mem::align_of::, u8, 16>>(), - mem::align_of::() - ); - assert_eq!( - mem::align_of::, u8, 16>>(), - mem::align_of::() - ); - - let n4 = InnerNode4::, (), 16>::empty(); - let n16 = InnerNode4::, (), 16>::empty(); - let n48 = InnerNode4::, (), 16>::empty(); - let n256 = InnerNode4::, (), 16>::empty(); - - let n4_ptr = (&n4 as *const InnerNode4, (), 16>).addr(); - let n16_ptr = (&n16 as *const InnerNode4, (), 16>).addr(); - let n48_ptr = (&n48 as *const InnerNode4, (), 16>).addr(); - let n256_ptr = (&n256 as *const InnerNode4, (), 16>).addr(); - - // Ensure that there are 3 bits of unused space in the node pointer because of - // the alignment. - assert!(n4_ptr.trailing_zeros() >= 3); - assert!(n16_ptr.trailing_zeros() >= 3); - assert!(n48_ptr.trailing_zeros() >= 3); - assert!(n256_ptr.trailing_zeros() >= 3); -} - -fn inner_node_write_child_test( - mut node: impl InnerNode, Value = ()>, - num_children: usize, -) { - let mut leaves = vec![LeafNode::new(vec![].into(), ()); num_children]; - - assert!(!node.is_full()); - { - let leaf_pointers = leaves - .iter_mut() - .map(|leaf| NodePtr::from(leaf).to_opaque()) - .collect::>(); - - for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { - println!("{idx}"); - node.write_child(u8::try_from(idx).unwrap(), leaf_pointer); - } - - for (idx, leaf_pointer) in leaf_pointers.into_iter().enumerate() { - assert_eq!( - node.lookup_child(u8::try_from(idx).unwrap()), - Some(leaf_pointer) - ); - } - } - // println!("{}") - assert!(node.is_full()); -} - -fn inner_node_remove_child_test( - mut node: impl InnerNode, Value = ()>, - num_children: usize, -) { - let mut leaves = vec![LeafNode::new(vec![].into(), ()); num_children]; - - assert!(!node.is_full()); - { - let leaf_pointers = leaves - .iter_mut() - .map(|leaf| NodePtr::from(leaf).to_opaque()) - .collect::>(); - - for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { - node.write_child(u8::try_from(idx).unwrap(), leaf_pointer); - } - - for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { - assert_eq!( - node.lookup_child(u8::try_from(idx).unwrap()), - Some(leaf_pointer) - ); - } - - for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { - assert_eq!( - node.remove_child(u8::try_from(idx).unwrap()), - Some(leaf_pointer) - ); - - assert_eq!(node.lookup_child(u8::try_from(idx).unwrap()), None); - } - } - assert!(!node.is_full()); -} - -fn inner_node_shrink_test( - mut node: impl InnerNode, Value = ()>, - num_children: usize, -) { - let mut leaves = vec![LeafNode::new(vec![].into(), ()); num_children]; - - let leaf_pointers = leaves - .iter_mut() - .map(|leaf| NodePtr::from(leaf).to_opaque()) - .collect::>(); - - for (idx, leaf_pointer) in leaf_pointers.iter().copied().enumerate() { - node.write_child(u8::try_from(idx).unwrap(), leaf_pointer); - } - - let shrunk_node = node.shrink(); - - for (idx, leaf_pointer) in leaf_pointers.into_iter().enumerate() { - assert_eq!( - shrunk_node.lookup_child(u8::try_from(idx).unwrap()), - Some(leaf_pointer) - ); - } -} - -#[test] -fn node4_lookup() { - let mut n = InnerNode4::, (), 16>::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - - assert!(n.lookup_child(123).is_none()); - - n.header.inc_num_children(); - n.header.inc_num_children(); - n.header.inc_num_children(); - - n.keys[0].write(3); - n.keys[1].write(123); - n.keys[2].write(1); - - n.child_pointers[0].write(l1_ptr); - n.child_pointers[1].write(l2_ptr); - n.child_pointers[2].write(l3_ptr); - - assert_eq!(n.lookup_child(123), Some(l2_ptr)); -} - -#[test] -fn node4_write_child() { - inner_node_write_child_test(InnerNode4::<_, _, 16>::empty(), 4) -} - -#[test] -fn node4_remove_child() { - inner_node_remove_child_test(InnerNode4::<_, _, 16>::empty(), 4) -} - -// #[test] -// #[should_panic] -// fn node4_write_child_full_panic() { -// inner_node_write_child_test(InnerNode4::empty(), 5); -// } - -#[test] -fn node4_grow() { - let mut n4 = InnerNode4::, (), 16>::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - - n4.write_child(3, l1_ptr); - n4.write_child(123, l2_ptr); - n4.write_child(1, l3_ptr); - - let n16 = n4.grow(); - - assert_eq!(n16.lookup_child(3), Some(l1_ptr)); - assert_eq!(n16.lookup_child(123), Some(l2_ptr)); - assert_eq!(n16.lookup_child(1), Some(l3_ptr)); - assert_eq!(n16.lookup_child(4), None); -} - -#[test] -#[should_panic] -fn node4_shrink() { - let n4 = InnerNode4::, (), 16>::empty(); - - n4.shrink(); -} - -#[test] -fn node16_lookup() { - let mut n = InnerNode16::, (), 16>::empty(); - let mut l1 = LeafNode::new(Box::from([]), ()); - let mut l2 = LeafNode::new(Box::from([]), ()); - let mut l3 = LeafNode::new(Box::from([]), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - - assert!(n.lookup_child(123).is_none()); - - n.header.inc_num_children(); - n.header.inc_num_children(); - n.header.inc_num_children(); - - n.keys[0].write(3); - n.keys[1].write(123); - n.keys[2].write(1); - - n.child_pointers[0].write(l1_ptr); - n.child_pointers[1].write(l2_ptr); - n.child_pointers[2].write(l3_ptr); - - assert_eq!(n.lookup_child(123), Some(l2_ptr)); -} - -#[test] -fn node16_write_child() { - inner_node_write_child_test(InnerNode16::<_, _, 16>::empty(), 16) -} - -#[test] -fn node16_remove_child() { - inner_node_remove_child_test(InnerNode16::<_, _, 16>::empty(), 16) -} - -// #[test] -// #[should_panic] -// fn node16_write_child_full_panic() { -// inner_node_write_child_test(InnerNode16::empty(), 17); -// } - -#[test] -#[should_panic] -fn node16_grow_panic() { - let mut n16 = InnerNode16::, (), 16>::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - - n16.write_child(3, l1_ptr); - n16.write_child(123, l2_ptr); - n16.write_child(1, l3_ptr); - - let n48 = n16.grow(); - - assert_eq!(n48.lookup_child(3), Some(l1_ptr)); - assert_eq!(n48.lookup_child(123), Some(l2_ptr)); - assert_eq!(n48.lookup_child(1), Some(l3_ptr)); - assert_eq!(n48.lookup_child(4), None); -} - -#[test] -fn node16_grow() { - let mut n16 = InnerNode16::, (), 16>::empty(); - let mut v = Vec::new(); - for i in 0..16 { - let mut l = LeafNode::new(vec![].into(), ()); - let l_ptr = NodePtr::from(&mut l).to_opaque(); - v.push(l_ptr); - n16.write_child(i * 2, l_ptr); - } - - let n48 = n16.grow(); - - for i in 0..16 { - assert_eq!(n48.lookup_child(i * 2), Some(v[i as usize])); - } -} - -#[test] -fn node16_shrink() { - inner_node_shrink_test(InnerNode16::<_, _, 16>::empty(), 4); -} - -#[test] -#[should_panic] -fn node16_shrink_too_many_children_panic() { - inner_node_shrink_test(InnerNode16::<_, _, 16>::empty(), 5); -} - -#[test] -fn node48_lookup() { - let mut n = InnerNode48::, (), 16>::empty(); - let mut l1 = LeafNode::new(Box::from([]), ()); - let mut l2 = LeafNode::new(Box::from([]), ()); - let mut l3 = LeafNode::new(Box::from([]), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - - assert!(n.lookup_child(123).is_none()); - - n.header.inc_num_children(); - n.header.inc_num_children(); - n.header.inc_num_children(); - - n.child_indices[1] = 2usize.try_into().unwrap(); - n.child_indices[3] = 0usize.try_into().unwrap(); - n.child_indices[123] = 1usize.try_into().unwrap(); - - n.child_pointers[0].write(l1_ptr); - n.child_pointers[1].write(l2_ptr); - n.child_pointers[2].write(l3_ptr); - - assert_eq!(n.lookup_child(123), Some(l2_ptr)); -} - -#[test] -fn node48_write_child() { - inner_node_write_child_test(InnerNode48::<_, _, 16>::empty(), 48) -} - -#[test] -fn node48_remove_child() { - inner_node_remove_child_test(InnerNode48::<_, _, 16>::empty(), 48) -} - -#[test] -#[should_panic] -fn node48_write_child_full_panic() { - inner_node_write_child_test(InnerNode48::<_, _, 16>::empty(), 49); -} - -#[test] -fn node48_grow() { - let mut n48 = InnerNode48::, (), 16>::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - - n48.write_child(3, l1_ptr); - n48.write_child(123, l2_ptr); - n48.write_child(1, l3_ptr); - - let n256 = n48.grow(); - - assert_eq!(n256.lookup_child(3), Some(l1_ptr)); - assert_eq!(n256.lookup_child(123), Some(l2_ptr)); - assert_eq!(n256.lookup_child(1), Some(l3_ptr)); - assert_eq!(n256.lookup_child(4), None); -} - -#[test] -fn node48_shrink() { - inner_node_shrink_test(InnerNode48::<_, _, 16>::empty(), 16); -} - -#[test] -#[should_panic] -fn node48_shrink_too_many_children_panic() { - inner_node_shrink_test(InnerNode48::<_, _, 16>::empty(), 17); -} - -#[test] -fn node256_lookup() { - let mut n = InnerNode256::, (), 16>::empty(); - let mut l1 = LeafNode::new(Box::from([]), ()); - let mut l2 = LeafNode::new(Box::from([]), ()); - let mut l3 = LeafNode::new(Box::from([]), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - - assert!(n.lookup_child(123).is_none()); - - n.header.inc_num_children(); - n.header.inc_num_children(); - n.header.inc_num_children(); - - n.child_pointers[1] = Some(l1_ptr); - n.child_pointers[123] = Some(l2_ptr); - n.child_pointers[3] = Some(l3_ptr); - - assert_eq!(n.lookup_child(123), Some(l2_ptr)); -} - -#[test] -fn node256_write_child() { - inner_node_write_child_test(InnerNode256::<_, _, 16>::empty(), 256) -} - -#[test] -fn node256_remove_child() { - inner_node_remove_child_test(InnerNode256::<_, _, 16>::empty(), 256) -} - -#[test] -#[should_panic] -fn node256_grow() { - let n = InnerNode256::, (), 16>::empty(); - - n.grow(); -} - -#[test] -fn node256_shrink() { - inner_node_shrink_test(InnerNode256::<_, _, 16>::empty(), 48); -} - -#[test] -#[should_panic] -fn node256_shrink_too_many_children_panic() { - inner_node_shrink_test(InnerNode256::<_, _, 16>::empty(), 49); -} - -// #[test] -// fn empty_prefix_bytes_match() { -// let mut h = Header::empty(); - -// h.extend_prefix(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]); -// h.ltrim_prefix(PREFIX_LEN); -// // 6 bytes are represented - -// assert_eq!(h.match_prefix(&[1, 2, 3]), 0); -// assert_eq!(h.match_prefix(&[0]), 0); -// assert_eq!(h.match_prefix(&[]), 0); -// assert_eq!(h.match_prefix(&[1, 2, 3, 4, 5, 6]), 0); -// assert_eq!(h.match_prefix(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), 0); - -// assert_eq!(h.match_prefix(&[9, 10, 11, 12]), 4); -// assert_eq!(h.match_prefix(&[9, 10, 11, 12, 13, 14]), 6); -// } - -#[test] -fn header_delete_prefix() { - let mut h = Header::<16>::new(&[1, 2, 3, 4, 5, 6, 7, 8], 8); - assert_eq!(h.read_prefix(), &[1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(h.prefix_len(), 8); - - h.ltrim_by(0); - assert_eq!(h.read_prefix(), &[1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(h.prefix_len(), 8); - - h.ltrim_by(3); - assert_eq!(h.read_prefix(), &[4, 5, 6, 7, 8]); - assert_eq!(h.prefix_len(), 5); - - h.ltrim_by(1); - assert_eq!(h.read_prefix(), &[5, 6, 7, 8]); - assert_eq!(h.prefix_len(), 4); - - h.ltrim_by(4); - assert_eq!(h.read_prefix(), &[]); - assert_eq!(h.prefix_len(), 0); -} - -#[test] -#[should_panic] -fn header_ltrim_prefix_too_many_bytes_panic() { - let mut h = Header::<16>::new(&[1, 2, 3, 4, 5, 6, 7, 8], 8); - assert_eq!(h.read_prefix(), &[1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(h.prefix_len(), 8); - - h.ltrim_by(10); -} - -#[test] -#[should_panic] -fn header_ltrim_prefix_non_stored_bytes_panic() { - let mut h = Header::<16>::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14], 14); - assert_eq!(h.read_prefix(), &[1, 2, 3, 4, 5, 6, 7, 8]); - assert_eq!(h.prefix_len(), 8); - - h.ltrim_by(0); -} - -// --------------------------------------- ITERATORS -// --------------------------------------- - -type FixtureReturn = ( - Node, - [LeafNode, (), 16>; N], - [OpaqueNodePtr, (), 16>; N], -); - -fn node4_fixture() -> FixtureReturn, (), 16>, 4> { - let mut n4 = InnerNode4::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let mut l4 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - let l4_ptr = NodePtr::from(&mut l4).to_opaque(); - - n4.write_child(3, l1_ptr); - n4.write_child(255, l2_ptr); - n4.write_child(0u8, l3_ptr); - n4.write_child(85, l4_ptr); - - (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) -} - -#[test] -fn node4_iterate() { - let (n4, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = node4_fixture(); - - assert_eq!( - [(0u8, l3_ptr), (3, l1_ptr), (85, l4_ptr), (255, l2_ptr)] - .into_iter() - .collect::>(), - n4.iter().collect::>(), - "expected values did not match for range [{:?}]", - .. - ); -} - -fn node16_fixture() -> FixtureReturn, (), 16>, 4> { - let mut n4 = InnerNode16::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let mut l4 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - let l4_ptr = NodePtr::from(&mut l4).to_opaque(); - - n4.write_child(3, l1_ptr); - n4.write_child(255, l2_ptr); - n4.write_child(0u8, l3_ptr); - n4.write_child(85, l4_ptr); - - (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) -} - -#[test] -fn node16_iterate() { - let (node, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = node16_fixture(); - - let pairs = node.iter().collect::>(); - assert_eq!( - pairs, - &[(0u8, l3_ptr), (3, l1_ptr), (85, l4_ptr), (255, l2_ptr),] - ) -} - -fn node48_fixture() -> FixtureReturn, (), 16>, 4> { - let mut n4 = InnerNode48::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let mut l4 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - let l4_ptr = NodePtr::from(&mut l4).to_opaque(); - - n4.write_child(3, l1_ptr); - n4.write_child(255, l2_ptr); - n4.write_child(0u8, l3_ptr); - n4.write_child(85, l4_ptr); - - (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) -} - -#[test] -fn node48_iterate() { - let (node, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = node48_fixture(); - - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 3 && ptr == l1_ptr)); - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 255 && ptr == l2_ptr)); - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 0u8 && ptr == l3_ptr)); - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 85 && ptr == l4_ptr)); -} - -fn node256_fixture() -> FixtureReturn, (), 16>, 4> { - let mut n4 = InnerNode256::empty(); - let mut l1 = LeafNode::new(vec![].into(), ()); - let mut l2 = LeafNode::new(vec![].into(), ()); - let mut l3 = LeafNode::new(vec![].into(), ()); - let mut l4 = LeafNode::new(vec![].into(), ()); - let l1_ptr = NodePtr::from(&mut l1).to_opaque(); - let l2_ptr = NodePtr::from(&mut l2).to_opaque(); - let l3_ptr = NodePtr::from(&mut l3).to_opaque(); - let l4_ptr = NodePtr::from(&mut l4).to_opaque(); - - n4.write_child(3, l1_ptr); - n4.write_child(255, l2_ptr); - n4.write_child(0u8, l3_ptr); - n4.write_child(85, l4_ptr); - - (n4, [l1, l2, l3, l4], [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) -} - -#[test] -fn node256_iterate() { - let (node, _, [l1_ptr, l2_ptr, l3_ptr, l4_ptr]) = node256_fixture(); - - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 3 && ptr == l1_ptr)); - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 255 && ptr == l2_ptr)); - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 0u8 && ptr == l3_ptr)); - assert!(node - .iter() - .any(|(key_fragment, ptr)| key_fragment == 85 && ptr == l4_ptr)); -}