1 //! B+-tree nodes.
2 
3 use super::{slice_insert, slice_shift, Forest, Node, SetValue, INNER_SIZE};
4 use core::borrow::{Borrow, BorrowMut};
5 use core::fmt;
6 
7 /// B+-tree node.
8 ///
9 /// A B+-tree has different node types for inner nodes and leaf nodes. Inner nodes contain M node
10 /// references and M-1 keys while leaf nodes contain N keys and values. Values for M and N are
11 /// chosen such that a node is exactly 64 bytes (a cache line) when keys and values are 32 bits
12 /// each.
13 ///
14 /// An inner node contains at least M/2 node references unless it is the right-most node at its
15 /// level. A leaf node contains at least N/2 keys unless it is the right-most leaf.
16 #[allow(dead_code)] // workaround for https://github.com/rust-lang/rust/issues/64362
17 pub(super) enum NodeData<F: Forest> {
18     Inner {
19         /// The number of keys in this node.
20         /// The number of node references is always one more.
21         size: u8,
22 
23         /// Keys discriminating sub-trees.
24         ///
25         /// The key in `keys[i]` is greater than all keys in `tree[i]` and less than or equal to
26         /// all keys in `tree[i+1]`.
27         keys: [F::Key; INNER_SIZE - 1],
28 
29         /// Sub-trees.
30         tree: [Node; INNER_SIZE],
31     },
32     Leaf {
33         /// Number of key-value pairs in this node.
34         size: u8,
35 
36         // Key array.
37         keys: F::LeafKeys,
38 
39         // Value array.
40         vals: F::LeafValues,
41     },
42     /// An unused node on the free list.
43     Free { next: Option<Node> },
44 }
45 
46 // Implement `Clone` and `Copy` manually, because deriving them would also require `Forest` to
47 // implement `Clone`.
48 impl<F: Forest> Copy for NodeData<F> {}
49 impl<F: Forest> Clone for NodeData<F> {
50     fn clone(&self) -> Self {
51         *self
52     }
53 }
54 
55 impl<F: Forest> NodeData<F> {
56     /// Is this a free/unused node?
57     pub fn is_free(&self) -> bool {
58         match *self {
59             Self::Free { .. } => true,
60             _ => false,
61         }
62     }
63 
64     /// Get the number of entries in this node.
65     ///
66     /// This is the number of outgoing edges in an inner node, or the number of key-value pairs in
67     /// a leaf node.
68     pub fn entries(&self) -> usize {
69         match *self {
70             Self::Inner { size, .. } => usize::from(size) + 1,
71             Self::Leaf { size, .. } => usize::from(size),
72             Self::Free { .. } => panic!("freed node"),
73         }
74     }
75 
76     /// Create an inner node with a single key and two sub-trees.
77     pub fn inner(left: Node, key: F::Key, right: Node) -> Self {
78         // Splat the key and right node to the whole array.
79         // Saves us from inventing a default/reserved value.
80         let mut tree = [right; INNER_SIZE];
81         tree[0] = left;
82         Self::Inner {
83             size: 1,
84             keys: [key; INNER_SIZE - 1],
85             tree,
86         }
87     }
88 
89     /// Create a leaf node with a single key-value pair.
90     pub fn leaf(key: F::Key, value: F::Value) -> Self {
91         Self::Leaf {
92             size: 1,
93             keys: F::splat_key(key),
94             vals: F::splat_value(value),
95         }
96     }
97 
98     /// Unwrap an inner node into two slices (keys, trees).
99     pub fn unwrap_inner(&self) -> (&[F::Key], &[Node]) {
100         match *self {
101             Self::Inner {
102                 size,
103                 ref keys,
104                 ref tree,
105             } => {
106                 let size = usize::from(size);
107                 // TODO: We could probably use `get_unchecked()` here since `size` is always in
108                 // range.
109                 (&keys[0..size], &tree[0..=size])
110             }
111             _ => panic!("Expected inner node"),
112         }
113     }
114 
115     /// Unwrap a leaf node into two slices (keys, values) of the same length.
116     pub fn unwrap_leaf(&self) -> (&[F::Key], &[F::Value]) {
117         match *self {
118             Self::Leaf {
119                 size,
120                 ref keys,
121                 ref vals,
122             } => {
123                 let size = usize::from(size);
124                 let keys = keys.borrow();
125                 let vals = vals.borrow();
126                 // TODO: We could probably use `get_unchecked()` here since `size` is always in
127                 // range.
128                 (&keys[0..size], &vals[0..size])
129             }
130             _ => panic!("Expected leaf node"),
131         }
132     }
133 
134     /// Unwrap a mutable leaf node into two slices (keys, values) of the same length.
135     pub fn unwrap_leaf_mut(&mut self) -> (&mut [F::Key], &mut [F::Value]) {
136         match *self {
137             Self::Leaf {
138                 size,
139                 ref mut keys,
140                 ref mut vals,
141             } => {
142                 let size = usize::from(size);
143                 let keys = keys.borrow_mut();
144                 let vals = vals.borrow_mut();
145                 // TODO: We could probably use `get_unchecked_mut()` here since `size` is always in
146                 // range.
147                 (&mut keys[0..size], &mut vals[0..size])
148             }
149             _ => panic!("Expected leaf node"),
150         }
151     }
152 
153     /// Get the critical key for a leaf node.
154     /// This is simply the first key.
155     pub fn leaf_crit_key(&self) -> F::Key {
156         match *self {
157             Self::Leaf { size, ref keys, .. } => {
158                 debug_assert!(size > 0, "Empty leaf node");
159                 keys.borrow()[0]
160             }
161             _ => panic!("Expected leaf node"),
162         }
163     }
164 
165     /// Try to insert `(key, node)` at key-position `index` in an inner node.
166     /// This means that `key` is inserted at `keys[i]` and `node` is inserted at `tree[i + 1]`.
167     /// If the node is full, this leaves the node unchanged and returns false.
168     pub fn try_inner_insert(&mut self, index: usize, key: F::Key, node: Node) -> bool {
169         match *self {
170             Self::Inner {
171                 ref mut size,
172                 ref mut keys,
173                 ref mut tree,
174             } => {
175                 let sz = usize::from(*size);
176                 debug_assert!(sz <= keys.len());
177                 debug_assert!(index <= sz, "Can't insert at {} with {} keys", index, sz);
178 
179                 if let Some(ks) = keys.get_mut(0..=sz) {
180                     *size = (sz + 1) as u8;
181                     slice_insert(ks, index, key);
182                     slice_insert(&mut tree[1..=sz + 1], index, node);
183                     true
184                 } else {
185                     false
186                 }
187             }
188             _ => panic!("Expected inner node"),
189         }
190     }
191 
192     /// Try to insert `key, value` at `index` in a leaf node, but fail and return false if the node
193     /// is full.
194     pub fn try_leaf_insert(&mut self, index: usize, key: F::Key, value: F::Value) -> bool {
195         match *self {
196             Self::Leaf {
197                 ref mut size,
198                 ref mut keys,
199                 ref mut vals,
200             } => {
201                 let sz = usize::from(*size);
202                 let keys = keys.borrow_mut();
203                 let vals = vals.borrow_mut();
204                 debug_assert!(sz <= keys.len());
205                 debug_assert!(index <= sz);
206 
207                 if let Some(ks) = keys.get_mut(0..=sz) {
208                     *size = (sz + 1) as u8;
209                     slice_insert(ks, index, key);
210                     slice_insert(&mut vals[0..=sz], index, value);
211                     true
212                 } else {
213                     false
214                 }
215             }
216             _ => panic!("Expected leaf node"),
217         }
218     }
219 
220     /// Split off the second half of this node.
221     /// It is assumed that this a completely full inner or leaf node.
222     ///
223     /// The `insert_index` parameter is the position where an insertion was tried and failed. The
224     /// node will be split in half with a bias towards an even split after the insertion is retried.
225     pub fn split(&mut self, insert_index: usize) -> SplitOff<F> {
226         match *self {
227             Self::Inner {
228                 ref mut size,
229                 ref keys,
230                 ref tree,
231             } => {
232                 debug_assert_eq!(usize::from(*size), keys.len(), "Node not full");
233 
234                 // Number of tree entries in the lhs node.
235                 let l_ents = split_pos(tree.len(), insert_index + 1);
236                 let r_ents = tree.len() - l_ents;
237 
238                 // With INNER_SIZE=8, we get l_ents=4 and:
239                 //
240                 // self: [ n0 k0 n1 k1 n2 k2 n3 k3 n4 k4 n5 k5 n6 k6 n7 ]
241                 // lhs:  [ n0 k0 n1 k1 n2 k2 n3 ]
242                 // crit_key = k3 (not present in either node)
243                 // rhs:  [ n4 k4 n5 k5 n6 k6 n7 ]
244 
245                 // 1. Truncate the LHS.
246                 *size = (l_ents - 1) as u8;
247 
248                 // 2. Copy second half to `rhs_data`.
249                 let mut r_keys = *keys;
250                 r_keys[0..r_ents - 1].copy_from_slice(&keys[l_ents..]);
251 
252                 let mut r_tree = *tree;
253                 r_tree[0..r_ents].copy_from_slice(&tree[l_ents..]);
254 
255                 SplitOff {
256                     lhs_entries: l_ents,
257                     rhs_entries: r_ents,
258                     crit_key: keys[l_ents - 1],
259                     rhs_data: Self::Inner {
260                         size: (r_ents - 1) as u8,
261                         keys: r_keys,
262                         tree: r_tree,
263                     },
264                 }
265             }
266             Self::Leaf {
267                 ref mut size,
268                 ref keys,
269                 ref vals,
270             } => {
271                 let o_keys = keys.borrow();
272                 let o_vals = vals.borrow();
273                 debug_assert_eq!(usize::from(*size), o_keys.len(), "Node not full");
274 
275                 let l_size = split_pos(o_keys.len(), insert_index);
276                 let r_size = o_keys.len() - l_size;
277 
278                 // 1. Truncate the LHS node at `l_size`.
279                 *size = l_size as u8;
280 
281                 // 2. Copy second half to `rhs_data`.
282                 let mut r_keys = *keys;
283                 r_keys.borrow_mut()[0..r_size].copy_from_slice(&o_keys[l_size..]);
284 
285                 let mut r_vals = *vals;
286                 r_vals.borrow_mut()[0..r_size].copy_from_slice(&o_vals[l_size..]);
287 
288                 SplitOff {
289                     lhs_entries: l_size,
290                     rhs_entries: r_size,
291                     crit_key: o_keys[l_size],
292                     rhs_data: Self::Leaf {
293                         size: r_size as u8,
294                         keys: r_keys,
295                         vals: r_vals,
296                     },
297                 }
298             }
299             _ => panic!("Expected leaf node"),
300         }
301     }
302 
303     /// Remove the sub-tree at `index` from this inner node.
304     ///
305     /// Note that `index` refers to a sub-tree entry and not a key entry as it does for
306     /// `try_inner_insert()`. It is possible to remove the first sub-tree (which can't be inserted
307     /// by `try_inner_insert()`).
308     ///
309     /// Return an indication of the node's health (i.e. below half capacity).
310     pub fn inner_remove(&mut self, index: usize) -> Removed {
311         match *self {
312             Self::Inner {
313                 ref mut size,
314                 ref mut keys,
315                 ref mut tree,
316             } => {
317                 let ents = usize::from(*size) + 1;
318                 debug_assert!(ents <= tree.len());
319                 debug_assert!(index < ents);
320                 // Leave an invalid 0xff size when node becomes empty.
321                 *size = ents.wrapping_sub(2) as u8;
322                 if ents > 1 {
323                     slice_shift(&mut keys[index.saturating_sub(1)..ents - 1], 1);
324                 }
325                 slice_shift(&mut tree[index..ents], 1);
326                 Removed::new(index, ents - 1, tree.len())
327             }
328             _ => panic!("Expected inner node"),
329         }
330     }
331 
332     /// Remove the key-value pair at `index` from this leaf node.
333     ///
334     /// Return an indication of the node's health (i.e. below half capacity).
335     pub fn leaf_remove(&mut self, index: usize) -> Removed {
336         match *self {
337             Self::Leaf {
338                 ref mut size,
339                 ref mut keys,
340                 ref mut vals,
341             } => {
342                 let sz = usize::from(*size);
343                 let keys = keys.borrow_mut();
344                 let vals = vals.borrow_mut();
345                 *size -= 1;
346                 slice_shift(&mut keys[index..sz], 1);
347                 slice_shift(&mut vals[index..sz], 1);
348                 Removed::new(index, sz - 1, keys.len())
349             }
350             _ => panic!("Expected leaf node"),
351         }
352     }
353 
354     /// Balance this node with its right sibling.
355     ///
356     /// It is assumed that the current node has underflowed. Look at the right sibling node and do
357     /// one of two things:
358     ///
359     /// 1. Move all entries to the right node, leaving this node empty, or
360     /// 2. Distribute entries evenly between the two nodes.
361     ///
362     /// In the first case, `None` is returned. In the second case, the new critical key for the
363     /// right sibling node is returned.
364     pub fn balance(&mut self, crit_key: F::Key, rhs: &mut Self) -> Option<F::Key> {
365         match (self, rhs) {
366             (
367                 &mut Self::Inner {
368                     size: ref mut l_size,
369                     keys: ref mut l_keys,
370                     tree: ref mut l_tree,
371                 },
372                 &mut Self::Inner {
373                     size: ref mut r_size,
374                     keys: ref mut r_keys,
375                     tree: ref mut r_tree,
376                 },
377             ) => {
378                 let l_ents = usize::from(*l_size) + 1;
379                 let r_ents = usize::from(*r_size) + 1;
380                 let ents = l_ents + r_ents;
381 
382                 if ents <= r_tree.len() {
383                     // All entries will fit in the RHS node.
384                     // We'll leave the LHS node empty, but first use it as a scratch space.
385                     *l_size = 0;
386                     // Insert `crit_key` between the two nodes.
387                     l_keys[l_ents - 1] = crit_key;
388                     l_keys[l_ents..ents - 1].copy_from_slice(&r_keys[0..r_ents - 1]);
389                     r_keys[0..ents - 1].copy_from_slice(&l_keys[0..ents - 1]);
390                     l_tree[l_ents..ents].copy_from_slice(&r_tree[0..r_ents]);
391                     r_tree[0..ents].copy_from_slice(&l_tree[0..ents]);
392                     *r_size = (ents - 1) as u8;
393                     None
394                 } else {
395                     // The entries don't all fit in one node. Distribute some from RHS -> LHS.
396                     // Split evenly with a bias to putting one entry in LHS.
397                     let r_goal = ents / 2;
398                     let l_goal = ents - r_goal;
399                     debug_assert!(l_goal > l_ents, "Node must be underflowed");
400 
401                     l_keys[l_ents - 1] = crit_key;
402                     l_keys[l_ents..l_goal - 1].copy_from_slice(&r_keys[0..l_goal - 1 - l_ents]);
403                     l_tree[l_ents..l_goal].copy_from_slice(&r_tree[0..l_goal - l_ents]);
404                     *l_size = (l_goal - 1) as u8;
405 
406                     let new_crit = r_keys[r_ents - r_goal - 1];
407                     slice_shift(&mut r_keys[0..r_ents - 1], r_ents - r_goal);
408                     slice_shift(&mut r_tree[0..r_ents], r_ents - r_goal);
409                     *r_size = (r_goal - 1) as u8;
410 
411                     Some(new_crit)
412                 }
413             }
414             (
415                 &mut Self::Leaf {
416                     size: ref mut l_size,
417                     keys: ref mut l_keys,
418                     vals: ref mut l_vals,
419                 },
420                 &mut Self::Leaf {
421                     size: ref mut r_size,
422                     keys: ref mut r_keys,
423                     vals: ref mut r_vals,
424                 },
425             ) => {
426                 let l_ents = usize::from(*l_size);
427                 let l_keys = l_keys.borrow_mut();
428                 let l_vals = l_vals.borrow_mut();
429                 let r_ents = usize::from(*r_size);
430                 let r_keys = r_keys.borrow_mut();
431                 let r_vals = r_vals.borrow_mut();
432                 let ents = l_ents + r_ents;
433 
434                 if ents <= r_vals.len() {
435                     // We can fit all entries in the RHS node.
436                     // We'll leave the LHS node empty, but first use it as a scratch space.
437                     *l_size = 0;
438                     l_keys[l_ents..ents].copy_from_slice(&r_keys[0..r_ents]);
439                     r_keys[0..ents].copy_from_slice(&l_keys[0..ents]);
440                     l_vals[l_ents..ents].copy_from_slice(&r_vals[0..r_ents]);
441                     r_vals[0..ents].copy_from_slice(&l_vals[0..ents]);
442                     *r_size = ents as u8;
443                     None
444                 } else {
445                     // The entries don't all fit in one node. Distribute some from RHS -> LHS.
446                     // Split evenly with a bias to putting one entry in LHS.
447                     let r_goal = ents / 2;
448                     let l_goal = ents - r_goal;
449                     debug_assert!(l_goal > l_ents, "Node must be underflowed");
450 
451                     l_keys[l_ents..l_goal].copy_from_slice(&r_keys[0..l_goal - l_ents]);
452                     l_vals[l_ents..l_goal].copy_from_slice(&r_vals[0..l_goal - l_ents]);
453                     *l_size = l_goal as u8;
454 
455                     slice_shift(&mut r_keys[0..r_ents], r_ents - r_goal);
456                     slice_shift(&mut r_vals[0..r_ents], r_ents - r_goal);
457                     *r_size = r_goal as u8;
458 
459                     Some(r_keys[0])
460                 }
461             }
462             _ => panic!("Mismatched nodes"),
463         }
464     }
465 }
466 
467 /// Find the right split position for halving a full node with `len` entries to recover from a
468 /// failed insertion at `ins`.
469 ///
470 /// If `len` is even, we should split straight down the middle regardless of `len`.
471 ///
472 /// If `len` is odd, we should split the node such that the two halves are the same size after the
473 /// insertion is retried.
474 fn split_pos(len: usize, ins: usize) -> usize {
475     // Anticipate `len` being a compile time constant, so this all folds away when `len` is even.
476     if ins <= len / 2 {
477         len / 2
478     } else {
479         (len + 1) / 2
480     }
481 }
482 
483 /// The result of splitting off the second half of a node.
484 pub(super) struct SplitOff<F: Forest> {
485     /// The number of entries left in the original node which becomes the left-hand-side of the
486     /// pair. This is the number of outgoing node edges for an inner node, and the number of
487     /// key-value pairs for a leaf node.
488     pub lhs_entries: usize,
489 
490     /// The number of entries in the new RHS node.
491     pub rhs_entries: usize,
492 
493     /// The critical key separating the LHS and RHS nodes. All keys in the LHS sub-tree are less
494     /// than the critical key, and all entries in the RHS sub-tree are greater or equal to the
495     /// critical key.
496     pub crit_key: F::Key,
497 
498     /// The RHS node data containing the elements that were removed from the original node (now the
499     /// LHS).
500     pub rhs_data: NodeData<F>,
501 }
502 
503 /// The result of removing an entry from a node.
504 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
505 pub(super) enum Removed {
506     /// An entry was removed, and the node is still in good shape.
507     Healthy,
508 
509     /// The node is in good shape after removing the rightmost element.
510     Rightmost,
511 
512     /// The node has too few entries now, and it should be balanced with a sibling node.
513     Underflow,
514 
515     /// The last entry was removed. For an inner node, this means that the `keys` array is empty
516     /// and there is just a single sub-tree left.
517     Empty,
518 }
519 
520 impl Removed {
521     /// Create a `Removed` status from a size and capacity.
522     fn new(removed: usize, new_size: usize, capacity: usize) -> Self {
523         if 2 * new_size >= capacity {
524             if removed == new_size {
525                 Self::Rightmost
526             } else {
527                 Self::Healthy
528             }
529         } else if new_size > 0 {
530             Self::Underflow
531         } else {
532             Self::Empty
533         }
534     }
535 }
536 
537 // Display ": value" or nothing at all for `()`.
538 pub(super) trait ValDisp {
539     fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
540 }
541 
542 impl ValDisp for SetValue {
543     fn valfmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
544         Ok(())
545     }
546 }
547 
548 impl<T: fmt::Display> ValDisp for T {
549     fn valfmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550         write!(f, ":{}", self)
551     }
552 }
553 
554 impl<F> fmt::Display for NodeData<F>
555 where
556     F: Forest,
557     F::Key: fmt::Display,
558     F::Value: ValDisp,
559 {
560     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
561         match *self {
562             Self::Inner { size, keys, tree } => {
563                 write!(f, "[ {}", tree[0])?;
564                 for i in 0..usize::from(size) {
565                     write!(f, " {} {}", keys[i], tree[i + 1])?;
566                 }
567                 write!(f, " ]")
568             }
569             Self::Leaf { size, keys, vals } => {
570                 let keys = keys.borrow();
571                 let vals = vals.borrow();
572                 write!(f, "[")?;
573                 for i in 0..usize::from(size) {
574                     write!(f, " {}", keys[i])?;
575                     vals[i].valfmt(f)?;
576                 }
577                 write!(f, " ]")
578             }
579             Self::Free { next: Some(n) } => write!(f, "[ free -> {} ]", n),
580             Self::Free { next: None } => write!(f, "[ free ]"),
581         }
582     }
583 }
584 
585 #[cfg(test)]
586 mod tests {
587     use super::*;
588     use alloc::string::ToString;
589     use core::mem;
590 
591     // Forest impl for a set implementation.
592     struct TF();
593 
594     impl Forest for TF {
595         type Key = char;
596         type Value = SetValue;
597         type LeafKeys = [char; 15];
598         type LeafValues = [SetValue; 15];
599 
600         fn splat_key(key: Self::Key) -> Self::LeafKeys {
601             [key; 15]
602         }
603 
604         fn splat_value(value: Self::Value) -> Self::LeafValues {
605             [value; 15]
606         }
607     }
608 
609     #[test]
610     fn inner() {
611         let n1 = Node(1);
612         let n2 = Node(2);
613         let n3 = Node(3);
614         let n4 = Node(4);
615         let mut inner = NodeData::<TF>::inner(n1, 'c', n4);
616         assert_eq!(mem::size_of_val(&inner), 64);
617         assert_eq!(inner.to_string(), "[ node1 c node4 ]");
618 
619         assert!(inner.try_inner_insert(0, 'a', n2));
620         assert_eq!(inner.to_string(), "[ node1 a node2 c node4 ]");
621 
622         assert!(inner.try_inner_insert(1, 'b', n3));
623         assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");
624 
625         for i in 3..7 {
626             assert!(inner.try_inner_insert(
627                 usize::from(i),
628                 ('a' as u8 + i) as char,
629                 Node(i as u32 + 2),
630             ));
631         }
632         assert_eq!(
633             inner.to_string(),
634             "[ node1 a node2 b node3 c node4 d node5 e node6 f node7 g node8 ]"
635         );
636 
637         // Now the node is full and insertion should fail anywhere.
638         assert!(!inner.try_inner_insert(0, 'x', n3));
639         assert!(!inner.try_inner_insert(4, 'x', n3));
640         assert!(!inner.try_inner_insert(7, 'x', n3));
641 
642         // Splitting should be independent of the hint because we have an even number of node
643         // references.
644         let saved = inner.clone();
645         let sp = inner.split(1);
646         assert_eq!(sp.lhs_entries, 4);
647         assert_eq!(sp.rhs_entries, 4);
648         assert_eq!(sp.crit_key, 'd');
649         // The critical key is not present in either of the resulting nodes.
650         assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");
651         assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]");
652 
653         assert_eq!(inner.inner_remove(0), Removed::Underflow);
654         assert_eq!(inner.to_string(), "[ node2 b node3 c node4 ]");
655 
656         assert_eq!(inner.inner_remove(1), Removed::Underflow);
657         assert_eq!(inner.to_string(), "[ node2 c node4 ]");
658 
659         assert_eq!(inner.inner_remove(1), Removed::Underflow);
660         assert_eq!(inner.to_string(), "[ node2 ]");
661 
662         assert_eq!(inner.inner_remove(0), Removed::Empty);
663 
664         inner = saved;
665         let sp = inner.split(6);
666         assert_eq!(sp.lhs_entries, 4);
667         assert_eq!(sp.rhs_entries, 4);
668         assert_eq!(sp.crit_key, 'd');
669         assert_eq!(inner.to_string(), "[ node1 a node2 b node3 c node4 ]");
670         assert_eq!(sp.rhs_data.to_string(), "[ node5 e node6 f node7 g node8 ]");
671     }
672 
673     #[test]
674     fn leaf() {
675         let mut leaf = NodeData::<TF>::leaf('d', SetValue());
676         assert_eq!(leaf.to_string(), "[ d ]");
677 
678         assert!(leaf.try_leaf_insert(0, 'a', SetValue()));
679         assert_eq!(leaf.to_string(), "[ a d ]");
680         assert!(leaf.try_leaf_insert(1, 'b', SetValue()));
681         assert!(leaf.try_leaf_insert(2, 'c', SetValue()));
682         assert_eq!(leaf.to_string(), "[ a b c d ]");
683         for i in 4..15 {
684             assert!(leaf.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue()));
685         }
686         assert_eq!(leaf.to_string(), "[ a b c d e f g h i j k l m n o ]");
687 
688         // Now the node is full and insertion should fail anywhere.
689         assert!(!leaf.try_leaf_insert(0, 'x', SetValue()));
690         assert!(!leaf.try_leaf_insert(8, 'x', SetValue()));
691         assert!(!leaf.try_leaf_insert(15, 'x', SetValue()));
692 
693         // The index given to `split` is not the split position, it's a hint for balancing the node.
694         let saved = leaf.clone();
695         let sp = leaf.split(12);
696         assert_eq!(sp.lhs_entries, 8);
697         assert_eq!(sp.rhs_entries, 7);
698         assert_eq!(sp.crit_key, 'i');
699         assert_eq!(leaf.to_string(), "[ a b c d e f g h ]");
700         assert_eq!(sp.rhs_data.to_string(), "[ i j k l m n o ]");
701 
702         assert!(leaf.try_leaf_insert(8, 'i', SetValue()));
703         assert_eq!(leaf.leaf_remove(2), Removed::Healthy);
704         assert_eq!(leaf.to_string(), "[ a b d e f g h i ]");
705         assert_eq!(leaf.leaf_remove(7), Removed::Underflow);
706         assert_eq!(leaf.to_string(), "[ a b d e f g h ]");
707 
708         leaf = saved;
709         let sp = leaf.split(7);
710         assert_eq!(sp.lhs_entries, 7);
711         assert_eq!(sp.rhs_entries, 8);
712         assert_eq!(sp.crit_key, 'h');
713         assert_eq!(leaf.to_string(), "[ a b c d e f g ]");
714         assert_eq!(sp.rhs_data.to_string(), "[ h i j k l m n o ]");
715     }
716 
717     #[test]
718     fn optimal_split_pos() {
719         // An even split is easy.
720         assert_eq!(split_pos(8, 0), 4);
721         assert_eq!(split_pos(8, 8), 4);
722 
723         // Easy cases for odd splits.
724         assert_eq!(split_pos(7, 0), 3);
725         assert_eq!(split_pos(7, 7), 4);
726 
727         // If the insertion point is the same as the split position, we
728         // will append to the lhs node.
729         assert_eq!(split_pos(7, 3), 3);
730         assert_eq!(split_pos(7, 4), 4);
731     }
732 
733     #[test]
734     fn inner_balance() {
735         let n1 = Node(1);
736         let n2 = Node(2);
737         let n3 = Node(3);
738         let mut lhs = NodeData::<TF>::inner(n1, 'a', n2);
739         assert!(lhs.try_inner_insert(1, 'b', n3));
740         assert_eq!(lhs.to_string(), "[ node1 a node2 b node3 ]");
741 
742         let n11 = Node(11);
743         let n12 = Node(12);
744         let mut rhs = NodeData::<TF>::inner(n11, 'p', n12);
745 
746         for i in 1..4 {
747             assert!(rhs.try_inner_insert(
748                 usize::from(i),
749                 ('p' as u8 + i) as char,
750                 Node(i as u32 + 12),
751             ));
752         }
753         assert_eq!(
754             rhs.to_string(),
755             "[ node11 p node12 q node13 r node14 s node15 ]"
756         );
757 
758         // 3+5 elements fit in RHS.
759         assert_eq!(lhs.balance('o', &mut rhs), None);
760         assert_eq!(
761             rhs.to_string(),
762             "[ node1 a node2 b node3 o node11 p node12 q node13 r node14 s node15 ]"
763         );
764 
765         // 2+8 elements are redistributed.
766         lhs = NodeData::<TF>::inner(Node(20), 'x', Node(21));
767         assert_eq!(lhs.balance('y', &mut rhs), Some('o'));
768         assert_eq!(
769             lhs.to_string(),
770             "[ node20 x node21 y node1 a node2 b node3 ]"
771         );
772         assert_eq!(
773             rhs.to_string(),
774             "[ node11 p node12 q node13 r node14 s node15 ]"
775         );
776     }
777 
778     #[test]
779     fn leaf_balance() {
780         let mut lhs = NodeData::<TF>::leaf('a', SetValue());
781         for i in 1..6 {
782             assert!(lhs.try_leaf_insert(usize::from(i), ('a' as u8 + i) as char, SetValue()));
783         }
784         assert_eq!(lhs.to_string(), "[ a b c d e f ]");
785 
786         let mut rhs = NodeData::<TF>::leaf('0', SetValue());
787         for i in 1..8 {
788             assert!(rhs.try_leaf_insert(usize::from(i), ('0' as u8 + i) as char, SetValue()));
789         }
790         assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]");
791 
792         // 6+8 elements all fits in rhs.
793         assert_eq!(lhs.balance('0', &mut rhs), None);
794         assert_eq!(rhs.to_string(), "[ a b c d e f 0 1 2 3 4 5 6 7 ]");
795 
796         assert!(lhs.try_leaf_insert(0, 'x', SetValue()));
797         assert!(lhs.try_leaf_insert(1, 'y', SetValue()));
798         assert!(lhs.try_leaf_insert(2, 'z', SetValue()));
799         assert_eq!(lhs.to_string(), "[ x y z ]");
800 
801         // 3+14 elements need redistribution.
802         assert_eq!(lhs.balance('a', &mut rhs), Some('0'));
803         assert_eq!(lhs.to_string(), "[ x y z a b c d e f ]");
804         assert_eq!(rhs.to_string(), "[ 0 1 2 3 4 5 6 7 ]");
805     }
806 }
807