Repository: tnballo/scapegoat (language: rust)

Issue:
Switch internal arena from `smallvec` to `tinyvec` (breaking change)
Replace [`smallvec`](https://crates.io/crates/smallvec) dependency with [`tinyvec`](https://crates.io/crates/tinyvec).

* **Pro:** all deps and this lib become `#![forbid(unsafe_code)]`, e.g. 100% of the compiler's output is safe.

* **Con:** Breaking change, additional trait bound for map keys and set elements: from `Ord` to `Ord + Default`. Requires v2.X.

Cannot use feature flag to toggle between the two deps since [trait aliases](https://rust-lang.github.io/rfcs/1733-trait-alias.html) are not yet supported on stable?


Discussion / hints:

Fix patch:
diff --git a/CONFIG.md b/CONFIG.md
index db4a346..b2fd5bd 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -18,27 +18,23 @@ It controls the trade-off between total rebuild time and maximum height guarante
 
 We choose 2/3, e.g. `a = 0.666...`, by default.
 
-* This is the same  default used in the [recursive] [Open Data Structures textbook implementation](https://opendatastructures.org/ods-java/8_Scapegoat_Trees.html) of a scapegoat tree.
-
 * The original paper does not recommend any specific value for `a`, but Figure 4 shows comparative results for values in the range `0.55 <= a < 0.75`. The authors recommend tuning `a` for your expected workload.
 
+* This is the same  default used in the [recursive] [Open Data Structures textbook implementation](https://opendatastructures.org/ods-java/8_Scapegoat_Trees.html) of a scapegoat tree.
+
 Note our default is almost exactly in the middle of the paper's range, suggesting it's a balanced choice (pun intended).
 
-Just like with stack arena size, `a` can be compile-timed configured by exporting environment variables before build.
-The `a` denominator is the floating point string assigned to env var `SG_ALPHA_NUMERATOR`.
-The `a` denominator is the floating point string assigned to env var `SG_ALPHA_DENOMINATOR`.
+`a` can be changed at runtime via the API `set_rebal_param(alpha_num: f32, alpha_denom: f32)`.
+The library's performance characteristics can be tuned on-the-fly, without recompiling.
 For example, manually setting the default 2/3 would be:
 
+```rust
+use scapegoat::SgMap;
+let mut map: SgMap<isize, isize, 10> = SgMap::new();
+assert!(map.set_rebal_param(2.0, 3.0).is_ok());
 ```
-export SG_ALPHA_NUMERATOR=2.0
-export SG_ALPHA_DENOMINATOR=3.0
-cargo build --release
-```
-
-`a` can also be changed at runtime via the API `set_rebal_param(alpha_num: f32, alpha_denom: f32)`.
-The library's performance characteristics can be tuned on-the-fly, without recompiling.
 
-## Additional Features
+## Optional Features
 
 ### The `low_mem_insert` feature
 
diff --git a/Cargo.toml b/Cargo.toml
index f5716af..eabba8e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "scapegoat"
-version = "1.7.0"
+version = "2.0.0"
 authors = ["Tiemoko Ballo"]
 edition = "2018"
 license = "MIT"
@@ -8,9 +8,9 @@ readme = "README.md"
 homepage = "https://github.com/tnballo/scapegoat"
 repository = "https://github.com/tnballo/scapegoat"
 documentation = "https://docs.rs/scapegoat"
-keywords = ["scapegoat", "tree", "set", "map", "no_std"]
+keywords = ["tree", "set", "map", "no_std", "fallible"]
 categories = ["algorithms", "data-structures", "no-std", "embedded"]
-description = "Safe, embedded-friendly ordered set/map via a scapegoat tree."
+description = "Safe, fallible, embedded-friendly ordered set/map via a scapegoat tree. Validated against BTreeSet/BTreeMap."
 include = [
     "src/**/*.rs",
     "benches/**/*.rs",
@@ -21,9 +21,9 @@ include = [
 ]
 
 [dependencies]
-smallvec = "1.7"  # Has no dependencies of it's own
-micromath = "2.0" # Has no dependenceis of it's own
-smallnum = "0.2"  # Has no dependencies of it's own
+tinyvec = { version = "^1.5", features = ["rustc_1_55"] } # Has no dependencies of it's own
+micromath = "^2.0" # Has no dependenceis of it's own
+smallnum = "^0.4"  # Has no dependencies of it's own
 
 [dev-dependencies]
 criterion = "0.3"
@@ -31,7 +31,6 @@ rand = { version = "0.7", features = ["small_rng"] }
 lazy_static = "1"
 
 [features]
-high_assurance = []
 alt_impl = []
 low_mem_insert = []
 fast_rebalance = []
diff --git a/Dockerfile b/Dockerfile
index f40425a..a306775 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,5 @@
-FROM rust:1.56.1-slim
+# MSRV
+FROM rust:1.55-slim
 
 # Non-Rust tooling
 ENV TZ=US/New_York
@@ -6,19 +7,23 @@ RUN apt-get update -y
 RUN DEBIAN_FRONTEND="noninteractive" apt-get install -y \
     rr \
     tree \
-    vim
+    vim \
+    musl-tools
 
 # Rust tooling
 RUN rustup toolchain install nightly
+RUN rustup default nightly
+RUN rustup component add rust-src --toolchain nightly
 RUN rustup component add llvm-tools-preview
+RUN rustup target add x86_64-unknown-linux-musl
 RUN cargo install cargo-fuzz
 RUN cargo install cargo-binutils
+RUN cargo install cargo-bloat
 
 # Src import
 RUN mkdir /scapegoat
 WORKDIR /scapegoat
 COPY . /scapegoat/
 
-# Build
-RUN export SG_MAX_STACK_ELEMS=1024
-RUN cargo build
\ No newline at end of file
+# MSRV Test
+RUN cargo test
\ No newline at end of file
diff --git a/README.md b/README.md
index 97e036f..2c5885f 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
 # scapegoat
 
 [![crates.io](https://img.shields.io/crates/v/scapegoat.svg)](https://crates.io/crates/scapegoat)
+![MSRV 1.55+](https://img.shields.io/badge/rustc-1.55+-yellow.svg)
 [![docs.rs](https://docs.rs/scapegoat/badge.svg)](https://docs.rs/scapegoat/)
 [![GitHub Actions](https://github.com/tnballo/scapegoat/workflows/test/badge.svg)](https://github.com/tnballo/scapegoat/actions)
 [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/tnballo/scapegoat/blob/master/LICENSE)
@@ -9,19 +10,18 @@
 
 Ordered set and map data structures via an arena-based [scapegoat tree](https://people.csail.mit.edu/rivest/pubs/GR93.pdf) (memory-efficient, self-balancing binary search tree).
 
-* Safe: `#![forbid(unsafe_code)]`.
 * Embedded-friendly: `!#[no_std]` by default.
+* Safe: `#![forbid(unsafe_code)]`, including all dependencies.
 * Validated via differential fuzzing, against the standard library's `BTreeSet` and `BTreeMap`.
 
 ### About
 
-Three APIs:
+Two APIs:
 
-* Ordered Set API ([`SGSet`](crate::SGSet)) - subset of [`BTreeSet`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html) nightly.
-* Ordered Map API ([`SGMap`](crate::SGMap)) - subset of [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) nightly.
-* Binary Tree API ([`SGTree`](crate::SGTree)) - backend for the previous two.
+* Ordered Set API ([`SgSet`](crate::SgSet)) - subset of [`BTreeSet`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html) nightly.
+* Ordered Map API ([`SgMap`](crate::SgMap)) - subset of [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) nightly.
 
-Strives for two properties:
+Strives for three properties:
 
 * **Maximal safety:** strong [memory safety](https://tiemoko.com/blog/blue-team-rust/) guarantees, hence `#![forbid(unsafe_code)]`.
     * **Compile-time safety:** no `unsafe` (no raw pointer dereference, etc.).
@@ -33,51 +33,64 @@ Strives for two properties:
     * **Recursion-free:** all operations are iterative, so stack use is fixed and runtime is minimized.
     * **Zero-copy:** rebuild/removal re-point in-place, nodes are never copied or cloned.
 
+* **Fallibility**: for embedded use cases prioritizing robustness (or [kernelspace](https://lkml.org/lkml/2021/4/14/1099) code):
+    * A `try_*` variant of each fallible API (e.g. `insert`, `append`, `extend`, etc.) is available.
+    * **Out-of-memory (OOM)** `panic!` becomes avoidable: `try_*` variants return [`Result<_, SgError>`](crate::SgError).
+    * Heap fragmentation doesn't impact **Worst Case Execution Time (WCET)**, this library doesn't use the heap.
+
 Other features:
 
-* **Generic:** map keys and set elements can be any type that implements the `Ord` trait.
-* **Arbitrarily mutable:** elements can be insert and removed, map values can be mutated.
+* **Generic:** map keys and set elements can be any type that implements the `Ord + Default` traits.
+* **Arbitrarily mutable:** elements can be insert and removed, map values can be mutated. Safely.
 
 ### Usage
 
-`SGMap` non-exhaustive, `!#[no_std]` API example (would work identically for `std::collections::BTreeMap`):
+`SgMap` non-exhaustive, `!#[no_std]` API example (would work almost identically for `std::collections::BTreeMap`):
 
 ```rust
-use scapegoat::SGMap;
-use smallvec::{smallvec, SmallVec};
+use scapegoat::SgMap;
+use tinyvec::{array_vec, ArrayVec};
 
-const REF_BUF_LEN: usize = 5;
+// This const is an argument to each generic constructor below.
+// So we'll use *only the bare minimum* memory for 5 elements.
+// - Stack RAM usage can be precisely controlled: per map instance (constructor call-site).
+// - To save executable RAM/ROM (monomorphization!), stick to a global capacity like this.
+const CAPACITY: usize = 5;
 
-let mut example = SGMap::new();
+let mut example = SgMap::<_, _, CAPACITY>::new(); // BTreeMap::new()
 let mut stack_str = "your friend the";
 
 // Insert "dynamically" (as if heap)
 example.insert(3, "the");
 example.insert(2, "don't blame");
 example.insert(1, "Please");
-example.insert(4, "borrow checker");
+
+// Fallible insert variant
+assert!(example.try_insert(4, "borrow checker").is_ok());
 
 // Ordered reference iterator
 assert!(example
     .iter()
     .map(|(_, v)| *v)
-    .collect::<SmallVec<[&str; REF_BUF_LEN]>>()
+    .collect::<ArrayVec<[&str; CAPACITY]>>()
     .iter()
     .eq(["Please","don't blame","the","borrow checker"].iter()));
 
 // Container indexing
 assert_eq!(example[&3], "the");
 
-// Fast (no search) head removal
+// Head removal
 let please_tuple = example.pop_first().unwrap();
 assert_eq!(please_tuple, (1, "Please"));
 
-// By-predicate removal (iterates all entries)
+// By-predicate removal
 example.retain(|_, v| !v.contains("a"));
 
 // Extension
-let iterable: SmallVec<[(isize, &str); REF_BUF_LEN]> =
-    smallvec![(1337, "safety!"), (0, "Leverage"), (100, "for")];
+let iterable = array_vec![
+    [(isize, &str); CAPACITY] =>
+    (1337, "safety!"), (0, "Leverage"), (100, "for")
+];
 example.extend(iterable.into_iter());
 
 // Value mutation
@@ -88,97 +101,58 @@ if let Some(three_val) = example.get_mut(&3) {
 // New message :)
 assert!(example
     .into_values()
-    .collect::<SmallVec<[&str; REF_BUF_LEN]>>()
+    .collect::<ArrayVec<[&str; CAPACITY]>>()
     .iter()
     .eq(["Leverage","your friend the","borrow checker","for","safety!"].iter()));
 ```
 
 Additional [examples here](https://github.com/tnballo/scapegoat/blob/master/examples/README.md).
 
-### Configuring a Stack Storage Limit
+### Stack Capacity: Important Context
 
-The maximum number of stack-stored elements (set) or key-value pairs (map/tree) is determined at compile-time, via the environment variable `SG_MAX_STACK_ELEMS`.
-[Valid values](https://docs.rs/smallvec/1.7.0/smallvec/trait.Array.html#foreign-impls) include the range `[0, 32]` and powers of 2 up to `1,048,576`.
-For example, to store up to `2048` items on the stack:
+Per the above, const generic type parameters decide collection capacity.
+And thus also stack usage.
+That usage is fixed:
 
-```bash
-export SG_MAX_STACK_ELEMS=2048
-cargo build --release
+```rust
+use core::mem::size_of_val;
+use scapegoat::SgMap;
+
+let small_map: SgMap<u64, u64, 100> = SgMap::new(); // 100 item capacity
+let big_map: SgMap<u64, u64, 2_048> = SgMap::new(); // 2,048 item capacity
+
+#[cfg(target_pointer_width = "64")]
+#[cfg(not(feature = "low_mem_insert"))]
+#[cfg(not(feature = "fast_rebalance"))]
+{
+    assert_eq!(size_of_val(&small_map), 2_680); // 2.7 KB
+    assert_eq!(size_of_val(&big_map), 53_328);  // 53.3 KB
+}
 ```
 
-Please note:
-
-* If the `SG_MAX_STACK_ELEMS` environment variable is not set, it will default to `1024`.
-
-* For any system with heap memory: the first `SG_MAX_STACK_ELEMS` elements are stack-allocated and the remainder will be automatically heap-allocated.
+The maximum supported capacity is `65_535` (e.g. `0xffff` or [`u16::MAX`](https://doc.rust-lang.org/std/primitive.u16.html#associatedconstant.MAX)) items.
 
-* For embedded systems with only stack memory: `SG_MAX_STACK_ELEMS` is a hard maximum - attempting to insert beyond this limit will cause a panic.
-    * Use feature `high_assurance` to ensure error handling and avoid panic (see below).
-
-> **Warning:**
-> Although stack usage is constant (no recursion), a stack overflow can happen at runtime if `SG_MAX_STACK_ELEMS` (configurable) and/or the stored item type (generic) is too large.
+> **WARNING:**
+> Although stack usage is constant (no recursion), a stack overflow can happen at runtime if `N` (const generic capacity) and/or the stored item type (generic) is too large.
 > Note *stack* overflow is distinct from *buffer* overflow (which safe Rust prevents).
 > Regardless, you must test to ensure you don't exceed the stack frame(s) size limit of your target platform.
 > Rust only supports stack probes on x86/x64, although [creative linking solutions](https://blog.japaric.io/stack-overflow-protection/) have been suggested for other architectures.
 
 For more advanced configuration options, see [the documentation here](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md).
 
-### The `high_assurance` Feature
-
-For embedded use cases prioritizing robustness (or [kernelspace](https://lkml.org/lkml/2021/4/14/1099) code), the `high_assurance` feature can be enabled with the standard `Cargo.toml` declaration:
-
-```rust
-[dependencies]
-scapegoat = { version = "^1.7", features = ["high_assurance"] }
-```
-
-Enabling this feature makes two changes:
+### Trusted Dependencies
 
-1. **Front-end, API Tweak:** `insert` and `append` APIs now return `Result`. `Err` indicates stack storage is already at maximum capacity, so caller must handle. No heap use, no panic potential on insert.
-
-2. **Back-end, Integer Packing:** Because the fixed/max size of the stack arena is known, indexing integers (metadata stored at every node!) can be size-optimized. This memory micro-optimization honors the original design goals of the scapegoat data structure.
+This library has three dependencies, each of which have no dependencies of their own (e.g. exactly three total dependencies).
 
-That second change is a subtle but interesting one.
-Example of packing saving 53% (31 KB) of RAM usage:
+* [`tinyvec`](https://crates.io/crates/tinyvec) - `!#[no_std]`, `#![forbid(unsafe_code)]` `Vec` alternative.
+* [`micromath`](https://crates.io/crates/micromath) - `!#[no_std]`, `#![forbid(unsafe_code)]` floating point approximations.
+* [`smallnum`](https://crates.io/crates/smallnum) - `!#[no_std]`, `#![forbid(unsafe_code)]` integer abstraction.
 
-```rust
-use core::mem::size_of;
-use scapegoat::SGMap;
-
-// If you're on a 64-bit system, you can compile-time check the below numbers yourself!
-// Just do:
-//
-// $ cargo test --doc
-// $ cargo test --doc --features="high_assurance"
-//
-// One command per set of `cfg` macros below.
-// Internally, this compile-time struct packing is done with the `smallnum` crate:
-// https://crates.io/crates/smallnum
-
-// This code assumes `SG_MAX_STACK_ELEMS == 1024` (default)
-let temp: SGMap<u64, u64> = SGMap::new();
-let other_features_enabled = cfg!(any(feature = "fast_rebalance", feature = "low_mem_insert"));
-if temp.capacity() == 1024 && (!other_features_enabled) {
-
-    // Without packing
-    #[cfg(target_pointer_width = "64")]
-    #[cfg(not(feature = "high_assurance"))] // Disabled
-    {
-        assert_eq!(size_of::<SGMap<u64, u64>>(), 57_440);
-    }
-
-    // With packing
-    #[cfg(target_pointer_width = "64")]
-    #[cfg(feature = "high_assurance")]  // Enabled
-    {
-        assert_eq!(size_of::<SGMap<u64, u64>>(), 26_688);
-    }
-}
-```
+Because this library and all dependencies are `#![forbid(unsafe_code)]`, no 3rd-party `unsafe` code will be introduced into your project.
 
-### Considerations
+### Additional Considerations
 
-#### General Goals
+**General Goals**
 
 This project is an exercise in safe, portable data structure design.
 The goal is to offer embedded developers familiar, ergonomic APIs on resource constrained systems that otherwise don't get the luxury of dynamic collections.
@@ -189,37 +163,31 @@ The standard library has been heavily optimized for cache performance.
 This library is optimized for low, stack-only memory footprint.
 It offers:
 
-* **Best-effort Compatibility:** APIs are a subset of `BTreeMap`'s/`BTreeSet`'s, making it a somewhat "drop-in" replacement for `!#[no_std]` systems. Please [open an issue](https://github.com/tnballo/scapegoat/issues) if an API you need isn't yet supported.
+* **Best-effort Compatibility:** APIs are mostly a subset of `BTreeMap`'s/`BTreeSet`'s, making it a mostly "drop-in" replacement for `!#[no_std]` systems. Please [open an issue](https://github.com/tnballo/scapegoat/issues) if an API you need isn't yet supported.
 
 * **Dynamic Validation:** [Coverage-guided differential fuzzing](https://github.com/tnballo/scapegoat/blob/master/fuzz/README.md) is used to demonstrate that this implementation is logically equivalent and equally reliable.
 
 * **Tunable Performance:** A [single floating point value](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md#tuning-the-the-trees-a-factor) optimizes relative performance of `insert`, `get`, and `remove` operation classes. And it can be changed at runtime.
 
-#### Algorithmic Complexity
+**Algorithmic Complexity**
 
-Space complexity is always `O(n)`.
+Space complexity is always `O(n)`. Time complexity:
 
 | Operation | Average Case | Worst Case |
 | --- | --- | --- |
 | `get` | `O(log n)` | `O(log n)` |
 | `insert` | `O(log n)` | Amortized `O(log n)` |
 | `remove` | `O(log n)` | Amortized `O(log n)` |
+| `first` | `O(1)` | `O(1)` |
+| `last` | `O(1)` | `O(1)` |
 
 The [`low_mem_insert`](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md#the-low_mem_insert-feature) and [`fast_rebalance`](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md#the-fast_rebalance-feature) features can be used to fine-tune tradeoffs of memory usage and speed.
 
-#### Memory Footprint Demos
+**Memory Footprint Demos**
 
-* [Code size demo](https://github.com/tnballo/scapegoat/blob/master/misc/min_size/README.md) - `SGMap<usize, usize>` with `insert`, `get`, and `remove` called: **17.0KB** for an x86-64 binary. Caveat: you'll likely want to use more than 3 functions, resulting in more executable code getting included.
+* [Code size demo](https://github.com/tnballo/scapegoat/blob/master/misc/min_size/README.md) - `SgMap<usize, usize, 1024>` with `insert`, `get`, and `remove` called: **16.0KB** for an x86-64 binary. Caveat: you'll likely want to use more than 3 functions, resulting in more executable code getting included.
 
-* [Stack space demo](https://github.com/tnballo/scapegoat/blob/master/examples/tiny_map.rs) - `SGMap<u8, u8>` with a 256 pair capacity: **2.6KB** storage cost. Caveat: 2-3x more stack space is required for runtime book keeping (e.g. rebalancing).
-
-#### Trusted Dependencies
-
-This library has three dependencies, each of which have no dependencies of their own (e.g. exactly three total dependencies).
-
-* [`smallvec`](https://crates.io/crates/smallvec) - `!#[no_std]` compatible `Vec` alternative. Used in Mozilla's Servo browser engine.
-* [`micromath`](https://crates.io/crates/micromath) - `!#[no_std]`, `#![forbid(unsafe_code)]` floating point approximations.
-* [`smallnum`](https://crates.io/crates/smallnum) - `!#[no_std]`, `#![forbid(unsafe_code)]` integer packing.
+* [Stack space demo](https://github.com/tnballo/scapegoat/blob/master/examples/tiny_map.rs) - `SgMap<u8, u8, 128>`: **1.3KB** storage cost. Caveat: more stack space is required for runtime book keeping (e.g. rebalancing).
 
 ### License and Contributing
 
diff --git a/README.tpl b/README.tpl
index a7d30c6..edcdfe3 100644
--- a/README.tpl
+++ b/README.tpl
@@ -1,6 +1,7 @@
 # {{crate}}
 
 [![crates.io](https://img.shields.io/crates/v/scapegoat.svg)](https://crates.io/crates/scapegoat)
+![MSRV 1.55+](https://img.shields.io/badge/rustc-1.55+-yellow.svg)
 [![docs.rs](https://docs.rs/scapegoat/badge.svg)](https://docs.rs/scapegoat/)
 [![GitHub Actions](https://github.com/tnballo/scapegoat/workflows/test/badge.svg)](https://github.com/tnballo/scapegoat/actions)
 [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/tnballo/scapegoat/blob/master/LICENSE)
diff --git a/benches/bench_set_from.rs b/benches/bench_set_from.rs
index 2949260..c6590b1 100644
--- a/benches/bench_set_from.rs
+++ b/benches/bench_set_from.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
 use std::convert::TryInto;
 
 use criterion::{criterion_group, criterion_main, Criterion};
-use scapegoat::SGSet;
+use scapegoat::SgSet;
 
 mod test_data;
 use test_data::{RAND_10_000, SEQ_10_000};
@@ -14,7 +14,7 @@ fn bench_from_rand(c: &mut Criterion) {
 
     c.bench_function("sgs_from_10_000_rand", |b| {
         b.iter(|| {
-            let _ = SGSet::from(rand_10k);
+            let _ = SgSet::from(rand_10k);
         })
     });
 
@@ -30,7 +30,7 @@ fn bench_from_seq(c: &mut Criterion) {
 
     c.bench_function("sgs_from_10_000_seq", |b| {
         b.iter(|| {
-            let _ = SGSet::from(seq_10k);
+            let _ = SgSet::from(seq_10k);
         })
     });
 
diff --git a/benches/bench_set_rand.rs b/benches/bench_set_rand.rs
index 0ab2528..7f5c8d4 100644
--- a/benches/bench_set_rand.rs
+++ b/benches/bench_set_rand.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
 use std::iter::FromIterator;
 
 use criterion::{criterion_group, criterion_main, Criterion};
-use scapegoat::SGSet;
+use scapegoat::SgSet;
 
 mod test_data;
 use test_data::{
@@ -17,7 +17,7 @@ fn bench_insert(c: &mut Criterion) {
 
     c.bench_function("sgs_insert_100_rand", |b| {
         b.iter(|| {
-            let mut sgs = SGSet::new();
+            let mut sgs = SgSet::<_, 100>::new();
             for k in &RAND_100.keys {
                 sgs.insert(*k);
             }
@@ -26,7 +26,7 @@ fn bench_insert(c: &mut Criterion) {
 
     c.bench_function("std_insert_100_rand", |b| {
         b.iter(|| {
-            let mut std = SGSet::new();
+            let mut std = BTreeSet::new();
             for k in &RAND_100.keys {
                 std.insert(*k);
             }
@@ -37,7 +37,7 @@ fn bench_insert(c: &mut Criterion) {
 
     c.bench_function("sgs_insert_1_000_rand", |b| {
         b.iter(|| {
-            let mut sgs = SGSet::new();
+            let mut sgs = SgSet::<_, 1_000>::new();
             for k in &RAND_1_000.keys {
                 sgs.insert(*k);
             }
@@ -55,17 +55,15 @@ fn bench_insert(c: &mut Criterion) {
 
     // SGS vs STD 10_000 -----------------------------------------------------------------------------------------------
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("sgs_insert_10_000_rand", |b| {
         b.iter(|| {
-            let mut sgs = SGSet::new();
+            let mut sgs = SgSet::<_, 10_000>::new();
             for k in &RAND_10_000.keys {
                 sgs.insert(*k);
             }
         })
     });
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("std_insert_10_000_rand", |b| {
         b.iter(|| {
             let mut std = BTreeSet::new();
@@ -115,7 +113,6 @@ fn bench_get(c: &mut Criterion) {
 
     // SGS vs STD 10_000 -----------------------------------------------------------------------------------------------
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("sgs_get_10_000_rand", |b| {
         b.iter(|| {
             for k in &RAND_10_000.get_idxs {
@@ -124,7 +121,6 @@ fn bench_get(c: &mut Criterion) {
         })
     });
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("std_get_10_000_rand", |b| {
         b.iter(|| {
             for k in &RAND_10_000.get_idxs {
@@ -135,16 +131,12 @@ fn bench_get(c: &mut Criterion) {
 }
 
 fn bench_remove(c: &mut Criterion) {
-    let mut sgs_100: SGSet<usize> = SGSet::from_iter(RAND_100.keys.clone());
-    let mut sgs_1_000: SGSet<usize> = SGSet::from_iter(RAND_1_000.keys.clone());
-
-    #[cfg(not(feature = "high_assurance"))]
-    let mut sgs_10_000: SGSet<usize> = SGSet::from_iter(RAND_10_000.keys.clone());
+    let mut sgs_100: SgSet<usize, 100> = SgSet::from_iter(RAND_100.keys.clone());
+    let mut sgs_1_000: SgSet<usize, 1_000> = SgSet::from_iter(RAND_1_000.keys.clone());
+    let mut sgs_10_000: SgSet<usize, 10_000> = SgSet::from_iter(RAND_10_000.keys.clone());
 
     let mut std_100: BTreeSet<usize> = BTreeSet::from_iter(RAND_100.keys.clone());
     let mut std_1_000: BTreeSet<usize> = BTreeSet::from_iter(RAND_1_000.keys.clone());
-
-    #[cfg(not(feature = "high_assurance"))]
     let mut std_10_000: BTreeSet<usize> = BTreeSet::from_iter(RAND_10_000.keys.clone());
 
     // SGS vs STD 100 --------------------------------------------------------------------------------------------------
@@ -185,7 +177,6 @@ fn bench_remove(c: &mut Criterion) {
 
     // SGS vs STD 10_000 -----------------------------------------------------------------------------------------------
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("sgs_remove_10_000_rand", |b| {
         b.iter(|| {
             for k in &RAND_10_000.remove_idxs {
@@ -194,7 +185,6 @@ fn bench_remove(c: &mut Criterion) {
         })
     });
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("std_remove_10_000_rand", |b| {
         b.iter(|| {
             for k in &RAND_10_000.remove_idxs {
diff --git a/benches/bench_set_seq.rs b/benches/bench_set_seq.rs
index a31517e..36a0523 100644
--- a/benches/bench_set_seq.rs
+++ b/benches/bench_set_seq.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
 use std::iter::FromIterator;
 
 use criterion::{criterion_group, criterion_main, Criterion};
-use scapegoat::SGSet;
+use scapegoat::SgSet;
 
 mod test_data;
 use test_data::{
@@ -17,7 +17,7 @@ fn bench_insert(c: &mut Criterion) {
 
     c.bench_function("sgs_insert_100_seq", |b| {
         b.iter(|| {
-            let mut sgs = SGSet::new();
+            let mut sgs = SgSet::<_, 100>::new();
             for k in &SEQ_100.keys {
                 sgs.insert(*k);
             }
@@ -26,7 +26,7 @@ fn bench_insert(c: &mut Criterion) {
 
     c.bench_function("std_insert_100_seq", |b| {
         b.iter(|| {
-            let mut std = SGSet::new();
+            let mut std = BTreeSet::new();
             for k in &SEQ_100.keys {
                 std.insert(*k);
             }
@@ -37,7 +37,7 @@ fn bench_insert(c: &mut Criterion) {
 
     c.bench_function("sgs_insert_1_000_seq", |b| {
         b.iter(|| {
-            let mut sgs = SGSet::new();
+            let mut sgs = SgSet::<_, 1_000>::new();
             for k in &SEQ_1_000.keys {
                 sgs.insert(*k);
             }
@@ -55,17 +55,15 @@ fn bench_insert(c: &mut Criterion) {
 
     // SGS vs STD 10_000 -----------------------------------------------------------------------------------------------
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("sgs_insert_10_000_seq", |b| {
         b.iter(|| {
-            let mut sgs = SGSet::new();
+            let mut sgs = SgSet::<_, 10_000>::new();
             for k in &SEQ_10_000.keys {
                 sgs.insert(*k);
             }
         })
     });
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("std_insert_10_000_seq", |b| {
         b.iter(|| {
             let mut std = BTreeSet::new();
@@ -115,7 +113,6 @@ fn bench_get(c: &mut Criterion) {
 
     // SGS vs STD 10_000 -----------------------------------------------------------------------------------------------
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("sgs_get_10_000_seq", |b| {
         b.iter(|| {
             for k in &SEQ_10_000.get_idxs {
@@ -124,7 +121,6 @@ fn bench_get(c: &mut Criterion) {
         })
     });
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("std_get_10_000_seq", |b| {
         b.iter(|| {
             for k in &SEQ_10_000.get_idxs {
@@ -135,16 +131,12 @@ fn bench_get(c: &mut Criterion) {
 }
 
 fn bench_remove(c: &mut Criterion) {
-    let mut sgs_100: SGSet<usize> = SGSet::from_iter(SEQ_100.keys.clone());
-    let mut sgs_1_000: SGSet<usize> = SGSet::from_iter(SEQ_1_000.keys.clone());
-
-    #[cfg(not(feature = "high_assurance"))]
-    let mut sgs_10_000: SGSet<usize> = SGSet::from_iter(SEQ_10_000.keys.clone());
+    let mut sgs_100: SgSet<usize, 100> = SgSet::from_iter(SEQ_100.keys.clone());
+    let mut sgs_1_000: SgSet<usize, 1_000> = SgSet::from_iter(SEQ_1_000.keys.clone());
+    let mut sgs_10_000: SgSet<usize, 10_000> = SgSet::from_iter(SEQ_10_000.keys.clone());
 
     let mut std_100: BTreeSet<usize> = BTreeSet::from_iter(SEQ_100.keys.clone());
     let mut std_1_000: BTreeSet<usize> = BTreeSet::from_iter(SEQ_1_000.keys.clone());
-
-    #[cfg(not(feature = "high_assurance"))]
     let mut std_10_000: BTreeSet<usize> = BTreeSet::from_iter(SEQ_10_000.keys.clone());
 
     // SGS vs STD 100 --------------------------------------------------------------------------------------------------
@@ -185,7 +177,6 @@ fn bench_remove(c: &mut Criterion) {
 
     // SGS vs STD 10_000 -----------------------------------------------------------------------------------------------
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("sgs_remove_10_000_seq", |b| {
         b.iter(|| {
             for k in &SEQ_10_000.remove_idxs {
@@ -194,7 +185,6 @@ fn bench_remove(c: &mut Criterion) {
         })
     });
 
-    #[cfg(not(feature = "high_assurance"))]
     c.bench_function("std_remove_10_000_seq", |b| {
         b.iter(|| {
             for k in &SEQ_10_000.remove_idxs {
diff --git a/build.rs b/build.rs
deleted file mode 100644
index 93f6367..0000000
--- a/build.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use std::env;
-use std::fs;
-use std::path::Path;
-
-// https://docs.rs/smallvec/1.7.0/smallvec/trait.Array.html#implementors
-const ELEM_MAX: usize = 1_048_576;
-
-fn main() {
-    let env_key_max_items = "SG_MAX_STACK_ELEMS"; // TODO: for v2.0, rename to "SG_MAX_STACK_ITEMS" (to reflect both set elements and map key/val pairs)
-    let env_val_max_items_def = "1024";
-
-    // Original paper's alpha, `a`, can be chosen in the range `0.5 <= a < 1.0`.
-    // We choose 2/3, i.e. `a = 0.666...`, by default.
-    // Please see CONFIG.md.
-    let env_key_alpha_num = "SG_ALPHA_NUMERATOR";
-    let env_val_alpha_num_def = "2.0";
-    let env_key_alpha_denom = "SG_ALPHA_DENOMINATOR";
-    let env_val_alpha_denom_def = "3.0";
-
-    println!("cargo:rerun-if-env-changed={}", env_key_max_items);
-    println!("cargo:rerun-if-env-changed={}", env_key_alpha_num);
-    println!("cargo:rerun-if-env-changed={}", env_key_alpha_denom);
-
-    let out_dir = env::var_os("OUT_DIR").unwrap();
-    let consts_file_path = Path::new(&out_dir).join("consts.rs");
-
-    let max_elems = match env::var(env_key_max_items) {
-        Ok(val) => val,
-        Err(_) => {
-            println!(
-                "cargo:warning=Unset environment variable, using default: \'{}={}\'",
-                env_key_max_items, env_val_max_items_def
-            );
-            env_val_max_items_def.to_string()
-        }
-    };
-
-    assert!(
-        max_elems.parse::<usize>().unwrap() <= ELEM_MAX,
-        "Exceeded maximum stack item limit!"
-    );
-
-    let alpha_num = match env::var(env_key_alpha_num) {
-        Ok(val) => val,
-        Err(_) => env_val_alpha_num_def.to_string(),
-    };
-
-    let alpha_denom = match env::var(env_key_alpha_denom) {
-        Ok(val) => val,
-        Err(_) => env_val_alpha_denom_def.to_string(),
-    };
-
-    let alpha = alpha_num.parse::<f32>().unwrap() / alpha_denom.parse::<f32>().unwrap();
-    assert!(
-        (0.5..1.0).contains(&alpha),
-        "Invalid alpha! Condition must hold: 0.5 <= (SG_ALPHA_NUMERATOR / SG_ALPHA_DENOMINATOR) < 1"
-    );
-
-    let consts_file_contents = format!(
-        "const MAX_ELEMS: usize = {};\n
-        const ALPHA_NUM: f32 = {};\n
-        const ALPHA_DENOM: f32 = {};\n",
-        max_elems, alpha_num, alpha_denom,
-    );
-
-    fs::write(&consts_file_path, &consts_file_contents).unwrap();
-}
diff --git a/examples/README.md b/examples/README.md
index 70bb9f2..7e55608 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,6 +1,6 @@
 ## Examples
 
-The examples don't have output, but you can run them to check their asserts (features optional, e.g. append `--features="high_assurance"`):
+The examples don't have output, but you can run them to check their asserts (features optional, e.g. append `--features="low_mem_insert"`):
 
 ```
 cargo run --example <name>
@@ -8,10 +8,10 @@ cargo run --example <name>
 
 Alphabetical enumeration:
 
-* [`ha_insert`](./ha_insert.rs) - insertion semantics, with `high_assurance` feature enabled/disabled.
 * [`search_by_slice`](./search_by_slice.rs) - search set of sized types by an unsized type.
-* [`static_strs`](./static_strs.rs) - build sentences with a mutable `SGMap<isize, &str>` (from main [`README.md`](../README.md)).
-* [`tiny_map`](./tiny_map.rs) - 2.6KB `SGMap<u8, u8>` with configuration settings saving 78% (9.6KB) of stack usage.
+* [`static_strs`](./static_strs.rs) - build sentences with a mutable `SgMap<isize, &str, 5>` (from main [`README.md`](../README.md)).
+* [`tiny_map`](./tiny_map.rs) - `SgMap<u8, u8, 128>` using 1.3 KB of stack space.
+* [`try_insert`](./try_insert.rs) - fallible insertion semantics.
 
 Have another `!#[no_std]` example?
 Consider [contributing](https://github.com/tnballo/scapegoat/pulls) it!
\ No newline at end of file
diff --git a/examples/ha_insert.rs b/examples/ha_insert.rs
deleted file mode 100644
index 332fddc..0000000
--- a/examples/ha_insert.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-#[cfg(not(feature = "high_assurance"))]
-use scapegoat::SGMap;
-
-#[cfg(feature = "high_assurance")]
-use scapegoat::{SGErr, SGMap};
-
-// Identity permutation fill: (0, 0), (1, 1), (2, 2), ... , (n, n)
-fn id_perm_fill<K, V>(sgm: &mut SGMap<K, V>)
-where
-    K: From<usize> + Ord,
-    V: From<usize>,
-{
-    sgm.clear();
-    for i in 0..sgm.capacity() {
-        #[cfg(not(feature = "high_assurance"))]
-        assert!(sgm.insert(K::from(i), V::from(i)).is_none());
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgm.insert(K::from(i), V::from(i)).is_ok());
-    }
-    assert_eq!(sgm.len(), sgm.capacity());
-}
-
-fn main() {
-    let mut sgm: SGMap<usize, usize> = SGMap::new();
-    id_perm_fill(&mut sgm);
-
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        // Would be panic if !#[no_std]
-        assert_eq!(sgm.insert(usize::MAX, usize::MAX), None);
-    }
-    #[cfg(feature = "high_assurance")]
-    {
-        assert_eq!(
-            sgm.insert(usize::MAX, usize::MAX),
-            Err(SGErr::StackCapacityExceeded)
-        );
-    }
-}
diff --git a/examples/search_by_slice.rs b/examples/search_by_slice.rs
index 407c5f6..3a98e31 100644
--- a/examples/search_by_slice.rs
+++ b/examples/search_by_slice.rs
@@ -1,7 +1,7 @@
 use core::mem::size_of_val;
 
-use scapegoat::SGSet;
-use smallvec::{smallvec, SmallVec};
+use scapegoat::SgSet;
+use tinyvec::array_vec;
 
 const U8_BUF_LEN: usize = 32;
 
@@ -18,28 +18,25 @@ fn main() {
     assert_eq!(size_of_val(&bad_food), 8);
 
     // Store the two words in our set
-    let mut set = SGSet::new();
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        set.insert(bad_code);
-        set.insert(bad_food);
-    }
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(set.insert(bad_code).is_ok());
-        assert!(set.insert(bad_food).is_ok());
-    }
+    let mut set = SgSet::<_, U8_BUF_LEN>::new();
+    set.insert(bad_code);
+    set.insert(bad_food);
 
     // Vec<u8> is sized, it's actually a fat pointer to a heap buffer.
-    // SmallVec<[u8; U8_BUF_LEN]> is sized, it's actually a stack buffer.
+    // ArrayVec<[u8; U8_BUF_LEN]> is sized, it's actually a stack buffer.
     // But slices of the vec are unsized! For example:
     //     &my_vec[0..5] is the first 5 elements
     //     &my_vec[1..] is all but the first element
     //     &my_vec[..] is all elements
-    let bad_food_vec: SmallVec<[u8; U8_BUF_LEN]> =
-        smallvec![0xB, 0xA, 0xA, 0xD, 0xF, 0x0, 0x0, 0xD];
-    let bad_dude_vec: SmallVec<[u8; U8_BUF_LEN]> =
-        smallvec![0xB, 0xA, 0xA, 0xD, 0xD, 0x0, 0x0, 0xD];
+    let bad_food_vec = array_vec![
+        [u8; U8_BUF_LEN] =>
+        0xB, 0xA, 0xA, 0xD, 0xF, 0x0, 0x0, 0xD
+    ];
+
+    let bad_dude_vec = array_vec![
+        [u8; U8_BUF_LEN] =>
+        0xB, 0xA, 0xA, 0xD, 0xD, 0x0, 0x0, 0xD
+    ];
 
     // We're effectively searching for a [u8; 8] present
     assert_eq!(
diff --git a/examples/static_strs.rs b/examples/static_strs.rs
index ac1f220..9044487 100644
--- a/examples/static_strs.rs
+++ b/examples/static_strs.rs
@@ -1,50 +1,48 @@
-use scapegoat::SGMap;
-use smallvec::{smallvec, SmallVec};
+use scapegoat::SgMap;
+use tinyvec::{array_vec, ArrayVec};
 
-const REF_BUF_LEN: usize = 5;
+// This const is an argument to each generic constructor below.
+// So we'll use *only the bare minimum* memory for 5 elements.
+// - Stack RAM usage can be precisely controlled: per map instance (constructor call-site).
+// - To save executable RAM/ROM (monomorphization!), stick to a global capacity like this.
+const CAPACITY: usize = 5;
 
-// !#[no_std] demo mutable manipulation of SGMap<isize, &str>
+// !#[no_std] demo mutable manipulation of SgMap<isize, &str, 5>
 fn main() {
-    let mut example = SGMap::new();
+    let mut example = SgMap::<_, _, CAPACITY>::new(); // BTreeMap::new()
     let mut stack_str = "your friend the";
 
     // Insert "dynamically" (as if heap)
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        example.insert(3, "the");
-        example.insert(2, "don't blame");
-        example.insert(1, "Please");
-        example.insert(4, "borrow checker");
-    }
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(example.insert(3, "the").is_ok());
-        assert!(example.insert(2, "don't blame").is_ok());
-        assert!(example.insert(1, "Please").is_ok());
-        assert!(example.insert(4, "borrow checker").is_ok());
-    }
+    example.insert(3, "the");
+    example.insert(2, "don't blame");
+    example.insert(1, "Please");
+
+    // Fallible insert variant
+    assert!(example.try_insert(4, "borrow checker").is_ok());
 
     // Ordered reference iterator
     assert!(example
         .iter()
         .map(|(_, v)| *v)
-        .collect::<SmallVec<[&str; REF_BUF_LEN]>>()
+        .collect::<ArrayVec<[&str; CAPACITY]>>()
         .iter()
         .eq(["Please", "don't blame", "the", "borrow checker"].iter()));
 
     // Container indexing
     assert_eq!(example[&3], "the");
 
-    // Fast (no search) head removal
+    // Head removal
     let please_tuple = example.pop_first().unwrap();
     assert_eq!(please_tuple, (1, "Please"));
 
-    // By-predicate removal (iterates all entries)
+    // By-predicate removal
     example.retain(|_, v| !v.contains("a"));
 
     // Extension
-    let iterable: SmallVec<[(isize, &str); REF_BUF_LEN]> =
-        smallvec![(1337, "safety!"), (0, "Leverage"), (100, "for")];
+    let iterable = array_vec![
+        [(isize, &str); CAPACITY] =>
+        (1337, "safety!"), (0, "Leverage"), (100, "for")
+    ];
     example.extend(iterable.into_iter());
 
     // Value mutation
@@ -55,7 +53,7 @@ fn main() {
     // New message :)
     assert!(example
         .into_values()
-        .collect::<SmallVec<[&str; REF_BUF_LEN]>>()
+        .collect::<ArrayVec<[&str; CAPACITY]>>()
         .iter()
         .eq([
             "Leverage",
diff --git a/examples/tiny_map.rs b/examples/tiny_map.rs
index 52fbc15..d4d570b 100644
--- a/examples/tiny_map.rs
+++ b/examples/tiny_map.rs
@@ -1,51 +1,22 @@
-#[allow(unused_imports)]
-use core::mem::size_of;
+use core::mem::size_of_val;
+use scapegoat::SgMap;
 
-#[allow(unused_imports)]
-use scapegoat::{SGMap, SGSet};
-
-// About:
-// * Index packing and low-memory insertion mode 78% (9.7KB) of stack usage (the extreme case!).
-// * Usage:
-//      $ export SG_MAX_STACK_ELEMS=256
-//      $ cargo run --example tiny_map
-//      $ cargo run --example tiny_map --features="high_assurance,low_mem_insert"
 fn main() {
-    // This code assumes `SG_MAX_STACK_ELEMS == 256` (non-default)
-    let temp: SGMap<u8, u8> = SGMap::new();
-    if temp.capacity() == 256 {
-        // Without packing
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(not(feature = "high_assurance"))]
-        #[cfg(not(feature = "low_mem_insert"))]
-        {
-            // Map of 256 (u8, u8) pairs
-            assert_eq!(size_of::<SGMap<u8, u8>>(), 12_384);
-
-            // Set of 256 u8 values
-            // Unfortunately the internal () value in the pair is not optimized out, so same size as map
-            assert_eq!(size_of::<SGSet<u8>>(), 12_384);
-
-            // Moving up to a u16 without packing, both the set and map are actually the same size as the u8 case above!
-            assert_eq!(size_of::<SGMap<u16, u16>>(), 12_384);
-            assert_eq!(size_of::<SGSet<u16>>(), 12_384);
-        }
+    let tiny_map: SgMap<u8, u8, 128> = SgMap::new();
 
-        // With packing
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(feature = "high_assurance")]
-        #[cfg(feature = "low_mem_insert")]
-        {
-            // Packed map of 256 (u8, u8) pairs
-            assert_eq!(size_of::<SGMap<u8, u8>>(), 2_608);
-
-            // Packed set of 256 u8 values
-            // Unfortunately the internal () value in the pair is not optimized out, so same size as map
-            assert_eq!(size_of::<SGSet<u8>>(), 2_608);
+    // Default configuration
+    #[cfg(target_pointer_width = "64")]
+    #[cfg(not(feature = "fast_rebalance"))]
+    #[cfg(not(feature = "low_mem_insert"))]
+    {
+        assert_eq!(size_of_val(&tiny_map), 1_608);
+    }
 
-            // Moving up to a u16, we see alignment that allows optimization of the () value - set is smaller than map!
-            assert_eq!(size_of::<SGMap<u16, u16>>(), 3_120);
-            assert_eq!(size_of::<SGSet<u16>>(), 2_608);
-        }
+    // Optimizing for low stack footprint
+    #[cfg(target_pointer_width = "64")]
+    #[cfg(not(feature = "fast_rebalance"))]
+    #[cfg(feature = "low_mem_insert")]
+    {
+        assert_eq!(size_of_val(&tiny_map), 1_352);
     }
 }
diff --git a/examples/try_insert.rs b/examples/try_insert.rs
new file mode 100644
index 0000000..639ecb4
--- /dev/null
+++ b/examples/try_insert.rs
@@ -0,0 +1,26 @@
+use scapegoat::{SgError, SgMap};
+
+// Identity permutation fill: (0, 0), (1, 1), (2, 2), ... , (n, n)
+fn id_perm_fill<K, V, const N: usize>(sgm: &mut SgMap<K, V, N>)
+where
+    K: From<usize> + Ord + Default,
+    V: From<usize> + Default,
+{
+    sgm.clear();
+    for i in 0..sgm.capacity() {
+        // Can insert, not yet full
+        assert!(sgm.try_insert(K::from(i), V::from(i)).is_ok());
+    }
+    assert!(sgm.is_full());
+}
+
+fn main() {
+    let mut sgm: SgMap<usize, usize, 1024> = SgMap::new();
+    id_perm_fill(&mut sgm);
+
+    // Can't insert, full!
+    assert_eq!(
+        sgm.try_insert(usize::MAX, usize::MAX),
+        Err(SgError::StackCapacityExceeded)
+    );
+}
diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml
index 5e969fc..511862b 100644
--- a/fuzz/Cargo.toml
+++ b/fuzz/Cargo.toml
@@ -10,9 +10,9 @@ edition = "2018"
 cargo-fuzz = true
 
 [dependencies]
-#libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] } // TODO: why doesn't this work?
-libfuzzer-sys = { version = "0.4" }
+libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] }
 arbitrary = { version = "1", features = ["derive"] }
+smallnum = "^0.4"
 
 [dependencies.scapegoat]
 path = ".."
diff --git a/fuzz/README.md b/fuzz/README.md
index ee07b31..1b3c3bc 100644
--- a/fuzz/README.md
+++ b/fuzz/README.md
@@ -17,7 +17,7 @@ For structure-aware fuzzing:
 cargo fuzz run sg_arena
 ```
 
-### `SGSet` APIs
+### `SgSet` APIs
 
 The goal of fuzzing is to ensure "lock step" with `std::collections::BTreeSet`.
 For structure-aware, differential fuzzing:
@@ -26,7 +26,7 @@ For structure-aware, differential fuzzing:
 cargo fuzz run sg_set
 ```
 
-### `SGMap` APIs
+### `SgMap` APIs
 
 The goal of fuzzing is to ensure "lock step" with `std::collections::BTreeMap`.
 For structure-aware, differential fuzzing:
@@ -35,6 +35,6 @@ For structure-aware, differential fuzzing:
 cargo fuzz run sg_map
 ```
 
-### `SGTree` APIs
+### `SgTree` APIs
 
-Both the `SGSet` and `SGMap` APIs are build atop `SGSet`, so their respective targets already provide `SGTree` coverage.
\ No newline at end of file
+Both the `SgSet` and `SgMap` APIs are build atop `SgSet`, so their respective targets already provide `SgTree` coverage.
\ No newline at end of file
diff --git a/fuzz/fuzz_targets/sg_arena.rs b/fuzz/fuzz_targets/sg_arena.rs
index 2e66743..762086d 100644
--- a/fuzz/fuzz_targets/sg_arena.rs
+++ b/fuzz/fuzz_targets/sg_arena.rs
@@ -1,79 +1,68 @@
 #![no_main]
 
 use std::collections::BTreeSet;
-use std::convert::TryInto;
 use std::fmt;
 
-use arbitrary::Arbitrary;
-use libfuzzer_sys::fuzz_target;
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
 
-use scapegoat::{Node, NodeArena};
+use scapegoat::Arena;
+use smallnum::small_unsigned;
 
-// Note: the hard_*() methods call their Option-returning equivalents
-// E.g. hard_get() calls get()
+const CAPACITY: usize = 2048;
+type Idx = small_unsigned!(CAPACITY);
+
+// Note: hard_remove() calls remove()
 // We only need to test the former to get coverage, since the harness upholds valid index invariants (same as library)
 #[derive(Arbitrary, Debug)]
 enum ArenaMethod<K: Ord + fmt::Debug, V: fmt::Debug> {
+    // new_idx_vec() always returns an array.
     New,
     // capacity() returns a constant. Omitted, irrelevant coverage.
     Add { key: K, val: V },
     Iter,
     IterMut,
     HardRemove { idx: usize },
-    HardGet { idx: usize },
-    HardGetMut { idx: usize },
     Len,
-    // sort() exercised through SGMap fuzz target (input invariants are complex, tree structure related)
+    IsOccupied { idx: usize },
+    // sort() exercised through SgMap fuzz target (input invariants are complex, tree structure related)
+    // node_size() returns a constant. Omitted, irrelevant coverage.
 }
 
 fuzz_target!(|methods: Vec<ArenaMethod<usize, usize>>| {
-    let mut arena = NodeArena::new();   // Arena under test
-    let mut idx_set = BTreeSet::new();  // Currently used arena indexs
+    let mut arena = Arena::<usize, usize, Idx, CAPACITY>::new(); // Arena under test
+    let mut idx_set = BTreeSet::new(); // Currently used arena indexes
 
     for m in methods {
         match m {
             ArenaMethod::New => {
-                arena = NodeArena::new();
+                arena = Arena::new();
                 idx_set.clear();
-            },
+            }
             ArenaMethod::Add { key, val } => {
-                let node = Node::new(key, val);
-                let idx = arena.add(node);
-                idx_set.insert(idx);
-            },
+                if idx_set.len() < CAPACITY {
+                    let idx = arena.add(key, val);
+                    idx_set.insert(idx);
+                }
+            }
             ArenaMethod::Iter => {
                 let _ = arena.iter();
-            },
+            }
             ArenaMethod::IterMut => {
                 let _ = arena.iter_mut();
-            },
-            ArenaMethod::HardRemove { idx } => {
-                match idx_set.remove(&idx.try_into().unwrap()) {
-                    false => continue,
-                    true => {
-                        let _ = arena.hard_remove(idx.try_into().unwrap());
-                    }
-                }
-            },
-            ArenaMethod::HardGet { idx } => {
-                match idx_set.get(&idx.try_into().unwrap()) {
-                    Some(valid_idx) => {
-                        let _ = arena.hard_get(*valid_idx);
-                    },
-                    None => continue,
-                }
-            },
-            ArenaMethod::HardGetMut { idx } => {
-                match idx_set.get(&idx.try_into().unwrap()) {
-                    Some(valid_idx) => {
-                        let _ = arena.hard_get_mut(*valid_idx);
-                    },
-                    None => continue,
+            }
+            ArenaMethod::HardRemove { idx } => match idx_set.remove(&idx) {
+                false => continue,
+                true => {
+                    let _ = arena.hard_remove(idx);
                 }
-            },
+            }
             ArenaMethod::Len => {
                 let _ = arena.len();
             }
+            ArenaMethod::IsOccupied { idx } => match idx_set.contains(&idx) {
+                false => continue,
+                true => assert!(arena.is_occupied(idx)),
+            }
         }
     }
 });
diff --git a/fuzz/fuzz_targets/sg_map.rs b/fuzz/fuzz_targets/sg_map.rs
index 6181467..177df55 100644
--- a/fuzz/fuzz_targets/sg_map.rs
+++ b/fuzz/fuzz_targets/sg_map.rs
@@ -2,13 +2,14 @@
 #![feature(map_first_last)]
 
 use std::collections::BTreeMap;
-use std::iter::FromIterator;
 use std::fmt::Debug;
+use std::iter::FromIterator;
+
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
 
-use arbitrary::Arbitrary;
-use libfuzzer_sys::fuzz_target;
+use scapegoat::SgMap;
 
-use scapegoat::SGMap;
+const CAPACITY: usize = 2048;
 
 #[derive(Arbitrary, Debug)]
 enum MapMethod<K: Ord + Debug, V: Debug> {
@@ -46,44 +47,45 @@ enum MapMethod<K: Ord + Debug, V: Debug> {
     Ord { other: Vec<(K, V)> },
 }
 
-fn checked_get_len<K: Ord, V>(sg_map: &SGMap<K, V>, bt_map: &BTreeMap<K, V>) -> usize {
+fn checked_get_len<K: Ord + Default, V: Default, const N: usize>(sg_map: &SgMap<K, V, N>, bt_map: &BTreeMap<K, V>) -> usize {
     let len = sg_map.len();
-    assert_eq!(
-        len,
-        bt_map.len()
-    );
+    assert_eq!(len, bt_map.len());
 
     len
 }
 
-fn assert_len_unchanged<K: Ord, V>(sg_map: &SGMap<K, V>, bt_map: &BTreeMap<K, V>, old_len: usize) {
-    assert_eq!(
-        checked_get_len(&sg_map, &bt_map),
-        old_len
-    );
+fn assert_len_unchanged<K: Ord + Default, V: Default, const N: usize>(sg_map: &SgMap<K, V, N>, bt_map: &BTreeMap<K, V>, old_len: usize) {
+    assert_eq!(checked_get_len(&sg_map, &bt_map), old_len);
 }
 
 // Differential fuzzing harness
 fuzz_target!(|methods: Vec<MapMethod<usize, usize>>| {
-    let mut sg_map = SGMap::new();      // Data structure under test
-    let mut bt_map = BTreeMap::new();   // Reference data structure
+    let mut sg_map = SgMap::<_, _, CAPACITY>::new(); // Data structure under test
+    let mut bt_map = BTreeMap::new(); // Reference data structure
 
     for m in methods {
         match m {
             // API Equivalence -----------------------------------------------------------------------------------------
             MapMethod::Append { other } => {
-                let mut sg_other = SGMap::from_iter(other.clone());
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let mut sg_other = SgMap::from_iter(other.clone());
                 let mut bt_other = BTreeMap::from_iter(other);
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                sg_map.append(&mut sg_other);
-                bt_map.append(&mut bt_other);
+                assert_eq!(sg_other.len(), bt_other.len());
+                if (len_old + sg_other.len()) <= CAPACITY {
+                    sg_map.append(&mut sg_other);
+                    bt_map.append(&mut bt_other);
 
-                assert!(sg_other.is_empty());
-                assert!(bt_other.is_empty());
+                    assert!(sg_other.is_empty());
+                    assert!(bt_other.is_empty());
 
-                assert!(checked_get_len(&sg_map, &bt_map) >= len_old);
-            },
+                    assert!(checked_get_len(&sg_map, &bt_map) >= len_old);
+                }
+            }
             MapMethod::Clear => {
                 sg_map.clear();
                 bt_map.clear();
@@ -93,178 +95,128 @@ fuzz_target!(|methods: Vec<MapMethod<usize, usize>>| {
 
                 assert_eq!(sg_map.len(), 0);
                 assert_eq!(bt_map.len(), 0);
-            },
+            }
             MapMethod::ContainsKey { key } => {
-                assert_eq!(
-                    sg_map.contains_key(&key),
-                    bt_map.contains_key(&key)
-                );
-            },
+                assert_eq!(sg_map.contains_key(&key), bt_map.contains_key(&key));
+            }
             MapMethod::FirstKey => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
                 match bt_map.first_entry() {
                     Some(occupied_entry) => {
-                        assert_eq!(
-                            sg_map.first_key(),
-                            Some(occupied_entry.key()),
-                        );
-                    },
+                        assert_eq!(sg_map.first_key(), Some(occupied_entry.key()),);
+                    }
                     None => {
-                        assert_eq!(
-                            sg_map.first_key(),
-                            None
-                        );
+                        assert_eq!(sg_map.first_key(), None);
                     }
                 };
 
                 assert_len_unchanged(&sg_map, &bt_map, len_old);
-            },
+            }
             MapMethod::FirstKeyValue => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.first_key_value(),
-                    bt_map.first_key_value()
-                );
+                assert_eq!(sg_map.first_key_value(), bt_map.first_key_value());
 
                 assert_len_unchanged(&sg_map, &bt_map, len_old);
-            },
+            }
             MapMethod::Get { key } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.get(&key),
-                    bt_map.get(&key)
-                );
+                assert_eq!(sg_map.get(&key), bt_map.get(&key));
 
                 assert_len_unchanged(&sg_map, &bt_map, len_old);
-            },
+            }
             MapMethod::GetKeyValue { key } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.get_key_value(&key),
-                    bt_map.get_key_value(&key)
-                );
+                assert_eq!(sg_map.get_key_value(&key), bt_map.get_key_value(&key));
 
                 assert_len_unchanged(&sg_map, &bt_map, len_old);
-            },
+            }
             MapMethod::GetMut { key } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.get_mut(&key),
-                    bt_map.get_mut(&key)
-                );
+                assert_eq!(sg_map.get_mut(&key), bt_map.get_mut(&key));
 
                 assert_len_unchanged(&sg_map, &bt_map, len_old);
-            },
+            }
             MapMethod::Insert { key, val } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
+                if len_old < CAPACITY {
+                    assert_eq!(sg_map.insert(key, val), bt_map.insert(key, val));
 
-                assert_eq!(
-                    sg_map.insert(key, val),
-                    bt_map.insert(key, val)
-                );
-
-                assert!(checked_get_len(&sg_map, &bt_map) >= len_old);
-            },
+                    assert!(checked_get_len(&sg_map, &bt_map) >= len_old);
+                }
+            }
             MapMethod::IsEmpty => {
-                assert_eq!(
-                    sg_map.is_empty(),
-                    bt_map.is_empty(),
-                );
-            },
+                assert_eq!(sg_map.is_empty(), bt_map.is_empty(),);
+            }
             MapMethod::Iter => {
                 assert!(sg_map.iter().eq(bt_map.iter()));
-            },
+            }
             MapMethod::IterMut => {
                 assert!(sg_map.iter_mut().eq(bt_map.iter_mut()));
-            },
+            }
             MapMethod::Keys => {
                 assert!(sg_map.keys().eq(bt_map.keys()));
-            },
+            }
             MapMethod::LastKey => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
                 match bt_map.last_entry() {
                     Some(occupied_entry) => {
-                        assert_eq!(
-                            sg_map.last_key(),
-                            Some(occupied_entry.key()),
-                        );
-                    },
+                        assert_eq!(sg_map.last_key(), Some(occupied_entry.key()),);
+                    }
                     None => {
-                        assert_eq!(
-                            sg_map.last_key(),
-                            None
-                        );
+                        assert_eq!(sg_map.last_key(), None);
                     }
                 };
 
                 assert_len_unchanged(&sg_map, &bt_map, len_old);
-            },
+            }
             MapMethod::LastKeyValue => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.last_key_value(),
-                    bt_map.last_key_value()
-                );
+                assert_eq!(sg_map.last_key_value(), bt_map.last_key_value());
 
                 assert_len_unchanged(&sg_map, &bt_map, len_old);
-            },
+            }
             MapMethod::Len => {
-                assert_eq!(
-                    sg_map.len(),
-                    bt_map.len()
-                );
-            },
+                assert_eq!(sg_map.len(), bt_map.len());
+            }
             MapMethod::New => {
-                sg_map = SGMap::new();
+                sg_map = SgMap::new();
                 bt_map = BTreeMap::new();
-            },
+            }
             MapMethod::PopFirst => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.pop_first(),
-                    bt_map.pop_first()
-                );
+                assert_eq!(sg_map.pop_first(), bt_map.pop_first());
 
                 assert!(checked_get_len(&sg_map, &bt_map) <= len_old);
-            },
+            }
             MapMethod::PopLast => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.pop_last(),
-                    bt_map.pop_last()
-                );
+                assert_eq!(sg_map.pop_last(), bt_map.pop_last());
 
                 assert!(checked_get_len(&sg_map, &bt_map) <= len_old);
-            },
+            }
             MapMethod::Remove { key } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.remove(&key),
-                    bt_map.remove(&key)
-                );
+                assert_eq!(sg_map.remove(&key), bt_map.remove(&key));
 
                 assert!(checked_get_len(&sg_map, &bt_map) <= len_old);
-            },
+            }
             MapMethod::RemoveEntry { key } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert_eq!(
-                    sg_map.remove_entry(&key),
-                    bt_map.remove_entry(&key)
-                );
+                assert_eq!(sg_map.remove_entry(&key), bt_map.remove_entry(&key));
 
                 assert!(checked_get_len(&sg_map, &bt_map) <= len_old);
-            },
+            }
             MapMethod::Retain { rand_key } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
@@ -273,50 +225,51 @@ fuzz_target!(|methods: Vec<MapMethod<usize, usize>>| {
 
                 assert!(sg_map.iter().eq(bt_map.iter()));
                 assert!(checked_get_len(&sg_map, &bt_map) <= len_old);
-            },
+            }
             MapMethod::SplitOff { key } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
 
-                assert!(sg_map.split_off(&key).iter().eq(bt_map.split_off(&key).iter()));
+                assert!(sg_map
+                    .split_off(&key)
+                    .iter()
+                    .eq(bt_map.split_off(&key).iter()));
 
                 assert!(sg_map.iter().eq(bt_map.iter()));
                 assert!(checked_get_len(&sg_map, &bt_map) <= len_old);
-            },
+            }
             // Trait Equivalence ---------------------------------------------------------------------------------------
             MapMethod::Clone => {
                 assert!(sg_map.clone().iter().eq(bt_map.clone().iter()));
-            },
+            }
             MapMethod::Debug => {
-                assert_eq!(
-                    format!("{:?}", sg_map),
-                    format!("{:?}", bt_map),
-                );
-            },
+                assert_eq!(format!("{:?}", sg_map), format!("{:?}", bt_map),);
+            }
             MapMethod::Extend { other } => {
                 let len_old = checked_get_len(&sg_map, &bt_map);
-
-                sg_map.extend(other.clone().into_iter());
-                bt_map.extend(other.into_iter());
-
-                assert!(sg_map.iter().eq(bt_map.iter()));
-                assert!(checked_get_len(&sg_map, &bt_map) >= len_old);
-            },
+                if (len_old + other.len()) <= CAPACITY {
+                    sg_map.extend(other.clone().into_iter());
+                    bt_map.extend(other.into_iter());
+
+                    assert!(sg_map.iter().eq(bt_map.iter()));
+                    assert!(checked_get_len(&sg_map, &bt_map) >= len_old);
+                }
+            }
             MapMethod::Ord { other } => {
-                let sg_map_new = SGMap::from_iter(other.clone().into_iter());
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let sg_map_new = SgMap::from_iter(other.clone().into_iter());
                 let bt_map_new = BTreeMap::from_iter(other.into_iter());
 
-                assert_eq!(
-                    sg_map.cmp(&sg_map_new),
-                    bt_map.cmp(&bt_map_new),
-                );
-            },
+                assert_eq!(sg_map.cmp(&sg_map_new), bt_map.cmp(&bt_map_new),);
+            }
             MapMethod::Values => {
                 assert!(sg_map.values().eq(bt_map.values()));
-            },
+            }
             MapMethod::ValuesMut => {
                 assert!(sg_map.values_mut().eq(bt_map.values_mut()));
-            },
+            }
         }
     }
 });
-
diff --git a/fuzz/fuzz_targets/sg_set.rs b/fuzz/fuzz_targets/sg_set.rs
index d1f32a6..15d55c7 100644
--- a/fuzz/fuzz_targets/sg_set.rs
+++ b/fuzz/fuzz_targets/sg_set.rs
@@ -2,13 +2,14 @@
 #![feature(map_first_last)]
 
 use std::collections::BTreeSet;
-use std::iter::FromIterator;
 use std::fmt::Debug;
+use std::iter::FromIterator;
+
+use libfuzzer_sys::{arbitrary::Arbitrary, fuzz_target};
 
-use arbitrary::Arbitrary;
-use libfuzzer_sys::fuzz_target;
+use scapegoat::SgSet;
 
-use scapegoat::SGSet;
+const CAPACITY: usize = 2048;
 
 #[derive(Arbitrary, Debug)]
 enum SetMethod<T: Ord + Debug> {
@@ -46,44 +47,45 @@ enum SetMethod<T: Ord + Debug> {
     Ord { other: Vec<T> },
 }
 
-fn checked_get_len<T: Ord>(sg_set: &SGSet<T>, bt_set: &BTreeSet<T>) -> usize {
-        let len = sg_set.len();
-        assert_eq!(
-            len,
-            bt_set.len()
-        );
+fn checked_get_len<T: Ord + Default, const N: usize>(sg_set: &SgSet<T, N>, bt_set: &BTreeSet<T>) -> usize {
+    let len = sg_set.len();
+    assert_eq!(len, bt_set.len());
 
-        len
+    len
 }
 
-fn assert_len_unchanged<T: Ord>(sg_set: &SGSet<T>, bt_set: &BTreeSet<T>, old_len: usize) {
-    assert_eq!(
-        checked_get_len(&sg_set, &bt_set),
-        old_len
-    );
+fn assert_len_unchanged<T: Ord + Default, const N: usize>(sg_set: &SgSet<T, N>, bt_set: &BTreeSet<T>, old_len: usize) {
+    assert_eq!(checked_get_len(&sg_set, &bt_set), old_len);
 }
 
 // Differential fuzzing harness
 fuzz_target!(|methods: Vec<SetMethod<usize>>| {
-    let mut sg_set = SGSet::new();      // Data structure under test
-    let mut bt_set = BTreeSet::new();   // Reference data structure
+    let mut sg_set = SgSet::new(); // Data structure under test
+    let mut bt_set = BTreeSet::new(); // Reference data structure
 
     for m in methods {
         match m {
             // API Equivalence -----------------------------------------------------------------------------------------
             SetMethod::Append { other } => {
-                let mut sg_other = SGSet::from_iter(other.clone());
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let mut sg_other = SgSet::from_iter(other.clone());
                 let mut bt_other = BTreeSet::from_iter(other);
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                sg_set.append(&mut sg_other);
-                bt_set.append(&mut bt_other);
+                assert_eq!(sg_other.len(), bt_other.len());
+                if (len_old + sg_other.len()) <= CAPACITY {
+                    sg_set.append(&mut sg_other);
+                    bt_set.append(&mut bt_other);
 
-                assert!(sg_other.is_empty());
-                assert!(bt_other.is_empty());
+                    assert!(sg_other.is_empty());
+                    assert!(bt_other.is_empty());
 
-                assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
-            },
+                    assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
+                }
+            }
             SetMethod::Clear => {
                 sg_set.clear();
                 bt_set.clear();
@@ -93,144 +95,147 @@ fuzz_target!(|methods: Vec<SetMethod<usize>>| {
 
                 assert_eq!(sg_set.len(), 0);
                 assert_eq!(bt_set.len(), 0);
-            },
+            }
             SetMethod::Contains { value } => {
-                assert_eq!(
-                    sg_set.contains(&value),
-                    bt_set.contains(&value)
-                );
-            },
+                assert_eq!(sg_set.contains(&value), bt_set.contains(&value));
+            }
             SetMethod::Difference { other } => {
-                let sg_diff: Vec<_> = sg_set.difference(&SGSet::from_iter(other.clone())).cloned().collect();
-                let bt_diff: Vec<_> = bt_set.difference(&BTreeSet::from_iter(other)).cloned().collect();
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let sg_diff: Vec<_> = sg_set
+                    .difference(&SgSet::from_iter(other.clone()))
+                    .cloned()
+                    .collect();
+
+                let bt_diff: Vec<_> = bt_set
+                    .difference(&BTreeSet::from_iter(other))
+                    .cloned()
+                    .collect();
 
                 assert_eq!(sg_diff, bt_diff);
                 assert!(sg_diff.len() <= sg_set.len());
-            },
+            }
             SetMethod::First => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert_eq!(
-                    sg_set.first(),
-                    bt_set.first()
-                );
+                assert_eq!(sg_set.first(), bt_set.first());
 
                 assert_len_unchanged(&sg_set, &bt_set, len_old);
-            },
+            }
             SetMethod::Get { value } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert_eq!(
-                    sg_set.get(&value),
-                    bt_set.get(&value)
-                );
+                assert_eq!(sg_set.get(&value), bt_set.get(&value));
 
                 assert_len_unchanged(&sg_set, &bt_set, len_old);
-            },
+            }
             SetMethod::Insert { value } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
+                if len_old < CAPACITY {
+                    assert_eq!(sg_set.insert(value), bt_set.insert(value));
 
-                assert_eq!(
-                    sg_set.insert(value),
-                    bt_set.insert(value)
-                );
-
-                assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
-            },
+                    assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
+                }
+            }
             SetMethod::Intersection { other } => {
-                let sg_inter: Vec<_> = sg_set.intersection(&SGSet::from_iter(other.clone())).cloned().collect();
-                let bt_inter: Vec<_> = bt_set.intersection(&BTreeSet::from_iter(other)).cloned().collect();
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let sg_inter: Vec<_> = sg_set
+                    .intersection(&SgSet::from_iter(other.clone()))
+                    .cloned()
+                    .collect();
+
+                let bt_inter: Vec<_> = bt_set
+                    .intersection(&BTreeSet::from_iter(other))
+                    .cloned()
+                    .collect();
 
                 assert_eq!(sg_inter, bt_inter);
                 assert!(sg_inter.len() <= sg_set.len());
-            },
+            }
             SetMethod::IsDisjoint { other } => {
+                if other.len() > CAPACITY {
+                    continue
+                }
+
                 assert_eq!(
-                    sg_set.is_disjoint(&SGSet::from_iter(other.clone())),
+                    sg_set.is_disjoint(&SgSet::from_iter(other.clone())),
                     bt_set.is_disjoint(&BTreeSet::from_iter(other))
                 );
-            },
+            }
             SetMethod::IsEmpty => {
-                assert_eq!(
-                    sg_set.is_empty(),
-                    bt_set.is_empty(),
-                );
-            },
+                assert_eq!(sg_set.is_empty(), bt_set.is_empty(),);
+            }
             SetMethod::IsSubset { other } => {
+                if other.len() > CAPACITY {
+                    continue
+                }
+
                 assert_eq!(
-                    sg_set.is_subset(&SGSet::from_iter(other.clone())),
+                    sg_set.is_subset(&SgSet::from_iter(other.clone())),
                     bt_set.is_subset(&BTreeSet::from_iter(other))
                 );
-            },
+            }
             SetMethod::Iter => {
                 assert!(sg_set.iter().eq(bt_set.iter()));
-            },
+            }
             SetMethod::IsSuperset { other } => {
+                if other.len() > CAPACITY {
+                    continue
+                }
+
                 assert_eq!(
-                    sg_set.is_superset(&SGSet::from_iter(other.clone())),
+                    sg_set.is_superset(&SgSet::from_iter(other.clone())),
                     bt_set.is_superset(&BTreeSet::from_iter(other))
                 );
-            },
+            }
             SetMethod::Last => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert_eq!(
-                    sg_set.last(),
-                    bt_set.last()
-                );
+                assert_eq!(sg_set.last(), bt_set.last());
 
                 assert_len_unchanged(&sg_set, &bt_set, len_old);
-            },
+            }
             SetMethod::Len => {
-                assert_eq!(
-                    sg_set.len(),
-                    bt_set.len()
-                );
+                assert_eq!(sg_set.len(), bt_set.len());
             }
             SetMethod::New => {
-                sg_set = SGSet::new();
+                sg_set = SgSet::new();
                 bt_set = BTreeSet::new();
-            },
+            }
             SetMethod::PopFirst => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert_eq!(
-                    sg_set.pop_first(),
-                    bt_set.pop_first()
-                );
+                assert_eq!(sg_set.pop_first(), bt_set.pop_first());
 
                 assert!(checked_get_len(&sg_set, &bt_set) <= len_old);
-            },
+            }
             SetMethod::PopLast => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert_eq!(
-                    sg_set.pop_last(),
-                    bt_set.pop_last()
-                );
+                assert_eq!(sg_set.pop_last(), bt_set.pop_last());
 
                 assert!(checked_get_len(&sg_set, &bt_set) <= len_old);
-            },
+            }
             SetMethod::Remove { value } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert_eq!(
-                    sg_set.remove(&value),
-                    bt_set.remove(&value)
-                );
+                assert_eq!(sg_set.remove(&value), bt_set.remove(&value));
 
                 assert!(checked_get_len(&sg_set, &bt_set) <= len_old);
-            },
+            }
             SetMethod::Replace { value } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
+                if len_old < CAPACITY {
+                    assert_eq!(sg_set.replace(value), bt_set.replace(value));
 
-                assert_eq!(
-                    sg_set.replace(value),
-                    bt_set.replace(value)
-                );
-
-                assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
-            },
+                    assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
+                }
+            }
             SetMethod::Retain { rand_value } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
@@ -239,66 +244,85 @@ fuzz_target!(|methods: Vec<SetMethod<usize>>| {
 
                 assert!(sg_set.iter().eq(bt_set.iter()));
                 assert!(checked_get_len(&sg_set, &bt_set) <= len_old);
-            },
+            }
             SetMethod::SplitOff { value } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert!(sg_set.split_off(&value).iter().eq(bt_set.split_off(&value).iter()));
+                assert!(sg_set
+                    .split_off(&value)
+                    .iter()
+                    .eq(bt_set.split_off(&value).iter()));
 
                 assert!(sg_set.iter().eq(bt_set.iter()));
                 assert!(checked_get_len(&sg_set, &bt_set) <= len_old);
-            },
+            }
             SetMethod::SymmetricDifference { other } => {
-                let sg_sym_diff: Vec<_> = sg_set.symmetric_difference(&SGSet::from_iter(other.clone())).cloned().collect();
-                let bt_sym_diff: Vec<_> = bt_set.symmetric_difference(&BTreeSet::from_iter(other)).cloned().collect();
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let sg_sym_diff: Vec<_> = sg_set
+                    .symmetric_difference(&SgSet::from_iter(other.clone()))
+                    .cloned()
+                    .collect();
+
+                let bt_sym_diff: Vec<_> = bt_set
+                    .symmetric_difference(&BTreeSet::from_iter(other))
+                    .cloned()
+                    .collect();
 
                 assert_eq!(sg_sym_diff, bt_sym_diff);
-            },
+            }
             SetMethod::Take { value } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                assert_eq!(
-                    sg_set.take(&value),
-                    bt_set.take(&value)
-                );
+                assert_eq!(sg_set.take(&value), bt_set.take(&value));
 
                 assert!(checked_get_len(&sg_set, &bt_set) <= len_old);
-            },
+            }
             SetMethod::Union { other } => {
-                let sg_union: Vec<_>= sg_set.union(&SGSet::from_iter(other.clone())).cloned().collect();
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let sg_union: Vec<_> = sg_set
+                    .union(&SgSet::from_iter(other.clone()))
+                    .cloned()
+                    .collect();
+
                 let bt_union: Vec<_> = bt_set.union(&BTreeSet::from_iter(other)).cloned().collect();
 
                 assert_eq!(sg_union, bt_union);
                 assert!(sg_union.len() >= sg_set.len());
-            },
+            }
             // Trait Equivalence ---------------------------------------------------------------------------------------
             SetMethod::Clone => {
                 assert!(sg_set.clone().iter().eq(bt_set.clone().iter()));
-            },
+            }
             SetMethod::Debug => {
-                assert_eq!(
-                    format!("{:?}", sg_set),
-                    format!("{:?}", bt_set),
-                );
+                assert_eq!(format!("{:?}", sg_set), format!("{:?}", bt_set),);
             }
             SetMethod::Extend { other } => {
                 let len_old = checked_get_len(&sg_set, &bt_set);
 
-                sg_set.extend(other.clone().into_iter());
-                bt_set.extend(other.into_iter());
+                if (len_old + other.len()) <= CAPACITY {
+                    sg_set.extend(other.clone().into_iter());
+                    bt_set.extend(other.into_iter());
 
-                assert!(sg_set.iter().eq(bt_set.iter()));
-                assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
-            },
+                    assert!(sg_set.iter().eq(bt_set.iter()));
+                    assert!(checked_get_len(&sg_set, &bt_set) >= len_old);
+                }
+            }
             SetMethod::Ord { other } => {
-                let sg_set_new = SGSet::from_iter(other.clone().into_iter());
+                if other.len() > CAPACITY {
+                    continue
+                }
+
+                let sg_set_new = SgSet::<_, CAPACITY>::from_iter(other.clone().into_iter());
                 let bt_set_new = BTreeSet::from_iter(other.into_iter());
 
-                assert_eq!(
-                    sg_set.cmp(&sg_set_new),
-                    bt_set.cmp(&bt_set_new),
-                );
-            },
+                assert_eq!(sg_set.cmp(&sg_set_new), bt_set.cmp(&bt_set_new),);
+            }
         }
     }
-});
\ No newline at end of file
+});
diff --git a/gen_readme.sh b/gen_readme.sh
index 9cdbbc5..4060709 100755
--- a/gen_readme.sh
+++ b/gen_readme.sh
@@ -3,4 +3,7 @@
 cargo readme --no-indent-headings > README.md
 
 # Image before crate name/version header
-echo -e "<br><p align=\"center\"><img src=\"https://raw.githubusercontent.com/tnballo/scapegoat/master/img/scapegoat.svg\" width=\"333\" alt=\"scapegoat\"></p><br>\n$(cat README.md)" > README.md
\ No newline at end of file
+echo -e "<br><p align=\"center\"><img src=\"https://raw.githubusercontent.com/tnballo/scapegoat/master/img/scapegoat.svg\" width=\"333\" alt=\"scapegoat\"></p><br>\n$(cat README.md)" > README.md
+
+# Make sure we're still truly no_std
+cargo build --target="thumbv7m-none-eabi"
diff --git a/misc/min_size/README.md b/misc/min_size/README.md
index 565ecfb..b594aca 100644
--- a/misc/min_size/README.md
+++ b/misc/min_size/README.md
@@ -1,19 +1,19 @@
-## Minimum Executable Size Comparison: `SGMap` vs `BTreeMap`
+## Minimum Executable Size Comparison: `SgMap` vs `BTreeMap`
 
-This directory contains a repeatable experiment: how small can we possibly make binaries that use `SGMap` and it's API-compatible counterpart, `BTreeMap`?
+This directory contains a repeatable experiment: how small can we possibly make binaries that use `SgMap` and it's API-compatible counterpart, `BTreeMap`?
 In terms of executable code bytes stored in the `.text` section.
 
-[`min_size_no_std`](./min_size_no_std/src/main.rs) is a `scapegoat::SGMap` test binary that calls only the most basic functions of the data structure: `insert`, `get`, and `remove`.
-It doesn't need a global allocator, since `SGMap` uses a stack arena.
+[`min_size_no_std`](./min_size_no_std/src/main.rs) is a `scapegoat::SgMap` test binary that calls only the most basic functions of the data structure: `insert`, `get`, and `remove`.
+It doesn't need a global allocator, since `SgMap` uses a stack arena.
 
 ```rust
 #![no_std]
 #![no_main]
-use scapegoat::SGMap;
+use scapegoat::SgMap;
 
 #[no_mangle]
 pub fn main(_argc: i32, _argv: *const *const u8) -> isize {
-    let mut map: SGMap<usize, usize> = SGMap::new();
+    let mut map: SgMap<usize, usize, 1024> = SgMap::new();
     map.insert(1, 2);
     assert_eq!(map.get(&1), Some(&2));
     assert_eq!(map.remove(&1), Some(2));
@@ -106,7 +106,7 @@ error: could not find native static library `c`, perhaps an -L flag is missing?
 
 Now we're ready to build some static binaries, fully from source!
 
-### Results for `scapegoat::SGMap`
+### Results for `scapegoat::SgMap`
 
 Determine executable byte count:
 
@@ -118,8 +118,8 @@ cargo size --release
 Sample output from an x86-64 machine (note your milage may vary, depending on your host architecture and compiler version):
 
 ```
-  text	   data	    bss	    dec	    hex	filename
-  17014	   3592	    728	  21334	   5356	min_size_no_std
+   text	   data	    bss	    dec	    hex	filename
+  16084	   3528	    728	  20340	   4f74	min_size_no_std
 ```
 
 **This demonstrates a `.text` section under 20KB in size is possible!**
@@ -132,22 +132,22 @@ To check sources of bloat:
 cargo bloat --release -n 10
 ```
 
-Sample output (oddly the reported `.text` size of 14.7KB is smaller than `cargo size`'s 17.0KB):
+Sample output (oddly the reported `.text` size of 13.9KB is smaller than `cargo size`'s 16.0KB):
 
 ```
  File  .text    Size     Crate Name
- 4.1%  19.6%  2.9KiB [Unknown] main
- 3.4%  16.6%  2.4KiB       std core::slice::sort::recurse
- 0.9%   4.3%    651B       std core::fmt::Formatter::pad_integral
- 0.9%   4.1%    625B       std <core::fmt::builders::PadAdapter as core::fmt::Write>::write_str
- 0.8%   3.8%    568B       std core::fmt::write
- 0.6%   2.7%    410B  smallvec smallvec::SmallVec<A>::push
- 0.6%   2.7%    403B  smallvec smallvec::SmallVec<A>::push
- 0.5%   2.6%    393B  smallvec smallvec::SmallVec<A>::push
- 0.5%   2.6%    391B [Unknown] static_init_tls
- 0.5%   2.6%    386B  smallvec smallvec::SmallVec<A>::push
- 7.5%  36.2%  5.3KiB           And 73 smaller methods. Use -n N to show more.
-20.7% 100.0% 14.7KiB           .text section size, the file size is 71.1KiB
+ 3.1%  17.7%  2.5KiB       std core::slice::sort::recurse
+ 2.4%  13.9%  1.9KiB [Unknown] main
+ 1.6%   9.1%  1.3KiB scapegoat scapegoat::tree::tree::SgTree<K,V,_>::rebuild
+ 0.8%   4.6%    651B       std core::fmt::Formatter::pad_integral
+ 0.8%   4.4%    625B       std <core::fmt::builders::PadAdapter as core::fmt::Write>::write_str
+ 0.7%   4.0%    568B       std core::fmt::write
+ 0.5%   2.8%    391B [Unknown] static_init_tls
+ 0.5%   2.7%    385B [Unknown] __init_libc
+ 0.4%   2.4%    346B [Unknown] _start_c
+ 0.4%   2.4%    335B       std core::fmt::builders::DebugTuple::field
+ 6.0%  34.1%  4.7KiB           And 69 smaller methods. Use -n N to show more.
+17.6% 100.0% 13.9KiB           .text section size, the file size is 78.8KiB
 ```
 
 Unclear why we need `core::fmt::write`, but regardless we're definitely in that **20KB ballpark**.
@@ -208,8 +208,8 @@ Sample output (oddly the reported `.text` size of 16.4KB is smaller than `cargo
 
 ### Conclusion
 
-Both `scapegoat::SGMap` and `std::collections::BTreeMap` can produce working dynamic collections in binaries under 20KB.
-Much to my surprise, both produce 17KB binaries despite the latter including `musl` libc's memory allocator.
+Both `scapegoat::SgMap` and `std::collections::BTreeMap` can produce working dynamic collections in binaries under 20KB.
+Perhaps surprisingly, both produce 16-17KB binaries despite the latter including `musl` libc's memory allocator.
 
 * Thanks to everyone that made suggestions on [this reddit thread](https://www.reddit.com/r/rust/comments/qu3k38/1012x_smaller_executable_footprint_than/).
 
diff --git a/misc/min_size/min_size_no_std/Cargo.toml b/misc/min_size/min_size_no_std/Cargo.toml
index 7882593..3aea9f8 100644
--- a/misc/min_size/min_size_no_std/Cargo.toml
+++ b/misc/min_size/min_size_no_std/Cargo.toml
@@ -1,18 +1,13 @@
-#cargo-features = ["strip"]
-
 [package]
 name = "min_size_no_std"
 version = "0.1.0"
 edition = "2021"
 
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
 [profile.dev]
 panic = "abort"
 
 [profile.release]
 panic = "abort"
-#strip = true
 opt-level = "z"
 lto = true
 codegen-units = 1
diff --git a/misc/min_size/min_size_no_std/src/main.rs b/misc/min_size/min_size_no_std/src/main.rs
index bcc1e9c..c2b6680 100644
--- a/misc/min_size/min_size_no_std/src/main.rs
+++ b/misc/min_size/min_size_no_std/src/main.rs
@@ -9,11 +9,11 @@ use core::alloc::{GlobalAlloc, Layout};
 
 extern crate libc;
 
-use scapegoat::SGMap;
+use scapegoat::SgMap;
 
 #[no_mangle]
 pub fn main(_argc: i32, _argv: *const *const u8) -> isize {
-    let mut map: SGMap<usize, usize> = SGMap::new();
+    let mut map: SgMap<usize, usize, 1024> = SgMap::new();
     map.insert(1, 2);
     assert_eq!(map.get(&1), Some(&2));
     assert_eq!(map.remove(&1), Some(2));
diff --git a/misc/min_size/min_size_std/Cargo.toml b/misc/min_size/min_size_std/Cargo.toml
index cecbebe..aca7460 100644
--- a/misc/min_size/min_size_std/Cargo.toml
+++ b/misc/min_size/min_size_std/Cargo.toml
@@ -1,18 +1,13 @@
-#cargo-features = ["strip"]
-
 [package]
 name = "min_size_std"
 version = "0.1.0"
 edition = "2021"
 
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
 [profile.dev]
 panic = "abort"
 
 [profile.release]
 panic = "abort"
-#strip = true
 opt-level = "z"
 lto = true
 codegen-units = 1
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 7413b99..0428803 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,19 +1,18 @@
 /*!
 Ordered set and map data structures via an arena-based [scapegoat tree](https://people.csail.mit.edu/rivest/pubs/GR93.pdf) (memory-efficient, self-balancing binary search tree).
 
-* Safe: `#![forbid(unsafe_code)]`.
 * Embedded-friendly: `!#[no_std]` by default.
+* Safe: `#![forbid(unsafe_code)]`, including all dependencies.
 * Validated via differential fuzzing, against the standard library's `BTreeSet` and `BTreeMap`.
 
 ### About
 
-Three APIs:
+Two APIs:
 
-* Ordered Set API ([`SGSet`](crate::SGSet)) - subset of [`BTreeSet`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html) nightly.
-* Ordered Map API ([`SGMap`](crate::SGMap)) - subset of [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) nightly.
-* Binary Tree API ([`SGTree`](crate::SGTree)) - backend for the previous two.
+* Ordered Set API ([`SgSet`](crate::SgSet)) - subset of [`BTreeSet`](https://doc.rust-lang.org/stable/std/collections/struct.BTreeSet.html) nightly.
+* Ordered Map API ([`SgMap`](crate::SgMap)) - subset of [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html) nightly.
 
-Strives for two properties:
+Strives for three properties:
 
 * **Maximal safety:** strong [memory safety](https://tiemoko.com/blog/blue-team-rust/) guarantees, hence `#![forbid(unsafe_code)]`.
     * **Compile-time safety:** no `unsafe` (no raw pointer dereference, etc.).
@@ -25,51 +24,64 @@ Strives for two properties:
     * **Recursion-free:** all operations are iterative, so stack use is fixed and runtime is minimized.
     * **Zero-copy:** rebuild/removal re-point in-place, nodes are never copied or cloned.
 
+* **Fallibility**: for embedded use cases prioritizing robustness (or [kernelspace](https://lkml.org/lkml/2021/4/14/1099) code):
+    * A `try_*` variant of each fallible API (e.g. `insert`, `append`, `extend`, etc.) is available.
+    * **Out-of-memory (OOM)** `panic!` becomes avoidable: `try_*` variants return [`Result<_, SgError>`](crate::SgError).
+    * Heap fragmentation doesn't impact **Worst Case Execution Time (WCET)**, this library doesn't use the heap.
+
 Other features:
 
-* **Generic:** map keys and set elements can be any type that implements the `Ord` trait.
-* **Arbitrarily mutable:** elements can be insert and removed, map values can be mutated.
+* **Generic:** map keys and set elements can be any type that implements the `Ord + Default` traits.
+* **Arbitrarily mutable:** elements can be inserted and removed, map values can be mutated. Safely.
 
 ### Usage
 
-`SGMap` non-exhaustive, `!#[no_std]` API example (would work identically for `std::collections::BTreeMap`):
+`SgMap` non-exhaustive, `!#[no_std]` API example (would work almost identically for `std::collections::BTreeMap`):
 
 ```rust
-use scapegoat::SGMap;
-use smallvec::{smallvec, SmallVec};
+use scapegoat::SgMap;
+use tinyvec::{array_vec, ArrayVec};
 
-const REF_BUF_LEN: usize = 5;
+// This const is an argument to each generic constructor below.
+// So we'll use *only the bare minimum* memory for 5 elements.
+// - Stack RAM usage can be precisely controlled: per map instance (constructor call-site).
+// - To save executable RAM/ROM (monomorphization!), stick to a global capacity like this.
+const CAPACITY: usize = 5;
 
-let mut example = SGMap::new();
+let mut example = SgMap::<_, _, CAPACITY>::new(); // BTreeMap::new()
 let mut stack_str = "your friend the";
 
 // Insert "dynamically" (as if heap)
 example.insert(3, "the");
 example.insert(2, "don't blame");
 example.insert(1, "Please");
-example.insert(4, "borrow checker");
+
+// Fallible insert variant
+assert!(example.try_insert(4, "borrow checker").is_ok());
 
 // Ordered reference iterator
 assert!(example
     .iter()
     .map(|(_, v)| *v)
-    .collect::<SmallVec<[&str; REF_BUF_LEN]>>()
+    .collect::<ArrayVec<[&str; CAPACITY]>>()
     .iter()
     .eq(["Please","don't blame","the","borrow checker"].iter()));
 
 // Container indexing
 assert_eq!(example[&3], "the");
 
-// Fast (no search) head removal
+// Head removal
 let please_tuple = example.pop_first().unwrap();
 assert_eq!(please_tuple, (1, "Please"));
 
-// By-predicate removal (iterates all entries)
+// By-predicate removal
 example.retain(|_, v| !v.contains("a"));
 
 // Extension
-let iterable: SmallVec<[(isize, &str); REF_BUF_LEN]> =
-    smallvec![(1337, "safety!"), (0, "Leverage"), (100, "for")];
+let iterable = array_vec![
+    [(isize, &str); CAPACITY] =>
+    (1337, "safety!"), (0, "Leverage"), (100, "for")
+];
 example.extend(iterable.into_iter());
 
 // Value mutation
@@ -80,97 +92,59 @@ if let Some(three_val) = example.get_mut(&3) {
 // New message :)
 assert!(example
     .into_values()
-    .collect::<SmallVec<[&str; REF_BUF_LEN]>>()
+    .collect::<ArrayVec<[&str; CAPACITY]>>()
     .iter()
     .eq(["Leverage","your friend the","borrow checker","for","safety!"].iter()));
 ```
 
 Additional [examples here](https://github.com/tnballo/scapegoat/blob/master/examples/README.md).
 
-### Configuring a Stack Storage Limit
+### Stack Capacity: Important Context
 
-The maximum number of stack-stored elements (set) or key-value pairs (map/tree) is determined at compile-time, via the environment variable `SG_MAX_STACK_ELEMS`.
-[Valid values](https://docs.rs/smallvec/1.7.0/smallvec/trait.Array.html#foreign-impls) include the range `[0, 32]` and powers of 2 up to `1,048,576`.
-For example, to store up to `2048` items on the stack:
+Per the above, const generic type parameters decide collection capacity.
+And thus also stack usage.
+That usage is fixed:
 
-```bash
-export SG_MAX_STACK_ELEMS=2048
-cargo build --release
+```rust
+use core::mem::size_of_val;
+use scapegoat::SgMap;
+
+let small_map: SgMap<u64, u64, 100> = SgMap::new(); // 100 item capacity
+let big_map: SgMap<u64, u64, 2_048> = SgMap::new(); // 2,048 item capacity
+
+#[cfg(target_pointer_width = "64")]
+#[cfg(not(feature = "low_mem_insert"))]
+#[cfg(not(feature = "fast_rebalance"))]
+{
+    assert_eq!(size_of_val(&small_map), 2_680); // 2.7 KB
+    assert_eq!(size_of_val(&big_map), 53_328);  // 53.3 KB
+}
 ```
 
-Please note:
-
-* If the `SG_MAX_STACK_ELEMS` environment variable is not set, it will default to `1024`.
-
-* For any system with heap memory: the first `SG_MAX_STACK_ELEMS` elements are stack-allocated and the remainder will be automatically heap-allocated.
-
-* For embedded systems with only stack memory: `SG_MAX_STACK_ELEMS` is a hard maximum - attempting to insert beyond this limit will cause a panic.
-    * Use feature `high_assurance` to ensure error handling and avoid panic (see below).
+The maximum supported capacity is `65_535` (e.g. `0xffff` or [`u16::MAX`](https://doc.rust-lang.org/std/primitive.u16.html#associatedconstant.MAX)) items.
 
-> **Warning:**
-> Although stack usage is constant (no recursion), a stack overflow can happen at runtime if `SG_MAX_STACK_ELEMS` (configurable) and/or the stored item type (generic) is too large.
+> **WARNING:**
+> Although stack usage is constant (no recursion), a stack overflow can happen at runtime if `N` (const generic capacity) and/or the stored item type (generic) is too large.
 > Note *stack* overflow is distinct from *buffer* overflow (which safe Rust prevents).
 > Regardless, you must test to ensure you don't exceed the stack frame(s) size limit of your target platform.
 > Rust only supports stack probes on x86/x64, although [creative linking solutions](https://blog.japaric.io/stack-overflow-protection/) have been suggested for other architectures.
 
 For more advanced configuration options, see [the documentation here](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md).
 
-### The `high_assurance` Feature
+### Trusted Dependencies
 
-For embedded use cases prioritizing robustness (or [kernelspace](https://lkml.org/lkml/2021/4/14/1099) code), the `high_assurance` feature can be enabled with the standard `Cargo.toml` declaration:
-
-```ignore
-[dependencies]
-scapegoat = { version = "^1.7", features = ["high_assurance"] }
-```
-
-Enabling this feature makes two changes:
-
-1. **Front-end, API Tweak:** `insert` and `append` APIs now return `Result`. `Err` indicates stack storage is already at maximum capacity, so caller must handle. No heap use, no panic potential on insert.
-
-2. **Back-end, Integer Packing:** Because the fixed/max size of the stack arena is known, indexing integers (metadata stored at every node!) can be size-optimized. This memory micro-optimization honors the original design goals of the scapegoat data structure.
+This library has three dependencies, each of which have no dependencies of their own (e.g. exactly three total dependencies).
 
-That second change is a subtle but interesting one.
-Example of packing saving 53% (31 KB) of RAM usage:
+* [`tinyvec`](https://crates.io/crates/tinyvec) - `!#[no_std]`, `#![forbid(unsafe_code)]` alternative to `Vec`.
+* [`micromath`](https://crates.io/crates/micromath) - `!#[no_std]`, `#![forbid(unsafe_code)]` floating point approximations.
+* [`smallnum`](https://crates.io/crates/smallnum) - `!#[no_std]`, `#![forbid(unsafe_code)]` integer abstraction.
 
-```rust
-use core::mem::size_of;
-use scapegoat::SGMap;
-
-// If you're on a 64-bit system, you can compile-time check the below numbers yourself!
-// Just do:
-//
-// $ cargo test --doc
-// $ cargo test --doc --features="high_assurance"
-//
-// One command per set of `cfg` macros below.
-// Internally, this compile-time struct packing is done with the `smallnum` crate:
-// https://crates.io/crates/smallnum
-
-// This code assumes `SG_MAX_STACK_ELEMS == 1024` (default)
-let temp: SGMap<u64, u64> = SGMap::new();
-let other_features_enabled = cfg!(any(feature = "fast_rebalance", feature = "low_mem_insert"));
-if temp.capacity() == 1024 && (!other_features_enabled) {
-
-    // Without packing
-    #[cfg(target_pointer_width = "64")]
-    #[cfg(not(feature = "high_assurance"))] // Disabled
-    {
-        assert_eq!(size_of::<SGMap<u64, u64>>(), 57_440);
-    }
-
-    // With packing
-    #[cfg(target_pointer_width = "64")]
-    #[cfg(feature = "high_assurance")]  // Enabled
-    {
-        assert_eq!(size_of::<SGMap<u64, u64>>(), 26_688);
-    }
-}
-```
+Because this library and all dependencies are `#![forbid(unsafe_code)]`, no 3rd-party `unsafe` code is introduced into your project.
+Safety is proven at compile-time.
 
-### Considerations
+### Additional Considerations
 
-#### General Goals
+**General Goals**
 
 This project is an exercise in safe, portable data structure design.
 The goal is to offer embedded developers familiar, ergonomic APIs on resource constrained systems that otherwise don't get the luxury of dynamic collections.
@@ -181,37 +155,31 @@ The standard library has been heavily optimized for cache performance.
 This library is optimized for low, stack-only memory footprint.
 It offers:
 
-* **Best-effort Compatibility:** APIs are a subset of `BTreeMap`'s/`BTreeSet`'s, making it a somewhat "drop-in" replacement for `!#[no_std]` systems. Please [open an issue](https://github.com/tnballo/scapegoat/issues) if an API you need isn't yet supported.
+* **Best-effort Compatibility:** APIs are mostly a subset of `BTreeMap`'s/`BTreeSet`'s, making it a mostly "drop-in" replacement for `!#[no_std]` systems. Please [open an issue](https://github.com/tnballo/scapegoat/issues) if an API you need isn't yet supported.
 
 * **Dynamic Validation:** [Coverage-guided differential fuzzing](https://github.com/tnballo/scapegoat/blob/master/fuzz/README.md) is used to demonstrate that this implementation is logically equivalent and equally reliable.
 
 * **Tunable Performance:** A [single floating point value](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md#tuning-the-the-trees-a-factor) optimizes relative performance of `insert`, `get`, and `remove` operation classes. And it can be changed at runtime.
 
-#### Algorithmic Complexity
+**Algorithmic Complexity**
 
-Space complexity is always `O(n)`.
+Space complexity is always `O(n)`. Time complexity:
 
 | Operation | Average Case | Worst Case |
 | --- | --- | --- |
 | `get` | `O(log n)` | `O(log n)` |
 | `insert` | `O(log n)` | Amortized `O(log n)` |
 | `remove` | `O(log n)` | Amortized `O(log n)` |
+| `first` | `O(1)` | `O(1)` |
+| `last` | `O(1)` | `O(1)` |
 
 The [`low_mem_insert`](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md#the-low_mem_insert-feature) and [`fast_rebalance`](https://github.com/tnballo/scapegoat/blob/master/CONFIG.md#the-fast_rebalance-feature) features can be used to fine-tune tradeoffs of memory usage and speed.
 
-#### Memory Footprint Demos
+**Memory Footprint Demos**
 
-* [Code size demo](https://github.com/tnballo/scapegoat/blob/master/misc/min_size/README.md) - `SGMap<usize, usize>` with `insert`, `get`, and `remove` called: **17.0KB** for an x86-64 binary. Caveat: you'll likely want to use more than 3 functions, resulting in more executable code getting included.
+* [Code size demo](https://github.com/tnballo/scapegoat/blob/master/misc/min_size/README.md) - `SgMap<usize, usize, 1024>` with `insert`, `get`, and `remove` called: **16.0KB** for an x86-64 binary. Caveat: you'll likely want to use more than 3 functions, resulting in more executable code getting included.
 
-* [Stack space demo](https://github.com/tnballo/scapegoat/blob/master/examples/tiny_map.rs) - `SGMap<u8, u8>` with a 256 pair capacity: **2.6KB** storage cost. Caveat: 2-3x more stack space is required for runtime book keeping (e.g. rebalancing).
-
-#### Trusted Dependencies
-
-This library has three dependencies, each of which have no dependencies of their own (e.g. exactly three total dependencies).
-
-* [`smallvec`](https://crates.io/crates/smallvec) - `!#[no_std]` compatible `Vec` alternative. Used in Mozilla's Servo browser engine.
-* [`micromath`](https://crates.io/crates/micromath) - `!#[no_std]`, `#![forbid(unsafe_code)]` floating point approximations.
-* [`smallnum`](https://crates.io/crates/smallnum) - `!#[no_std]`, `#![forbid(unsafe_code)]` integer packing.
+* [Stack space demo](https://github.com/tnballo/scapegoat/blob/master/examples/tiny_map.rs) - `SgMap<u8, u8, 128>`: **1.3KB** storage cost. Caveat: more stack space is required for runtime book keeping (e.g. rebalancing).
 
 ### License and Contributing
 
@@ -219,6 +187,10 @@ Licensed under the [MIT license](https://github.com/tnballo/scapegoat/blob/maste
 Contributions are welcome!
 */
 
+// Test temp
+//#![feature(variant_count)]
+
+// Production
 #![forbid(unsafe_code)]
 #![cfg_attr(not(any(test, fuzzing)), no_std)]
 #![cfg_attr(not(any(test, fuzzing)), deny(missing_docs))]
@@ -226,17 +198,21 @@ Contributions are welcome!
     html_logo_url = "https://raw.githubusercontent.com/tnballo/scapegoat/master/img/scapegoat.svg"
 )]
 
-include!(concat!(env!("OUT_DIR"), "/consts.rs"));
-
 // Only expose arena internals for fuzzing harness
 #[cfg(fuzzing)]
-pub use crate::tree::{Node, NodeArena, NodeGetHelper, NodeRebuildHelper};
+pub use crate::tree::{Arena, Node, NodeGetHelper, NodeRebuildHelper};
 
 mod tree;
-pub use crate::tree::{SGErr, SGTree};
+pub use crate::tree::SgError;
 
 mod map;
-pub use crate::map::{IntoKeys, IntoValues, Keys, SGMap, Values, ValuesMut};
+pub use crate::map::SgMap;
+
+/// [`SgMap`][crate::map::SgMap]'s iterator return types.
+pub mod map_types;
 
 mod set;
-pub use crate::set::SGSet;
+pub use crate::set::SgSet;
+
+/// [`SgSet`][crate::set::SgSet]'s iterator return types.
+pub mod set_types;
diff --git a/src/map.rs b/src/map.rs
index 74999c2..defca5e 100644
--- a/src/map.rs
+++ b/src/map.rs
@@ -3,31 +3,45 @@ use core::fmt::{self, Debug};
 use core::iter::FromIterator;
 use core::ops::Index;
 
-use crate::tree::{IntoIter, Iter, IterMut, SGErr, SGTree};
+use crate::map_types::{IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut};
+use crate::tree::{SgError, SgTree};
 
-/// Ordered map.
-/// A wrapper interface for `SGTree`.
-/// API examples and descriptions are all adapted or directly copied from the standard library's [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html).
-#[allow(clippy::upper_case_acronyms)] // TODO: Removal == breaking change, e.g. v2.0
+/// Safe, fallible, embedded-friendly ordered map.
+///
+/// ### Fallible APIs
+///
+/// * [`try_insert`][crate::map::SgMap::try_insert]
+/// * [`try_append`][crate::map::SgMap::try_append]
+/// * [`try_extend`][crate::map::SgMap::try_extend]
+/// * [`try_from_iter`][crate::map::SgMap::try_from_iter]
+///
+/// [`TryFrom`](https://doc.rust-lang.org/stable/std/convert/trait.TryFrom.html) isn't implemented because it would collide with the blanket implementation.
+/// See [this open GitHub issue](https://github.com/rust-lang/rust/issues/50133#issuecomment-64690839) from 2018,
+/// this is a known Rust limitation that should be fixed via specialization in the future.
+///
+/// ### Attribution Note
+///
+/// The majority of API examples and descriptions are adapted or directly copied from the standard library's [`BTreeMap`](https://doc.rust-lang.org/std/collections/struct.BTreeMap.html).
+/// The goal is to offer embedded developers familiar, ergonomic APIs on resource constrained systems that otherwise don't get the luxury of dynamic collections.
 #[derive(Default, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
-pub struct SGMap<K: Ord, V> {
-    bst: SGTree<K, V>,
+pub struct SgMap<K: Ord + Default, V: Default, const N: usize> {
+    pub(crate) bst: SgTree<K, V, N>,
 }
 
-impl<K: Ord, V> SGMap<K, V> {
-    /// Makes a new, empty `SGMap`.
+impl<K: Ord + Default, V: Default, const N: usize> SgMap<K, V, N> {
+    /// Makes a new, empty `SgMap`.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     ///
     /// map.insert(1, "a");
     /// ```
     pub fn new() -> Self {
-        SGMap { bst: SGTree::new() }
+        SgMap { bst: SgTree::new() }
     }
 
     /// The [original scapegoat tree paper's](https://people.csail.mit.edu/rivest/pubs/GR93.pdf) alpha, `a`, can be chosen in the range `0.5 <= a < 1.0`.
@@ -45,26 +59,28 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map: SGMap<isize, isize> = SGMap::new();
+    /// let mut map: SgMap<isize, isize, 10> = SgMap::new();
     ///
     /// // Set 2/3, e.g. `a = 0.666...` (it's default value).
     /// assert!(map.set_rebal_param(2.0, 3.0).is_ok());
     /// ```
-    pub fn set_rebal_param(&mut self, alpha_num: f32, alpha_denom: f32) -> Result<(), SGErr> {
+    #[doc(alias = "rebalance")]
+    #[doc(alias = "alpha")]
+    pub fn set_rebal_param(&mut self, alpha_num: f32, alpha_denom: f32) -> Result<(), SgError> {
         self.bst.set_rebal_param(alpha_num, alpha_denom)
     }
 
     /// Get the current rebalance parameter, alpha, as a tuple of `(alpha_numerator, alpha_denominator)`.
-    /// See [the corresponding setter method][SGMap::set_rebal_param] for more details.
+    /// See [the corresponding setter method][SgMap::set_rebal_param] for more details.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map: SGMap<isize, isize> = SGMap::new();
+    /// let mut map: SgMap<isize, isize, 10> = SgMap::new();
     ///
     /// // Set 2/3, e.g. `a = 0.666...` (it's default value).
     /// assert!(map.set_rebal_param(2.0, 3.0).is_ok());
@@ -72,24 +88,22 @@ impl<K: Ord, V> SGMap<K, V> {
     /// // Get the currently set value
     /// assert_eq!(map.rebal_param(), (2.0, 3.0));
     /// ```
+    #[doc(alias = "rebalance")]
+    #[doc(alias = "alpha")]
     pub fn rebal_param(&self) -> (f32, f32) {
         self.bst.rebal_param()
     }
 
-    /// `#![no_std]`: total capacity, e.g. maximum number of map pairs.
-    /// Attempting to insert pairs beyond capacity will panic, unless the `high_assurance` feature is enabled.
-    ///
-    /// If using `std`: fast capacity, e.g. number of map pairs stored on the stack.
-    /// Pairs inserted beyond capacity will be stored on the heap.
+    /// Total capacity, e.g. maximum number of map pairs.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::<usize, &str>::new();
+    /// let mut map = SgMap::<usize, &str, 10>::new();
     ///
-    /// assert!(map.capacity() > 0)
+    /// assert!(map.capacity() == 10);
     /// ```
     pub fn capacity(&self) -> usize {
         self.bst.capacity()
@@ -99,19 +113,17 @@ impl<K: Ord, V> SGMap<K, V> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(2, "b");
     /// a.insert(1, "a");
     ///
     /// let keys: Vec<_> = a.keys().cloned().collect();
     /// assert_eq!(keys, [1, 2]);
     /// ```
-    pub fn keys(&self) -> Keys<'_, K, V> {
+    pub fn keys(&self) -> Keys<'_, K, V, N> {
         Keys { inner: self.iter() }
     }
 
@@ -122,16 +134,16 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(2, "b");
     /// a.insert(1, "a");
     ///
     /// let keys: Vec<i32> = a.into_keys().collect();
     /// assert_eq!(keys, [1, 2]);
     /// ```
-    pub fn into_keys(self) -> IntoKeys<K, V> {
+    pub fn into_keys(self) -> IntoKeys<K, V, N> {
         IntoKeys {
             inner: self.into_iter(),
         }
@@ -141,19 +153,17 @@ impl<K: Ord, V> SGMap<K, V> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(1, "hello");
     /// a.insert(2, "goodbye");
     ///
     /// let values: Vec<&str> = a.values().cloned().collect();
     /// assert_eq!(values, ["hello", "goodbye"]);
     /// ```
-    pub fn values(&self) -> Values<'_, K, V> {
+    pub fn values(&self) -> Values<'_, K, V, N> {
         Values { inner: self.iter() }
     }
 
@@ -164,16 +174,16 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(1, "hello");
     /// a.insert(2, "goodbye");
     ///
     /// let values: Vec<&str> = a.into_values().collect();
     /// assert_eq!(values, ["hello", "goodbye"]);
     /// ```
-    pub fn into_values(self) -> IntoValues<K, V> {
+    pub fn into_values(self) -> IntoValues<K, V, N> {
         IntoValues {
             inner: self.into_iter(),
         }
@@ -183,12 +193,10 @@ impl<K: Ord, V> SGMap<K, V> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(1, String::from("hello"));
     /// a.insert(2, String::from("goodbye"));
     ///
@@ -200,7 +208,7 @@ impl<K: Ord, V> SGMap<K, V> {
     /// assert_eq!(values, [String::from("hello!"),
     ///                     String::from("goodbye!")]);
     /// ```
-    pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
+    pub fn values_mut(&mut self) -> ValuesMut<'_, K, V, N> {
         ValuesMut {
             inner: self.iter_mut(),
         }
@@ -211,14 +219,14 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(1, "a");
     /// a.insert(2, "b");
     /// a.insert(3, "c");
     ///
-    /// let mut b = SGMap::new();
+    /// let mut b = SgMap::<_, _, 10>::new();
     /// b.insert(3, "d");
     /// b.insert(4, "e");
     /// b.insert(5, "f");
@@ -234,8 +242,7 @@ impl<K: Ord, V> SGMap<K, V> {
     /// assert_eq!(a[&4], "e");
     /// assert_eq!(a[&5], "f");
     /// ```
-    #[cfg(not(feature = "high_assurance"))]
-    pub fn append(&mut self, other: &mut SGMap<K, V>) {
+    pub fn append(&mut self, other: &mut SgMap<K, V, N>) {
         self.bst.append(&mut other.bst);
     }
 
@@ -244,20 +251,23 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use core::iter::FromIterator;
+    /// use scapegoat::{SgMap, SgError};
     ///
-    /// let mut a = SGMap::new();
-    /// a.insert(1, "a");
-    /// a.insert(2, "b");
-    /// a.insert(3, "c");
+    /// let mut a = SgMap::<_, _, 10>::new();
+    /// a.try_insert(1, "a").is_ok();
+    /// a.try_insert(2, "b").is_ok();
+    /// a.try_insert(3, "c").is_ok();
     ///
-    /// let mut b = SGMap::new();
-    /// b.insert(3, "d");
-    /// b.insert(4, "e");
-    /// b.insert(5, "f");
+    /// let mut b = SgMap::<_, _, 10>::new();
+    /// b.try_insert(3, "d").is_ok(); // Overwrite previous
+    /// b.try_insert(4, "e").is_ok();
+    /// b.try_insert(5, "f").is_ok();
     ///
-    /// a.append(&mut b);
+    /// // Successful append
+    /// assert!(a.try_append(&mut b).is_ok());
     ///
+    /// // Elements moved
     /// assert_eq!(a.len(), 5);
     /// assert_eq!(b.len(), 0);
     ///
@@ -266,10 +276,29 @@ impl<K: Ord, V> SGMap<K, V> {
     /// assert_eq!(a[&3], "d");
     /// assert_eq!(a[&4], "e");
     /// assert_eq!(a[&5], "f");
+    ///
+    /// // Fill remaining capacity
+    /// let mut key = 6;
+    /// while a.len() < a.capacity() {
+    ///     assert!(a.try_insert(key, "filler").is_ok());
+    ///     key += 1;
+    /// }
+    ///
+    /// // Full
+    /// assert!(a.is_full());
+    ///
+    /// // More data
+    /// let mut c = SgMap::<_, _, 10>::from_iter([(11, "k"), (12, "l")]);
+    /// let mut d = SgMap::<_, _, 10>::from_iter([(1, "a2"), (2, "b2")]);
+    ///
+    /// // Cannot append new pairs
+    /// assert_eq!(a.try_append(&mut c), Err(SgError::StackCapacityExceeded));
+    ///
+    /// // Can still replace existing pairs
+    /// assert!(a.try_append(&mut d).is_ok());
     /// ```
-    #[cfg(feature = "high_assurance")]
-    pub fn append(&mut self, other: &mut SGMap<K, V>) -> Result<(), SGErr> {
-        self.bst.append(&mut other.bst)
+    pub fn try_append(&mut self, other: &mut SgMap<K, V, N>) -> Result<(), SgError> {
+        self.bst.try_append(&mut other.bst)
     }
 
     /// Insert a key-value pair into the map.
@@ -280,9 +309,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// assert_eq!(map.insert(37, "a"), None);
     /// assert_eq!(map.is_empty(), false);
     ///
@@ -290,7 +319,6 @@ impl<K: Ord, V> SGMap<K, V> {
     /// assert_eq!(map.insert(37, "c"), Some("b"));
     /// assert_eq!(map[&37], "c");
     /// ```
-    #[cfg(not(feature = "high_assurance"))]
     pub fn insert(&mut self, key: K, val: V) -> Option<V>
     where
         K: Ord,
@@ -299,54 +327,119 @@ impl<K: Ord, V> SGMap<K, V> {
     }
 
     /// Insert a key-value pair into the map.
-    /// Returns `Err` if map's stack capacity is full, else the `Ok` contains:
+    /// Returns `Err` if the operation can't be completed, else the `Ok` contains:
     /// * `None` if the map did not have this key present.
-    /// * The old value if the tree did have this key present (both the value and key are updated,
+    /// * The old value if the map did have this key present (both the value and key are updated,
     /// this accommodates types that can be `==` without being identical).
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::{SGMap, SGErr};
+    /// use scapegoat::{SgMap, SgError};
     ///
-    /// let mut map = SGMap::new();
-    /// assert_eq!(map.insert(37, "a"), Ok(None));
+    /// let mut map = SgMap::<_, _, 10>::new();
+    ///
+    /// // Add a new pair
+    /// assert_eq!(map.try_insert(37, "a"), Ok(None));
     /// assert_eq!(map.is_empty(), false);
     ///
+    /// // Replace existing pair
     /// map.insert(37, "b");
-    /// assert_eq!(map.insert(37, "c"), Ok(Some("b")));
+    /// assert_eq!(map.try_insert(37, "c"), Ok(Some("b")));
     /// assert_eq!(map[&37], "c");
     ///
+    /// // Fill remaining capacity
     /// let mut key = 38;
     /// while map.len() < map.capacity() {
-    ///     map.insert(key, "filler");
+    ///     assert!(map.try_insert(key, "filler").is_ok());
     ///     key += 1;
     /// }
     ///
-    /// assert_eq!(map.first_key(), Some(&37));
-    /// assert_eq!(map.last_key(), Some(&(37 + (map.capacity() - 1))));
-    /// assert_eq!(map.len(), map.capacity());
+    /// // Full
+    /// assert!(map.is_full());
+    ///
+    /// // Cannot insert new pair
+    /// assert_eq!(map.try_insert(key, "out of bounds"), Err(SgError::StackCapacityExceeded));
     ///
-    /// assert_eq!(map.insert(key, "out of bounds"), Err(SGErr::StackCapacityExceeded));
+    /// // Can still replace existing pair
+    /// assert_eq!(map.try_insert(key - 1, "overwrite filler"), Ok(Some("filler")));
     /// ```
-    #[cfg(feature = "high_assurance")]
-    pub fn insert(&mut self, key: K, val: V) -> Result<Option<V>, SGErr>
+    pub fn try_insert(&mut self, key: K, val: V) -> Result<Option<V>, SgError>
     where
         K: Ord,
     {
-        self.bst.insert(key, val)
+        self.bst.try_insert(key, val)
     }
 
-    /// Gets an iterator over the entries of the map, sorted by key.
+    /// Attempt to extend a collection with the contents of an iterator.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use core::iter::FromIterator;
+    /// use scapegoat::{SgMap, SgError};
+    ///
+    /// let mut a = SgMap::<_, _, 2>::new();
+    /// let mut b = SgMap::<_, _, 3>::from_iter([(1, "a"), (2, "b"), (3, "c")]);
+    /// let mut c = SgMap::<_, _, 2>::from_iter([(1, "a"), (2, "b")]);
+    ///
+    /// // Too big
+    /// assert_eq!(a.try_extend(b.into_iter()), Err(SgError::StackCapacityExceeded));
+    ///
+    /// // Fits
+    /// assert!(a.try_extend(c.into_iter()).is_ok());
+    /// ```
+    ///
+    /// ### Note
+    ///
+    /// There is no `TryExtend` trait in `core`/`std`.
+    pub fn try_extend<I: ExactSizeIterator + IntoIterator<Item = (K, V)>>(
+        &mut self,
+        iter: I,
+    ) -> Result<(), SgError> {
+        self.bst.try_extend(iter)
+    }
+
+    /// Attempt conversion from an iterator.
+    /// Will fail if iterator length exceeds `u16::MAX`.
     ///
     /// # Examples
     ///
-    /// Basic usage:
+    /// ```
+    /// use scapegoat::{SgMap, SgError};
+    ///
+    /// const CAPACITY_1: usize = 1_000;
+    /// let vec: Vec<(usize, usize)> = (0..CAPACITY_1).map(|n|(n, n)).collect();
+    /// assert!(SgMap::<usize, usize, CAPACITY_1>::try_from_iter(vec.into_iter()).is_ok());
     ///
+    /// const CAPACITY_2: usize = (u16::MAX as usize) + 1;
+    /// let vec: Vec<(usize, usize)> = (0..CAPACITY_2).map(|n|(n, n)).collect();
+    /// assert_eq!(
+    ///     SgMap::<usize, usize, CAPACITY_2>::try_from_iter(vec.into_iter()),
+    ///     Err(SgError::MaximumCapacityExceeded)
+    /// );
     /// ```
-    /// use scapegoat::SGMap;
     ///
-    /// let mut map = SGMap::new();
+    /// ### Note
+    ///
+    /// There is no `TryFromIterator` trait in `core`/`std`.
+    pub fn try_from_iter<I: ExactSizeIterator + IntoIterator<Item = (K, V)>>(
+        iter: I,
+    ) -> Result<Self, SgError> {
+        match iter.len() <= SgTree::<K, V, N>::max_capacity() {
+            true => Ok(SgMap::from_iter(iter)),
+            false => Err(SgError::MaximumCapacityExceeded),
+        }
+    }
+
+    /// Gets an iterator over the entries of the map, sorted by key.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use scapegoat::SgMap;
+    ///
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(3, "c");
     /// map.insert(2, "b");
     /// map.insert(1, "a");
@@ -358,20 +451,18 @@ impl<K: Ord, V> SGMap<K, V> {
     /// let (first_key, first_value) = map.iter().next().unwrap();
     /// assert_eq!((*first_key, *first_value), (1, "a"));
     /// ```
-    pub fn iter(&self) -> Iter<'_, K, V> {
-        Iter::new(&self.bst)
+    pub fn iter(&self) -> Iter<'_, K, V, N> {
+        Iter::new(self)
     }
 
     /// Gets a mutable iterator over the entries of the map, sorted by key.
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert("a", 1);
     /// map.insert("b", 2);
     /// map.insert("c", 3);
@@ -386,8 +477,8 @@ impl<K: Ord, V> SGMap<K, V> {
     /// let (second_key, second_value) = map.iter().skip(1).next().unwrap();
     /// assert_eq!((*second_key, *second_value), ("b", 12));
     /// ```
-    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
-        IterMut::new(&mut self.bst)
+    pub fn iter_mut(&mut self) -> IterMut<'_, K, V, N> {
+        IterMut::new(self)
     }
 
     /// Removes a key from the map, returning the stored key and value if the key
@@ -399,9 +490,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// assert_eq!(map.remove_entry(&1), Some((1, "a")));
     /// assert_eq!(map.remove_entry(&1), None);
@@ -422,9 +513,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map: SGMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect();
+    /// let mut map: SgMap<i32, i32, 10> = (0..8).map(|x| (x, x*10)).collect();
     /// // Keep only the elements with even-numbered keys.
     /// map.retain(|&k, _| k % 2 == 0);
     /// assert!(map.into_iter().eq(vec![(0, 0), (2, 20), (4, 40), (6, 60)]));
@@ -442,12 +533,10 @@ impl<K: Ord, V> SGMap<K, V> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(1, "a");
     /// a.insert(2, "b");
     /// a.insert(3, "c");
@@ -466,12 +555,12 @@ impl<K: Ord, V> SGMap<K, V> {
     /// assert_eq!(b[&17], "d");
     /// assert_eq!(b[&41], "e");
     /// ```
-    pub fn split_off<Q>(&mut self, key: &Q) -> SGMap<K, V>
+    pub fn split_off<Q>(&mut self, key: &Q) -> SgMap<K, V, N>
     where
         K: Borrow<Q> + Ord,
         Q: Ord + ?Sized,
     {
-        SGMap {
+        SgMap {
             bst: self.bst.split_off(key),
         }
     }
@@ -485,9 +574,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// assert_eq!(map.remove(&1), Some("a"));
     /// assert_eq!(map.remove(&1), None);
@@ -508,9 +597,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
     /// assert_eq!(map.get_key_value(&2), None);
@@ -531,9 +620,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// assert_eq!(map.get(&1), Some(&"a"));
     /// assert_eq!(map.get(&2), None);
@@ -554,9 +643,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// if let Some(x) = map.get_mut(&1) {
     ///     *x = "b";
@@ -576,9 +665,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// a.insert(1, "a");
     /// a.clear();
     /// assert!(a.is_empty());
@@ -594,9 +683,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// assert_eq!(map.contains_key(&1), true);
     /// assert_eq!(map.contains_key(&2), false);
@@ -614,9 +703,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// assert!(a.is_empty());
     /// a.insert(1, "a");
     /// assert!(!a.is_empty());
@@ -625,15 +714,32 @@ impl<K: Ord, V> SGMap<K, V> {
         self.bst.is_empty()
     }
 
+    /// Returns `true` if the map's capacity is filled.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use scapegoat::SgMap;
+    ///
+    /// let mut a = SgMap::<_, _, 2>::new();
+    /// a.insert(1, "a");
+    /// assert!(!a.is_full());
+    /// a.insert(2, "b");
+    /// assert!(a.is_full());
+    /// ```
+    pub fn is_full(&self) -> bool {
+        self.bst.is_full()
+    }
+
     /// Returns a reference to the first key-value pair in the map.
     /// The key in this pair is the minimum key in the map.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// assert_eq!(map.first_key_value(), None);
     /// map.insert(1, "b");
     /// map.insert(2, "a");
@@ -651,9 +757,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// assert_eq!(map.first_key_value(), None);
     /// map.insert(1, "b");
     /// map.insert(2, "a");
@@ -674,9 +780,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// Draining elements in ascending order, while keeping a usable map each iteration.
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// map.insert(2, "b");
     /// while let Some((key, _val)) = map.pop_first() {
@@ -697,9 +803,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "b");
     /// map.insert(2, "a");
     /// assert_eq!(map.last_key_value(), Some((&2, &"a")));
@@ -716,9 +822,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "b");
     /// map.insert(2, "a");
     /// assert_eq!(map.last_key(), Some(&2));
@@ -738,9 +844,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// Draining elements in descending order, while keeping a usable map each iteration.
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut map = SGMap::new();
+    /// let mut map = SgMap::<_, _, 10>::new();
     /// map.insert(1, "a");
     /// map.insert(2, "b");
     /// while let Some((key, _val)) = map.pop_last() {
@@ -760,9 +866,9 @@ impl<K: Ord, V> SGMap<K, V> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let mut a = SGMap::new();
+    /// let mut a = SgMap::<_, _, 10>::new();
     /// assert_eq!(a.len(), 0);
     /// a.insert(1, "a");
     /// assert_eq!(a.len(), 1);
@@ -775,7 +881,7 @@ impl<K: Ord, V> SGMap<K, V> {
 // Convenience Traits --------------------------------------------------------------------------------------------------
 
 // Debug
-impl<K, V> Debug for SGMap<K, V>
+impl<K: Default, V: Default, const N: usize> Debug for SgMap<K, V, N>
 where
     K: Ord + Debug,
     V: Debug,
@@ -786,24 +892,33 @@ where
 }
 
 // From array.
-impl<K, V, const N: usize> From<[(K, V); N]> for SGMap<K, V>
+impl<K: Default, V: Default, const N: usize> From<[(K, V); N]> for SgMap<K, V, N>
 where
     K: Ord,
 {
     /// ```
-    /// use scapegoat::SGMap;
+    /// use scapegoat::SgMap;
     ///
-    /// let map1 = SGMap::from([(1, 2), (3, 4)]);
-    /// let map2: SGMap<_, _> = [(1, 2), (3, 4)].into();
+    /// let map1 = SgMap::from([(1, 2), (3, 4)]);
+    /// let map2: SgMap<_, _, 2> = [(1, 2), (3, 4)].into();
     /// assert_eq!(map1, map2);
     /// ```
+    ///
+    /// ### Warning
+    ///
+    /// [`TryFrom`](https://doc.rust-lang.org/stable/std/convert/trait.TryFrom.html) isn't implemented because it would collide with the blanket implementation.
+    /// See [this open GitHub issue](https://github.com/rust-lang/rust/issues/50133#issuecomment-64690839) from 2018,
+    /// this is a known Rust limitation that should be fixed via specialization in the future.
+    #[doc(alias = "tryfrom")]
+    #[doc(alias = "try_from")]
+    #[doc(alias = "TryFrom")]
     fn from(arr: [(K, V); N]) -> Self {
-        core::array::IntoIter::new(arr).collect()
+        IntoIterator::into_iter(arr).collect()
     }
 }
 
 // Indexing
-impl<K, V, Q> Index<&Q> for SGMap<K, V>
+impl<K: Default, V: Default, Q, const N: usize> Index<&Q> for SgMap<K, V, N>
 where
     K: Borrow<Q> + Ord,
     Q: Ord + ?Sized,
@@ -814,26 +929,26 @@ where
     ///
     /// # Panics
     ///
-    /// Panics if the key is not present in the `SGMap`.
+    /// Panics if the key is not present in the `SgMap`.
     fn index(&self, key: &Q) -> &Self::Output {
         &self.bst[key]
     }
 }
 
 // Construct from iterator.
-impl<K, V> FromIterator<(K, V)> for SGMap<K, V>
+impl<K: Default, V: Default, const N: usize> FromIterator<(K, V)> for SgMap<K, V, N>
 where
     K: Ord,
 {
     fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
-        let mut sgm = SGMap::new();
-        sgm.bst = SGTree::from_iter(iter);
+        let mut sgm = SgMap::new();
+        sgm.bst = SgTree::from_iter(iter);
         sgm
     }
 }
 
 // Extension from iterator.
-impl<K, V> Extend<(K, V)> for SGMap<K, V>
+impl<K: Default, V: Default, const N: usize> Extend<(K, V)> for SgMap<K, V, N>
 where
     K: Ord,
 {
@@ -843,7 +958,7 @@ where
 }
 
 // Extension from reference iterator.
-impl<'a, K, V> Extend<(&'a K, &'a V)> for SGMap<K, V>
+impl<'a, K: Default, V: Default, const N: usize> Extend<(&'a K, &'a V)> for SgMap<K, V, N>
 where
     K: Ord + Copy,
     V: Copy,
@@ -856,9 +971,9 @@ where
 // General Iterators ---------------------------------------------------------------------------------------------------
 
 // Reference iterator
-impl<'a, K: Ord, V> IntoIterator for &'a SGMap<K, V> {
+impl<'a, K: Ord + Default, V: Default, const N: usize> IntoIterator for &'a SgMap<K, V, N> {
     type Item = (&'a K, &'a V);
-    type IntoIter = Iter<'a, K, V>;
+    type IntoIter = Iter<'a, K, V, N>;
 
     fn into_iter(self) -> Self::IntoIter {
         self.iter()
@@ -866,99 +981,11 @@ impl<'a, K: Ord, V> IntoIterator for &'a SGMap<K, V> {
 }
 
 // Consuming iterator
-impl<K: Ord, V> IntoIterator for SGMap<K, V> {
+impl<K: Ord + Default, V: Default, const N: usize> IntoIterator for SgMap<K, V, N> {
     type Item = (K, V);
-    type IntoIter = IntoIter<K, V>;
+    type IntoIter = IntoIter<K, V, N>;
 
     fn into_iter(self) -> Self::IntoIter {
-        IntoIter::new(self.bst)
-    }
-}
-
-// Key Iterators -------------------------------------------------------------------------------------------------------
-
-// TODO: these need more trait implementations for full compatibility
-
-/// An iterator over the keys of a `SGMap`.
-///
-/// This `struct` is created by the [`keys`][SGMap::keys] method on [`SGMap`][SGMap].
-/// See its documentation for more.
-pub struct Keys<'a, K: Ord + 'a, V: 'a> {
-    inner: Iter<'a, K, V>,
-}
-
-impl<'a, K: Ord, V> Iterator for Keys<'a, K, V> {
-    type Item = &'a K;
-
-    fn next(&mut self) -> Option<&'a K> {
-        self.inner.next().map(|(k, _)| k)
-    }
-}
-
-/// An owning iterator over the keys of a `SGMap`.
-///
-/// This `struct` is created by the [`into_keys`][SGMap::into_keys] method on [`SGMap`][SGMap].
-/// See its documentation for more.
-pub struct IntoKeys<K: Ord, V> {
-    inner: IntoIter<K, V>,
-}
-
-impl<K: Ord, V> Iterator for IntoKeys<K, V> {
-    type Item = K;
-
-    fn next(&mut self) -> Option<K> {
-        self.inner.next().map(|(k, _)| k)
-    }
-}
-
-// Value Iterators -----------------------------------------------------------------------------------------------------
-
-// TODO: these need more trait implementations for full compatibility
-
-/// An iterator over the values of a `SGMap`.
-///
-/// This `struct` is created by the [`values`][SGMap::values] method on [`SGMap`][SGMap].
-/// See its documentation for more.
-pub struct Values<'a, K: Ord + 'a, V: 'a> {
-    inner: Iter<'a, K, V>,
-}
-
-impl<'a, K: Ord, V> Iterator for Values<'a, K, V> {
-    type Item = &'a V;
-
-    fn next(&mut self) -> Option<&'a V> {
-        self.inner.next().map(|(_, v)| v)
-    }
-}
-
-/// An owning iterator over the values of a `SGMap`.
-///
-/// This `struct` is created by the [`into_values`][SGMap::into_values] method on [`SGMap`][SGMap].
-/// See its documentation for more.
-pub struct IntoValues<K: Ord, V> {
-    inner: IntoIter<K, V>,
-}
-
-impl<K: Ord, V> Iterator for IntoValues<K, V> {
-    type Item = V;
-
-    fn next(&mut self) -> Option<V> {
-        self.inner.next().map(|(_, v)| v)
-    }
-}
-
-/// A mutable iterator over the values of a `SGMap`.
-///
-/// This `struct` is created by the [`values_mut`][SGMap::values_mut] method on [`SGMap`][SGMap].
-/// See its documentation for more.
-pub struct ValuesMut<'a, K: Ord + 'a, V: 'a> {
-    inner: IterMut<'a, K, V>,
-}
-
-impl<'a, K: Ord, V> Iterator for ValuesMut<'a, K, V> {
-    type Item = &'a mut V;
-
-    fn next(&mut self) -> Option<&'a mut V> {
-        self.inner.next().map(|(_, v)| v)
+        IntoIter::new(self)
     }
 }
diff --git a/src/map_types.rs b/src/map_types.rs
new file mode 100644
index 0000000..11742e1
--- /dev/null
+++ b/src/map_types.rs
@@ -0,0 +1,218 @@
+use crate::map::SgMap;
+use crate::tree::{IntoIter as TreeIntoIter, Iter as TreeIter, IterMut as TreeIterMut};
+
+// General Iterators ---------------------------------------------------------------------------------------------------
+
+/// An iterator over the entries of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`iter`][crate::map::SgMap::iter] method on [`SgMap`][crate::map::SgMap].
+/// documentation for more.
+///
+pub struct Iter<'a, T: Ord + Default, V: Default, const N: usize> {
+    ref_iter: TreeIter<'a, T, V, N>,
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iter<'a, K, V, N> {
+    /// Construct reference iterator.
+    pub(crate) fn new(map: &'a SgMap<K, V, N>) -> Self {
+        Iter {
+            ref_iter: TreeIter::new(&map.bst),
+        }
+    }
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iterator for Iter<'a, K, V, N> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.ref_iter.next()
+    }
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for Iter<'a, K, V, N> {
+    fn len(&self) -> usize {
+        self.ref_iter.len()
+    }
+}
+
+/// An owning iterator over the entries of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`into_iter`][crate::map::SgMap::into_iter] method on [`SgMap`][crate::map::SgMap].
+/// documentation for more.
+pub struct IntoIter<K: Ord + Default, V: Default, const N: usize> {
+    cons_iter: TreeIntoIter<K, V, N>,
+}
+
+impl<K: Ord + Default, V: Default, const N: usize> IntoIter<K, V, N> {
+    /// Construct owning iterator.
+    pub(crate) fn new(map: SgMap<K, V, N>) -> Self {
+        IntoIter {
+            cons_iter: TreeIntoIter::new(map.bst),
+        }
+    }
+}
+
+impl<K: Ord + Default, V: Default, const N: usize> Iterator for IntoIter<K, V, N> {
+    type Item = (K, V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.cons_iter.next()
+    }
+}
+
+impl<K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for IntoIter<K, V, N> {
+    fn len(&self) -> usize {
+        self.cons_iter.len()
+    }
+}
+
+/// An mutable iterator over the entries of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`iter_mut`][crate::map::SgMap::iter_mut] method on [`SgMap`][crate::map::SgMap].
+/// documentation for more.
+pub struct IterMut<'a, K: Ord + Default, V: Default, const N: usize> {
+    mut_iter: TreeIterMut<'a, K, V, N>,
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> IterMut<'a, K, V, N> {
+    /// Construct owning iterator.
+    pub(crate) fn new(map: &'a mut SgMap<K, V, N>) -> Self {
+        IterMut {
+            mut_iter: TreeIterMut::new(&mut map.bst),
+        }
+    }
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iterator for IterMut<'a, K, V, N> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.mut_iter.next()
+    }
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for IterMut<'a, K, V, N> {
+    fn len(&self) -> usize {
+        self.mut_iter.len()
+    }
+}
+
+// Key Iterators -------------------------------------------------------------------------------------------------------
+
+// TODO: these need more trait implementations for full compatibility
+
+/// An iterator over the keys of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`keys`][crate::map::SgMap::keys] method on [`SgMap`][crate::map::SgMap].
+/// See its documentation for more.
+pub struct Keys<'a, K: Ord + Default, V: Default, const N: usize> {
+    pub(crate) inner: Iter<'a, K, V, N>,
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iterator for Keys<'a, K, V, N> {
+    type Item = &'a K;
+
+    fn next(&mut self) -> Option<&'a K> {
+        self.inner.next().map(|(k, _)| k)
+    }
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for Keys<'a, K, V, N> {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+/// An owning iterator over the keys of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`into_keys`][crate::map::SgMap::into_keys] method on [`SgMap`][crate::map::SgMap].
+/// See its documentation for more.
+pub struct IntoKeys<K: Ord + Default, V: Default, const N: usize> {
+    pub(crate) inner: IntoIter<K, V, N>,
+}
+
+impl<K: Ord + Default, V: Default, const N: usize> Iterator for IntoKeys<K, V, N> {
+    type Item = K;
+
+    fn next(&mut self) -> Option<K> {
+        self.inner.next().map(|(k, _)| k)
+    }
+}
+
+impl<K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for IntoKeys<K, V, N> {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+// Value Iterators -----------------------------------------------------------------------------------------------------
+
+// TODO: these need more trait implementations for full compatibility
+
+/// An iterator over the values of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`values`][crate::map::SgMap::values] method on [`SgMap`][crate::map::SgMap].
+/// See its documentation for more.
+pub struct Values<'a, K: Ord + Default, V: Default, const N: usize> {
+    pub(crate) inner: Iter<'a, K, V, N>,
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iterator for Values<'a, K, V, N> {
+    type Item = &'a V;
+
+    fn next(&mut self) -> Option<&'a V> {
+        self.inner.next().map(|(_, v)| v)
+    }
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for Values<'a, K, V, N> {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+/// An owning iterator over the values of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`into_values`][crate::map::SgMap::into_values] method on [`SgMap`][crate::map::SgMap].
+/// See its documentation for more.
+pub struct IntoValues<K: Ord + Default, V: Default, const N: usize> {
+    pub(crate) inner: IntoIter<K, V, N>,
+}
+
+impl<K: Ord + Default, V: Default, const N: usize> Iterator for IntoValues<K, V, N> {
+    type Item = V;
+
+    fn next(&mut self) -> Option<V> {
+        self.inner.next().map(|(_, v)| v)
+    }
+}
+
+impl<K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for IntoValues<K, V, N> {
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
+
+/// A mutable iterator over the values of a [`SgMap`][crate::map::SgMap].
+///
+/// This `struct` is created by the [`values_mut`][crate::map::SgMap::values_mut] method on [`SgMap`][crate::map::SgMap].
+/// See its documentation for more.
+pub struct ValuesMut<'a, K: Ord + Default, V: Default, const N: usize> {
+    pub(crate) inner: IterMut<'a, K, V, N>,
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iterator for ValuesMut<'a, K, V, N> {
+    type Item = &'a mut V;
+
+    fn next(&mut self) -> Option<&'a mut V> {
+        self.inner.next().map(|(_, v)| v)
+    }
+}
+
+impl<'a, K: Ord + Default, V: Default, const N: usize> ExactSizeIterator
+    for ValuesMut<'a, K, V, N>
+{
+    fn len(&self) -> usize {
+        self.inner.len()
+    }
+}
diff --git a/src/set.rs b/src/set.rs
index aca0ef6..b43700d 100644
--- a/src/set.rs
+++ b/src/set.rs
@@ -1,33 +1,46 @@
 use core::borrow::Borrow;
-use core::cmp::Ordering;
 use core::fmt::{self, Debug};
 use core::iter::FromIterator;
 use core::ops::{BitAnd, BitOr, BitXor, Sub};
 
-use crate::tree::{
-    ElemRefIter, ElemRefVec, IntoIter as TreeIntoIter, Iter as TreeIter, SGErr, SGTree,
-};
-
-/// Ordered set.
-/// API examples and descriptions are all adapted or directly copied from the standard library's [`BTreeSet`](https://doc.rust-lang.org/std/collections/struct.BTreeSet.html).
-#[allow(clippy::upper_case_acronyms)] // TODO: Removal == breaking change, e.g. v2.0
+use crate::set_types::{Difference, Intersection, IntoIter, Iter, SymmetricDifference, Union};
+use crate::tree::{SgError, SgTree};
+
+/// Safe, fallible, embedded-friendly ordered set.
+///
+/// ### Fallible APIs
+///
+/// * [`try_insert`][crate::set::SgSet::try_insert]
+/// * [`try_append`][crate::set::SgSet::try_append]
+/// * [`try_extend`][crate::set::SgSet::try_extend]
+/// * [`try_from_iter`][crate::set::SgSet::try_from_iter]
+/// * [`try_replace`][crate::set::SgSet::try_replace]
+///
+/// [`TryFrom`](https://doc.rust-lang.org/stable/std/convert/trait.TryFrom.html) isn't implemented because it would collide with the blanket implementation.
+/// See [this open GitHub issue](https://github.com/rust-lang/rust/issues/50133#issuecomment-64690839) from 2018,
+/// this is a known Rust limitation that should be fixed via specialization in the future.
+///
+/// ### Attribution Note
+///
+/// The majority of API examples and descriptions are adapted or directly copied from the standard library's [`BTreeSet`](https://doc.rust-lang.org/std/collections/struct.BTreeSet.html).
+/// The goal is to offer embedded developers familiar, ergonomic APIs on resource constrained systems that otherwise don't get the luxury of dynamic collections.
 #[derive(Default, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
-pub struct SGSet<T: Ord> {
-    bst: SGTree<T, ()>,
+pub struct SgSet<T: Ord + Default, const N: usize> {
+    pub(crate) bst: SgTree<T, (), N>,
 }
 
-impl<T: Ord> SGSet<T> {
-    /// Makes a new, empty `SGSet`.
+impl<T: Ord + Default, const N: usize> SgSet<T, N> {
+    /// Makes a new, empty `SgSet`.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set: SGSet<i32> = SGSet::new();
+    /// let mut set: SgSet<i32, 10> = SgSet::new();
     /// ```
     pub fn new() -> Self {
-        SGSet { bst: SGTree::new() }
+        SgSet { bst: SgTree::new() }
     }
 
     /// The [original scapegoat tree paper's](https://people.csail.mit.edu/rivest/pubs/GR93.pdf) alpha, `a`, can be chosen in the range `0.5 <= a < 1.0`.
@@ -45,26 +58,28 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set: SGSet<isize> = SGSet::new();
+    /// let mut set: SgSet<isize, 10> = SgSet::new();
     ///
     /// // Set 2/3, e.g. `a = 0.666...` (it's default value).
     /// assert!(set.set_rebal_param(2.0, 3.0).is_ok());
     /// ```
-    pub fn set_rebal_param(&mut self, alpha_num: f32, alpha_denom: f32) -> Result<(), SGErr> {
+    #[doc(alias = "rebalance")]
+    #[doc(alias = "alpha")]
+    pub fn set_rebal_param(&mut self, alpha_num: f32, alpha_denom: f32) -> Result<(), SgError> {
         self.bst.set_rebal_param(alpha_num, alpha_denom)
     }
 
     /// Get the current rebalance parameter, alpha, as a tuple of `(alpha_numerator, alpha_denominator)`.
-    /// See [the corresponding setter method][SGSet::set_rebal_param] for more details.
+    /// See [the corresponding setter method][SgSet::set_rebal_param] for more details.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set: SGSet<isize> = SGSet::new();
+    /// let mut set: SgSet<isize, 10> = SgSet::new();
     ///
     /// // Set 2/3, e.g. `a = 0.666...` (it's default value).
     /// assert!(set.set_rebal_param(2.0, 3.0).is_ok());
@@ -72,24 +87,22 @@ impl<T: Ord> SGSet<T> {
     /// // Get the currently set value
     /// assert_eq!(set.rebal_param(), (2.0, 3.0));
     /// ```
+    #[doc(alias = "rebalance")]
+    #[doc(alias = "alpha")]
     pub fn rebal_param(&self) -> (f32, f32) {
         self.bst.rebal_param()
     }
 
-    /// `#![no_std]`: total capacity, e.g. maximum number of set elements.
-    /// Attempting to insert elements beyond capacity will panic, unless the `high_assurance` feature is enabled.
-    ///
-    /// If using `std`: fast capacity, e.g. number of set elements stored on the stack.
-    /// Elements inserted beyond capacity will be stored on the heap.
+    /// Total capacity, e.g. maximum number of set elements.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set: SGSet<i32> = SGSet::new();
+    /// let mut set: SgSet<i32, 10> = SgSet::new();
     ///
-    /// assert!(set.capacity() > 0)
+    /// assert!(set.capacity() == 10)
     /// ```
     pub fn capacity(&self) -> usize {
         self.bst.capacity()
@@ -100,14 +113,14 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut a = SGSet::new();
+    /// let mut a = SgSet::<_, 10>::new();
     /// a.insert(1);
     /// a.insert(2);
     /// a.insert(3);
     ///
-    /// let mut b = SGSet::new();
+    /// let mut b = SgSet::<_, 10>::new();
     /// b.insert(3);
     /// b.insert(4);
     /// b.insert(5);
@@ -123,8 +136,7 @@ impl<T: Ord> SGSet<T> {
     /// assert!(a.contains(&4));
     /// assert!(a.contains(&5));
     /// ```
-    #[cfg(not(feature = "high_assurance"))]
-    pub fn append(&mut self, other: &mut SGSet<T>)
+    pub fn append(&mut self, other: &mut SgSet<T, N>)
     where
         T: Ord,
     {
@@ -136,20 +148,23 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use core::iter::FromIterator;
+    /// use scapegoat::{SgSet, SgError};
     ///
-    /// let mut a = SGSet::new();
-    /// a.insert(1);
-    /// a.insert(2);
-    /// a.insert(3);
+    /// let mut a = SgSet::<_, 10>::new();
+    /// assert!(a.try_insert(1).is_ok());
+    /// assert!(a.try_insert(2).is_ok());
+    /// assert!(a.try_insert(3).is_ok());
     ///
-    /// let mut b = SGSet::new();
-    /// b.insert(3);
-    /// b.insert(4);
-    /// b.insert(5);
+    /// let mut b = SgSet::<_, 10>::new();
+    /// assert!(b.try_insert(3).is_ok()); // Overwrite previous
+    /// assert!(b.try_insert(4).is_ok());
+    /// assert!(b.try_insert(5).is_ok());
     ///
-    /// a.append(&mut b);
+    /// // Successful append
+    /// assert!(a.try_append(&mut b).is_ok());
     ///
+    /// // Elements moved
     /// assert_eq!(a.len(), 5);
     /// assert_eq!(b.len(), 0);
     ///
@@ -158,10 +173,29 @@ impl<T: Ord> SGSet<T> {
     /// assert!(a.contains(&3));
     /// assert!(a.contains(&4));
     /// assert!(a.contains(&5));
+    ///
+    /// // Fill remaining capacity
+    /// let mut key = 6;
+    /// while a.len() < a.capacity() {
+    ///     assert!(a.try_insert(key).is_ok());
+    ///     key += 1;
+    /// }
+    ///
+    /// // Full
+    /// assert!(a.is_full());
+    ///
+    /// // More data
+    /// let mut c = SgSet::<_, 10>::from_iter([11, 12]);
+    /// let mut d = SgSet::<_, 10>::from_iter([1, 2]);
+    ///
+    /// // Cannot append new pairs
+    /// assert_eq!(a.try_append(&mut c), Err(SgError::StackCapacityExceeded));
+    ///
+    /// // Can still replace existing pairs
+    /// assert!(a.try_append(&mut d).is_ok());
     /// ```
-    #[cfg(feature = "high_assurance")]
-    pub fn append(&mut self, other: &mut SGSet<T>) -> Result<(), SGErr> {
-        self.bst.append(&mut other.bst)
+    pub fn try_append(&mut self, other: &mut SgSet<T, N>) -> Result<(), SgError> {
+        self.bst.try_append(&mut other.bst)
     }
 
     /// Adds a value to the set.
@@ -171,15 +205,14 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set = SGSet::new();
+    /// let mut set = SgSet::<_, 10>::new();
     ///
     /// assert_eq!(set.insert(2), true);
     /// assert_eq!(set.insert(2), false);
     /// assert_eq!(set.len(), 1);
     /// ```
-    #[cfg(not(feature = "high_assurance"))]
     pub fn insert(&mut self, value: T) -> bool
     where
         T: Ord,
@@ -188,52 +221,123 @@ impl<T: Ord> SGSet<T> {
     }
 
     /// Adds a value to the set.
-    /// Returns `Err` if sets's stack capacity is full, else the `Ok` contains:
+    /// Returns `Err` if the operation can't be completed, else the `Ok` contains:
     /// * `true` if the set did not have this value present.
     /// * `false` if the set did have this value present (and that old entry is overwritten).
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::{SGSet, SGErr};
+    /// use scapegoat::{SgSet, SgError};
+    ///
+    /// let mut set = SgSet::<_, 10>::new();
     ///
-    /// let mut set = SGSet::new();
+    /// // Add a new element
+    /// assert_eq!(set.try_insert(2), Ok(true));
     ///
-    /// assert_eq!(set.insert(2), Ok(true));
-    /// assert_eq!(set.insert(2), Ok(false));
+    /// // Replace existing element
+    /// assert_eq!(set.try_insert(2), Ok(false));
     /// assert_eq!(set.len(), 1);
     ///
+    /// // Fill remaining capacity
     /// let mut elem = 3;
     /// while set.len() < set.capacity() {
-    ///     set.insert(elem);
+    ///     assert!(set.try_insert(elem).is_ok());
     ///     elem += 1;
     /// }
     ///
-    /// assert_eq!(set.first(), Some(&2));
-    /// assert_eq!(set.last(), Some(&(2 + (set.capacity() - 1))));
-    /// assert_eq!(set.len(), set.capacity());
+    /// // Full
+    /// assert!(set.is_full());
     ///
-    /// assert_eq!(set.insert(elem), Err(SGErr::StackCapacityExceeded));
+    /// // Cannot insert new element
+    /// assert_eq!(set.try_insert(elem), Err(SgError::StackCapacityExceeded));
+    ///
+    /// // Can still replace existing element
+    /// assert_eq!(set.try_insert(elem - 1), Ok(false));
     /// ```
-    #[cfg(feature = "high_assurance")]
-    pub fn insert(&mut self, value: T) -> Result<bool, SGErr>
+    pub fn try_insert(&mut self, value: T) -> Result<bool, SgError>
     where
         T: Ord,
     {
-        match self.bst.insert(value, ()) {
+        match self.bst.try_insert(value, ()) {
             Ok(opt_val) => Ok(opt_val.is_none()),
-            Err(_) => Err(SGErr::StackCapacityExceeded),
+            Err(_) => Err(SgError::StackCapacityExceeded),
         }
     }
 
-    /// Gets an iterator that visits the values in the `SGSet` in ascending order.
+    /// Attempt to extend a collection with the contents of an iterator.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use core::iter::FromIterator;
+    /// use scapegoat::{SgSet, SgError};
+    ///
+    /// let mut a = SgSet::<_, 2>::new();
+    /// let mut b = SgSet::<_, 3>::from_iter([1, 2, 3]);
+    /// let mut c = SgSet::<_, 2>::from_iter([1, 2]);
+    ///
+    /// // Too big
+    /// assert_eq!(a.try_extend(b.into_iter()), Err(SgError::StackCapacityExceeded));
+    ///
+    /// // Fits
+    /// assert!(a.try_extend(c.into_iter()).is_ok());
+    /// ```
+    ///
+    /// ### Note
+    ///
+    /// There is no `TryExtend` trait in `core`/`std`.
+    pub fn try_extend<I: ExactSizeIterator + IntoIterator<Item = T>>(
+        &mut self,
+        iter: I,
+    ) -> Result<(), SgError> {
+        // Derp :P
+        if iter.len() <= (self.capacity() - self.len()) {
+            let map: crate::SgMap<T, (), N> = iter.into_iter().map(|e| (e, ())).collect();
+            self.bst.try_extend(map.into_iter())
+        } else {
+            Err(SgError::StackCapacityExceeded)
+        }
+    }
+
+    /// Attempt conversion from an iterator.
+    /// Will fail if iterator length exceeds `u16::MAX`.
+    ///
+    /// # Examples
     ///
-    /// let set: SGSet<usize> = [1, 2, 3].iter().cloned().collect();
+    /// ```
+    /// use scapegoat::{SgSet, SgError};
+    ///
+    /// const CAPACITY_1: usize = 1_000;
+    /// assert!(SgSet::<_, CAPACITY_1>::try_from_iter((0..CAPACITY_1)).is_ok());
+    ///
+    /// const CAPACITY_2: usize = (u16::MAX as usize) + 1;
+    /// assert_eq!(
+    ///     SgSet::<_, CAPACITY_2>::try_from_iter((0..CAPACITY_2)),
+    ///     Err(SgError::MaximumCapacityExceeded)
+    /// );
+    /// ```
+    ///
+    /// ### Note
+    ///
+    /// There is no `TryFromIterator` trait in `core`/`std`.
+    pub fn try_from_iter<I: ExactSizeIterator + IntoIterator<Item = T>>(
+        iter: I,
+    ) -> Result<Self, SgError> {
+        match iter.len() <= SgTree::<T, (), N>::max_capacity() {
+            true => Ok(SgSet::from_iter(iter)),
+            false => Err(SgError::MaximumCapacityExceeded),
+        }
+    }
+
+    /// Gets an iterator that visits the values in the `SgSet` in ascending order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use scapegoat::SgSet;
+    ///
+    /// let set: SgSet<usize, 3> = [1, 2, 3].iter().cloned().collect();
     /// let mut set_iter = set.iter();
     /// assert_eq!(set_iter.next(), Some(&1));
     /// assert_eq!(set_iter.next(), Some(&2));
@@ -244,16 +348,16 @@ impl<T: Ord> SGSet<T> {
     /// Values returned by the iterator are returned in ascending order:
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let set: SGSet<usize> = [3, 1, 2].iter().cloned().collect();
+    /// let set: SgSet<usize, 3> = [3, 1, 2].iter().cloned().collect();
     /// let mut set_iter = set.iter();
     /// assert_eq!(set_iter.next(), Some(&1));
     /// assert_eq!(set_iter.next(), Some(&2));
     /// assert_eq!(set_iter.next(), Some(&3));
     /// assert_eq!(set_iter.next(), None);
     /// ```
-    pub fn iter(&self) -> Iter<'_, T> {
+    pub fn iter(&self) -> Iter<'_, T, N> {
         Iter::new(self)
     }
 
@@ -267,9 +371,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set = SGSet::new();
+    /// let mut set = SgSet::<_, 10>::new();
     ///
     /// set.insert(2);
     /// assert_eq!(set.remove(&2), true);
@@ -288,12 +392,10 @@ impl<T: Ord> SGSet<T> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut a = SGSet::new();
+    /// let mut a = SgSet::<_, 5>::new();
     /// a.insert(1);
     /// a.insert(2);
     /// a.insert(3);
@@ -312,12 +414,12 @@ impl<T: Ord> SGSet<T> {
     /// assert!(b.contains(&17));
     /// assert!(b.contains(&41));
     /// ```
-    pub fn split_off<Q>(&mut self, value: &Q) -> SGSet<T>
+    pub fn split_off<Q>(&mut self, value: &Q) -> SgSet<T, N>
     where
         T: Borrow<Q> + Ord,
         Q: Ord + ?Sized,
     {
-        SGSet {
+        SgSet {
             bst: self.bst.split_off(value),
         }
     }
@@ -328,9 +430,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set = SGSet::new();
+    /// let mut set = SgSet::<_, 10>::new();
     /// set.insert(Vec::<i32>::new());
     ///
     /// assert_eq!(set.get(&[][..]).unwrap().capacity(), 0);
@@ -342,20 +444,22 @@ impl<T: Ord> SGSet<T> {
         T: Ord,
     {
         let removed = self.bst.remove_entry(&value).map(|(k, _)| k);
-
-        #[cfg(not(feature = "high_assurance"))]
-        {
-            self.insert(value);
-        }
-        #[cfg(feature = "high_assurance")]
-        {
-            assert!(self.insert(value).is_ok());
-        }
-
+        self.insert(value);
         removed
     }
 
-    // TODO v2.0: impl and add fuzz test
+    // TODO: add example
+    /// Attempts to add a value to the set, replacing the existing value, if any, that is equal to the given
+    /// one. Returns the replaced value.
+    pub fn try_replace(&mut self, value: T) -> Result<Option<T>, SgError>
+    where
+        T: Ord,
+    {
+        let removed = self.bst.remove_entry(&value).map(|(k, _)| k);
+        self.try_insert(value)?;
+        Ok(removed)
+    }
+
     /// Removes and returns the value in the set, if any, that is equal to the given one.
     ///
     /// The value may be any borrowed form of the set's value type,
@@ -365,9 +469,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set: SGSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set: SgSet<_, 10> = [1, 2, 3].iter().cloned().collect();
     /// assert_eq!(set.take(&2), Some(2));
     /// assert_eq!(set.take(&2), None);
     /// ```
@@ -387,10 +491,10 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
     /// let xs = [1, 2, 3, 4, 5, 6];
-    /// let mut set: SGSet<i32> = xs.iter().cloned().collect();
+    /// let mut set: SgSet<i32, 10> = xs.iter().cloned().collect();
     /// // Keep only the even numbers.
     /// set.retain(|&k| k % 2 == 0);
     /// assert!(set.iter().eq([2, 4, 6].iter()));
@@ -412,9 +516,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let set: SGSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let set: SgSet<_, 10> = [1, 2, 3].iter().cloned().collect();
     /// assert_eq!(set.get(&2), Some(&2));
     /// assert_eq!(set.get(&4), None);
     /// ```
@@ -431,9 +535,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut v = SGSet::new();
+    /// let mut v = SgSet::<_, 10>::new();
     /// v.insert(1);
     /// v.clear();
     /// assert!(v.is_empty());;
@@ -451,9 +555,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let set: SGSet<_> = [1, 2, 3].iter().cloned().collect();
+    /// let set: SgSet<_, 10> = [1, 2, 3].iter().cloned().collect();
     /// assert_eq!(set.contains(&1), true);
     /// assert_eq!(set.contains(&4), false);
     /// ```
@@ -470,14 +574,14 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut map = SGSet::new();
-    /// assert_eq!(map.first(), None);
-    /// map.insert(1);
-    /// assert_eq!(map.first(), Some(&1));
-    /// map.insert(2);
-    /// assert_eq!(map.first(), Some(&1));
+    /// let mut set = SgSet::<_, 2>::new();
+    /// assert_eq!(set.first(), None);
+    /// set.insert(1);
+    /// assert_eq!(set.first(), Some(&1));
+    /// set.insert(2);
+    /// assert_eq!(set.first(), Some(&1));
     /// ```
     pub fn first(&self) -> Option<&T>
     where
@@ -492,9 +596,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set = SGSet::new();
+    /// let mut set = SgSet::<_, 10>::new();
     ///
     /// set.insert(1);
     /// while let Some(n) = set.pop_first() {
@@ -514,14 +618,14 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut map = SGSet::new();
-    /// assert_eq!(map.first(), None);
-    /// map.insert(1);
-    /// assert_eq!(map.last(), Some(&1));
-    /// map.insert(2);
-    /// assert_eq!(map.last(), Some(&2));
+    /// let mut set = SgSet::<_, 10>::new();
+    /// assert_eq!(set.first(), None);
+    /// set.insert(1);
+    /// assert_eq!(set.last(), Some(&1));
+    /// set.insert(2);
+    /// assert_eq!(set.last(), Some(&2));
     /// ```
     pub fn last(&self) -> Option<&T>
     where
@@ -536,9 +640,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut set = SGSet::new();
+    /// let mut set = SgSet::<_, 10>::new();
     ///
     /// set.insert(1);
     /// while let Some(n) = set.pop_last() {
@@ -558,9 +662,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut v = SGSet::new();
+    /// let mut v = SgSet::<_, 10>::new();
     /// assert_eq!(v.len(), 0);
     /// v.insert(1);
     /// assert_eq!(v.len(), 1);
@@ -574,30 +678,24 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut a = SGSet::new();
+    /// let mut a = SgSet::<_, 10>::new();
     /// a.insert(1);
     /// a.insert(2);
     ///
-    /// let mut b = SGSet::new();
+    /// let mut b = SgSet::<_, 10>::new();
     /// b.insert(2);
     /// b.insert(3);
     ///
     /// let diff: Vec<_> = a.difference(&b).cloned().collect();
     /// assert_eq!(diff, [1]);
     /// ```
-    pub fn difference(&self, other: &SGSet<T>) -> ElemRefIter<T>
+    pub fn difference(&self, other: &SgSet<T, N>) -> Difference<T, N>
     where
         T: Ord,
     {
-        let mut diff = ElemRefVec::new();
-        for val in self {
-            if !other.contains(val) {
-                diff.push(val);
-            }
-        }
-        diff.into_iter()
+        Difference::new(self, other)
     }
 
     /// Returns an iterator over values representing symmetric set difference, e.g., values in `self` or `other` but not both, in ascending order.
@@ -605,38 +703,32 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut a = SGSet::new();
+    /// let mut a = SgSet::<_, 10>::new();
     /// a.insert(1);
     /// a.insert(2);
     ///
-    /// let mut b = SGSet::new();
+    /// let mut b = SgSet::<_, 10>::new();
     /// b.insert(2);
     /// b.insert(3);
     ///
     /// let sym_diff: Vec<_> = a.symmetric_difference(&b).cloned().collect();
     /// assert_eq!(sym_diff, [1, 3]);
     /// ```
-    pub fn symmetric_difference<'a>(&'a self, other: &'a SGSet<T>) -> ElemRefIter<T>
+    ///
+    /// ### Warning
+    ///
+    /// At present, this function may panic if set capacity `N` exceeds `2048`.
+    /// The issue is that this function's returned iterator needs to be `2 * N` long to support disjoint sets,
+    /// but without unstable `feature(generic_const_exprs)` we can't compute `2 * N`.
+    /// So we use `4096` instead of `2 * N` as a workaround, hence `N` should be `<= 2048` to ensure no panic.
+    /// An `N > 2048` may or may not panic, depending on the size of set's intersection.
+    pub fn symmetric_difference<'a>(&'a self, other: &'a SgSet<T, N>) -> SymmetricDifference<T, N>
     where
         T: Ord,
     {
-        let mut sym_diff = ElemRefVec::new();
-        for val in self {
-            if !other.contains(val) {
-                sym_diff.push(val);
-            }
-        }
-
-        for val in other {
-            if !self.contains(val) {
-                sym_diff.push(val);
-            }
-        }
-
-        sym_diff.sort_unstable();
-        sym_diff.into_iter()
+        SymmetricDifference::new(self, other)
     }
 
     /// Returns an iterator over values representing set intersection, e.g., values in both `self` and `other`, in ascending order.
@@ -644,47 +736,24 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut a = SGSet::new();
+    /// let mut a = SgSet::<_, 10>::new();
     /// a.insert(1);
     /// a.insert(2);
     ///
-    /// let mut b = SGSet::new();
+    /// let mut b = SgSet::<_, 10>::new();
     /// b.insert(2);
     /// b.insert(3);
     ///
     /// let intersection: Vec<_> = a.intersection(&b).cloned().collect();
     /// assert_eq!(intersection, [2]);
     /// ```
-    pub fn intersection(&self, other: &SGSet<T>) -> ElemRefIter<T>
+    pub fn intersection(&self, other: &SgSet<T, N>) -> Intersection<T, N>
     where
         T: Ord,
     {
-        let mut self_iter = self.into_iter();
-        let mut other_iter = other.into_iter();
-        let mut opt_self_val = self_iter.next();
-        let mut opt_other_val = other_iter.next();
-        let mut intersect = ElemRefVec::new();
-
-        // Linear time
-        while let (Some(self_val), Some(other_val)) = (opt_self_val, opt_other_val) {
-            match self_val.cmp(other_val) {
-                Ordering::Less => {
-                    opt_self_val = self_iter.next();
-                }
-                Ordering::Equal => {
-                    intersect.push(self_val);
-                    opt_self_val = self_iter.next();
-                    opt_other_val = other_iter.next();
-                }
-                Ordering::Greater => {
-                    opt_other_val = other_iter.next();
-                }
-            }
-        }
-
-        intersect.into_iter()
+        Intersection::new(self, other)
     }
 
     /// Returns an iterator over values representing set union, e.g., values in `self` or `other`, in ascending order.
@@ -692,35 +761,30 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut a = SGSet::new();
+    /// let mut a = SgSet::<_, 10>::new();
     /// a.insert(1);
     ///
-    /// let mut b = SGSet::new();
+    /// let mut b = SgSet::<_, 10>::new();
     /// b.insert(2);
     ///
     /// let union: Vec<_> = a.union(&b).cloned().collect();
     /// assert_eq!(union, [1, 2]);
     /// ```
-    pub fn union<'a>(&'a self, other: &'a SGSet<T>) -> ElemRefIter<T>
+    ///
+    /// ### Warning
+    ///
+    /// At present, this function may panic if set capacity `N` exceeds `2048`.
+    /// The issue is that this function's returned iterator needs to be `2 * N` long to support disjoint sets,
+    /// but without unstable `feature(generic_const_exprs)` we can't compute `2 * N`.
+    /// So we use `4096` instead of `2 * N` as a workaround, hence `N` should be `<= 2048` to ensure no panic.
+    /// An `N > 2048` may or may not panic, depending on the size of set's intersection.
+    pub fn union<'a>(&'a self, other: &'a SgSet<T, N>) -> Union<T, N>
     where
         T: Ord,
     {
-        let mut union = ElemRefVec::new();
-
-        for val in self {
-            union.push(val);
-        }
-
-        for val in other {
-            if !union.contains(&val) {
-                union.push(val);
-            }
-        }
-
-        union.sort_unstable();
-        union.into_iter()
+        Union::new(self, other)
     }
 
     /// Returns `true` if the set contains no elements.
@@ -728,9 +792,9 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let mut v = SGSet::new();
+    /// let mut v = SgSet::<_, 10>::new();
     /// assert!(v.is_empty());
     /// v.insert(1);
     /// assert!(!v.is_empty());
@@ -739,14 +803,31 @@ impl<T: Ord> SGSet<T> {
         self.bst.is_empty()
     }
 
+    /// Returns `true` if the set's capacity is filled.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use scapegoat::SgSet;
+    ///
+    /// let mut a = SgSet::<_, 2>::new();
+    /// a.insert(1);
+    /// assert!(!a.is_full());
+    /// a.insert(2);
+    /// assert!(a.is_full());
+    /// ```
+    pub fn is_full(&self) -> bool {
+        self.bst.is_full()
+    }
+
     /// Returns `true` if `self` has no elements in common with other (empty intersection).
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
-    /// let a: SGSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let mut b = SGSet::new();
+    /// use scapegoat::SgSet;
+    /// let a: SgSet<_, 10> = [1, 2, 3].iter().cloned().collect();
+    /// let mut b = SgSet::new();
     ///
     /// assert_eq!(a.is_disjoint(&b), true);
     /// b.insert(4);
@@ -754,7 +835,7 @@ impl<T: Ord> SGSet<T> {
     /// b.insert(1);
     /// assert_eq!(a.is_disjoint(&b), false);
     /// ```
-    pub fn is_disjoint(&self, other: &SGSet<T>) -> bool
+    pub fn is_disjoint(&self, other: &SgSet<T, N>) -> bool
     where
         T: Ord,
     {
@@ -766,10 +847,10 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let sup: SGSet<_> = [1, 2, 3].iter().cloned().collect();
-    /// let mut set = SGSet::new();
+    /// let sup: SgSet<_, 10> = [1, 2, 3].iter().cloned().collect();
+    /// let mut set = SgSet::new();
     ///
     /// assert_eq!(set.is_subset(&sup), true);
     /// set.insert(2);
@@ -777,7 +858,7 @@ impl<T: Ord> SGSet<T> {
     /// set.insert(4);
     /// assert_eq!(set.is_subset(&sup), false);
     /// ```
-    pub fn is_subset(&self, other: &SGSet<T>) -> bool
+    pub fn is_subset(&self, other: &SgSet<T, N>) -> bool
     where
         T: Ord,
     {
@@ -789,10 +870,10 @@ impl<T: Ord> SGSet<T> {
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let sub: SGSet<_> = [1, 2].iter().cloned().collect();
-    /// let mut set = SGSet::new();
+    /// let sub: SgSet<_, 3> = [1, 2].iter().cloned().collect();
+    /// let mut set = SgSet::new();
     ///
     /// assert_eq!(set.is_superset(&sub), false);
     ///
@@ -803,7 +884,7 @@ impl<T: Ord> SGSet<T> {
     /// set.insert(2);
     /// assert_eq!(set.is_superset(&sub), true);
     /// ```
-    pub fn is_superset(&self, other: &SGSet<T>) -> bool
+    pub fn is_superset(&self, other: &SgSet<T, N>) -> bool
     where
         T: Ord,
     {
@@ -814,9 +895,9 @@ impl<T: Ord> SGSet<T> {
 // Convenience Traits --------------------------------------------------------------------------------------------------
 
 // Debug
-impl<T> Debug for SGSet<T>
+impl<T, const N: usize> Debug for SgSet<T, N>
 where
-    T: Ord + Debug,
+    T: Ord + Default + Debug,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_set()
@@ -826,38 +907,47 @@ where
 }
 
 // From array.
-impl<T, const N: usize> From<[T; N]> for SGSet<T>
+impl<T, const N: usize> From<[T; N]> for SgSet<T, N>
 where
-    T: Ord,
+    T: Ord + Default,
 {
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let set1 = SGSet::from([1, 2, 3, 4]);
-    /// let set2: SGSet<_> = [1, 2, 3, 4].into();
+    /// let set1 = SgSet::from([1, 2, 3, 4]);
+    /// let set2: SgSet<_, 4> = [1, 2, 3, 4].into();
     /// assert_eq!(set1, set2);
     /// ```
+    ///
+    /// ### Warning
+    ///
+    /// [`TryFrom`](https://doc.rust-lang.org/stable/std/convert/trait.TryFrom.html) isn't implemented because it would collide with the blanket implementation.
+    /// See [this open GitHub issue](https://github.com/rust-lang/rust/issues/50133#issuecomment-64690839) from 2018,
+    /// this is a known Rust limitation that should be fixed via specialization in the future.
+    #[doc(alias = "tryfrom")]
+    #[doc(alias = "try_from")]
+    #[doc(alias = "TryFrom")]
     fn from(arr: [T; N]) -> Self {
-        core::array::IntoIter::new(arr).collect()
+        IntoIterator::into_iter(arr).collect()
     }
 }
 
 // Construct from iterator.
-impl<T> FromIterator<T> for SGSet<T>
+impl<T, const N: usize> FromIterator<T> for SgSet<T, N>
 where
-    T: Ord,
+    T: Ord + Default,
 {
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
-        let mut sgs = SGSet::new();
-        sgs.bst = SGTree::from_iter(iter.into_iter().map(|e| (e, ())));
+        let mut sgs = SgSet::new();
+        sgs.bst = SgTree::from_iter(iter.into_iter().map(|e| (e, ())));
         sgs
     }
 }
 
 // Extension from iterator.
-impl<T> Extend<T> for SGSet<T>
+impl<T, const N: usize> Extend<T> for SgSet<T, N>
 where
-    T: Ord,
+    T: Ord + Default,
 {
     fn extend<TreeIter: IntoIterator<Item = T>>(&mut self, iter: TreeIter) {
         self.bst.extend(iter.into_iter().map(|e| (e, ())));
@@ -865,165 +955,123 @@ where
 }
 
 // Extension from reference iterator.
-impl<'a, T> Extend<&'a T> for SGSet<T>
+impl<'a, T, const N: usize> Extend<&'a T> for SgSet<T, N>
 where
-    T: 'a + Ord + Copy,
+    T: 'a + Ord + Default + Copy,
 {
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
         self.extend(iter.into_iter().cloned());
     }
 }
 
-// Iterators -----------------------------------------------------------------------------------------------------------
+// General Iterators ---------------------------------------------------------------------------------------------------
 
 // Reference iterator
-impl<'a, T: Ord> IntoIterator for &'a SGSet<T> {
+impl<'a, T: Ord + Default, const N: usize> IntoIterator for &'a SgSet<T, N> {
     type Item = &'a T;
-    type IntoIter = Iter<'a, T>;
+    type IntoIter = Iter<'a, T, N>;
 
     fn into_iter(self) -> Self::IntoIter {
         self.iter()
     }
 }
 
-/// Reference iterator wrapper
-pub struct Iter<'a, T: Ord> {
-    ref_iter: TreeIter<'a, T, ()>,
-}
-
-impl<'a, T: Ord> Iter<'a, T> {
-    pub fn new(set: &'a SGSet<T>) -> Self {
-        Iter {
-            ref_iter: TreeIter::new(&set.bst),
-        }
-    }
-}
-
-impl<'a, T: Ord> Iterator for Iter<'a, T> {
-    type Item = &'a T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.ref_iter.next().map(|(k, _)| k)
-    }
-}
-
 // Consuming iterator
-impl<T: Ord> IntoIterator for SGSet<T> {
+impl<T: Ord + Default, const N: usize> IntoIterator for SgSet<T, N> {
     type Item = T;
-    type IntoIter = IntoIter<T>;
+    type IntoIter = IntoIter<T, N>;
 
     fn into_iter(self) -> Self::IntoIter {
         IntoIter::new(self)
     }
 }
 
-/// Consuming iterator wrapper
-pub struct IntoIter<T: Ord> {
-    cons_iter: TreeIntoIter<T, ()>,
-}
-
-impl<T: Ord> IntoIter<T> {
-    pub fn new(set: SGSet<T>) -> Self {
-        IntoIter {
-            cons_iter: TreeIntoIter::new(set.bst),
-        }
-    }
-}
-
-impl<T: Ord> Iterator for IntoIter<T> {
-    type Item = T;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        self.cons_iter.next().map(|(k, _)| k)
-    }
-}
-
 // Operator Overloading ------------------------------------------------------------------------------------------------
 
-impl<T: Ord + Clone> Sub<&SGSet<T>> for &SGSet<T> {
-    type Output = SGSet<T>;
+impl<T: Ord + Default + Clone, const N: usize> Sub<&SgSet<T, N>> for &SgSet<T, N> {
+    type Output = SgSet<T, N>;
 
-    /// Returns the difference of `self` and `rhs` as a new `SGSet<T>`.
+    /// Returns the difference of `self` and `rhs` as a new `SgSet<T, N>`.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let a: SGSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: SGSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a: SgSet<_, 10> = vec![1, 2, 3].into_iter().collect();
+    /// let b: SgSet<_, 10> = vec![3, 4, 5].into_iter().collect();
     ///
     /// let result = &a - &b;
     /// let result_vec: Vec<_> = result.into_iter().collect();
     /// assert_eq!(result_vec, [1, 2]);
     /// ```
-    fn sub(self, rhs: &SGSet<T>) -> SGSet<T> {
+    fn sub(self, rhs: &SgSet<T, N>) -> SgSet<T, N> {
         self.difference(rhs).cloned().collect()
     }
 }
 
-impl<T: Ord + Clone> BitAnd<&SGSet<T>> for &SGSet<T> {
-    type Output = SGSet<T>;
+impl<T: Ord + Default + Clone, const N: usize> BitAnd<&SgSet<T, N>> for &SgSet<T, N> {
+    type Output = SgSet<T, N>;
 
-    /// Returns the intersection of `self` and `rhs` as a new `SGSet<T>`.
+    /// Returns the intersection of `self` and `rhs` as a new `SgSet<T, N>`.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let a: SGSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: SGSet<_> = vec![2, 3, 4].into_iter().collect();
+    /// let a: SgSet<_, 10> = vec![1, 2, 3].into_iter().collect();
+    /// let b: SgSet<_, 10> = vec![2, 3, 4].into_iter().collect();
     ///
     /// let result = &a & &b;
     /// let result_vec: Vec<_> = result.into_iter().collect();
     /// assert_eq!(result_vec, [2, 3]);
     /// ```
-    fn bitand(self, rhs: &SGSet<T>) -> SGSet<T> {
+    fn bitand(self, rhs: &SgSet<T, N>) -> SgSet<T, N> {
         self.intersection(rhs).cloned().collect()
     }
 }
 
-impl<T: Ord + Clone> BitOr<&SGSet<T>> for &SGSet<T> {
-    type Output = SGSet<T>;
+impl<T: Ord + Default + Clone, const N: usize> BitOr<&SgSet<T, N>> for &SgSet<T, N> {
+    type Output = SgSet<T, N>;
 
-    /// Returns the union of `self` and `rhs` as a new `SGSet<T>`.
+    /// Returns the union of `self` and `rhs` as a new `SgSet<T, N>`.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let a: SGSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: SGSet<_> = vec![3, 4, 5].into_iter().collect();
+    /// let a: SgSet<_, 10> = vec![1, 2, 3].into_iter().collect();
+    /// let b: SgSet<_, 10> = vec![3, 4, 5].into_iter().collect();
     ///
     /// let result = &a | &b;
     /// let result_vec: Vec<_> = result.into_iter().collect();
     /// assert_eq!(result_vec, [1, 2, 3, 4, 5]);
     /// ```
-    fn bitor(self, rhs: &SGSet<T>) -> SGSet<T> {
+    fn bitor(self, rhs: &SgSet<T, N>) -> SgSet<T, N> {
         self.union(rhs).cloned().collect()
     }
 }
 
-impl<T: Ord + Clone> BitXor<&SGSet<T>> for &SGSet<T> {
-    type Output = SGSet<T>;
+impl<T: Ord + Default + Clone, const N: usize> BitXor<&SgSet<T, N>> for &SgSet<T, N> {
+    type Output = SgSet<T, N>;
 
-    /// Returns the symmetric difference of `self` and `rhs` as a new `SGSet<T>`.
+    /// Returns the symmetric difference of `self` and `rhs` as a new `SgSet<T, N>`.
     ///
     /// # Examples
     ///
     /// ```
-    /// use scapegoat::SGSet;
+    /// use scapegoat::SgSet;
     ///
-    /// let a: SGSet<_> = vec![1, 2, 3].into_iter().collect();
-    /// let b: SGSet<_> = vec![2, 3, 4].into_iter().collect();
+    /// let a: SgSet<_, 10> = vec![1, 2, 3].into_iter().collect();
+    /// let b: SgSet<_, 10> = vec![2, 3, 4].into_iter().collect();
     ///
     /// let result = &a ^ &b;
     /// let result_vec: Vec<_> = result.into_iter().collect();
     /// assert_eq!(result_vec, [1, 4]);
     /// ```
-    fn bitxor(self, rhs: &SGSet<T>) -> SGSet<T> {
+    fn bitxor(self, rhs: &SgSet<T, N>) -> SgSet<T, N> {
         self.symmetric_difference(rhs).cloned().collect()
     }
 }
diff --git a/src/set_types.rs b/src/set_types.rs
new file mode 100644
index 0000000..76704a8
--- /dev/null
+++ b/src/set_types.rs
@@ -0,0 +1,400 @@
+use core::cmp::Ordering;
+
+use crate::set::SgSet;
+use crate::tree::{Idx, IntoIter as TreeIntoIter, Iter as TreeIter};
+
+use smallnum::SmallUnsigned;
+use tinyvec::{ArrayVec, ArrayVecIterator};
+
+// General Iterators ---------------------------------------------------------------------------------------------------
+
+/// An iterator over the items of a [`SgSet`][crate::set::SgSet].
+///
+/// This `struct` is created by the [`iter`][crate::set::SgSet::iter] method on [`SgSet`][crate::set::SgSet].
+/// See its documentation for more.
+pub struct Iter<'a, T: Ord + Default, const N: usize> {
+    ref_iter: TreeIter<'a, T, (), N>,
+}
+
+impl<'a, T: Ord + Default, const N: usize> Iter<'a, T, N> {
+    /// Construct reference iterator.
+    pub(crate) fn new(set: &'a SgSet<T, N>) -> Self {
+        Iter {
+            ref_iter: TreeIter::new(&set.bst),
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> Iterator for Iter<'a, T, N> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.ref_iter.next().map(|(k, _)| k)
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> ExactSizeIterator for Iter<'a, T, N> {
+    fn len(&self) -> usize {
+        self.ref_iter.len()
+    }
+}
+
+/// An owning iterator over the items of a [`SgSet`][crate::set::SgSet].
+///
+/// This `struct` is created by the [`into_iter`][crate::set::SgSet::into_iter] method on [`SgSet`][crate::set::SgSet]
+/// (provided by the IntoIterator trait). See its documentation for more.
+pub struct IntoIter<T: Ord + Default, const N: usize> {
+    cons_iter: TreeIntoIter<T, (), N>,
+}
+
+impl<T: Ord + Default, const N: usize> IntoIter<T, N> {
+    /// Construct owning iterator.
+    pub(crate) fn new(set: SgSet<T, N>) -> Self {
+        IntoIter {
+            cons_iter: TreeIntoIter::new(set.bst),
+        }
+    }
+}
+
+impl<T: Ord + Default, const N: usize> Iterator for IntoIter<T, N> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.cons_iter.next().map(|(k, _)| k)
+    }
+}
+
+impl<T: Ord + Default, const N: usize> ExactSizeIterator for IntoIter<T, N> {
+    fn len(&self) -> usize {
+        self.cons_iter.len()
+    }
+}
+
+/*
+Workaround Note:
+
+The remaining iterators in this file only store indexes into the input set(s) iterator(s) and have to
+recover set elements with `set.iter().nth(idx)`. Rather inefficient, solves a blocking problem:
+in `ArrayVecIterator<[&'a T; N]>` `Default` is not implemented for `&'a T`.
+
+TODO: faster solution?
+*/
+
+// TODO: without `feature(generic_const_exprs)`, `Union` and `SymmetricDifference` cannot compute `2 * N` length
+// iterator to support disjoint sets. This is a temporary workaround, documented in external API docs.
+const PLACEHOLDER_2N: usize = 4096;
+
+// Intersection Iterator -----------------------------------------------------------------------------------------------
+
+// TODO: these need more trait implementations for full compatibility
+// TODO: make this a lazy iterator like `std::collections::btree_set::Intersection`
+
+/// An iterator producing elements in the intersection of [`SgSet`][crate::set::SgSet]s.
+///
+/// This `struct` is created by the [`intersection`][crate::set::SgSet::difference] method on [`SgSet`][crate::set::SgSet].
+/// See its documentation for more.
+pub struct Intersection<'a, T: Ord + Default, const N: usize> {
+    pub(crate) inner: ArrayVecIterator<[Idx; N]>,
+    set_this: &'a SgSet<T, N>,
+    total_cnt: usize,
+    spent_cnt: usize,
+}
+
+impl<'a, T: Ord + Default, const N: usize> Intersection<'a, T, N> {
+    /// Construct `Intersection` iterator.
+    /// Values that are both in `this` and `other`.
+    pub(crate) fn new(this: &'a SgSet<T, N>, other: &SgSet<T, N>) -> Self {
+        let mut self_enum_iter = this.iter().enumerate();
+        let mut other_enum_iter = other.iter().enumerate();
+
+        let mut opt_self = self_enum_iter.next();
+        let mut opt_other = other_enum_iter.next();
+
+        let mut inter = ArrayVec::default();
+        let mut len = 0;
+
+        // If either is shorter, short-circuit.
+        while let (Some((self_idx, self_val)), Some((_, other_val))) = (opt_self, opt_other) {
+            match self_val.cmp(other_val) {
+                Ordering::Less => {
+                    opt_self = self_enum_iter.next();
+                }
+                Ordering::Equal => {
+                    inter.push(Idx::checked_from(self_idx));
+                    len += 1;
+                    opt_self = self_enum_iter.next();
+                    opt_other = other_enum_iter.next();
+                }
+                Ordering::Greater => {
+                    opt_other = other_enum_iter.next();
+                }
+            }
+        }
+
+        Intersection {
+            inner: inter.into_iter(),
+            set_this: this,
+            total_cnt: len,
+            spent_cnt: 0,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> Iterator for Intersection<'a, T, N> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<&'a T> {
+        match self.inner.next() {
+            Some(idx) => match self.set_this.iter().nth(idx.usize()) {
+                Some(item) => {
+                    self.spent_cnt += 1;
+                    Some(item)
+                }
+                None => None,
+            },
+            None => None,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> ExactSizeIterator for Intersection<'a, T, N> {
+    fn len(&self) -> usize {
+        debug_assert!(self.spent_cnt <= self.total_cnt);
+        self.total_cnt - self.spent_cnt
+    }
+}
+
+// Difference Iterator -------------------------------------------------------------------------------------------------
+
+// TODO: these need more trait implementations for full compatibility
+// TODO: make this a lazy iterator like `std::collections::btree_set::Difference`
+
+/// An iterator producing elements in the difference of [`SgSet`][crate::set::SgSet]s.
+///
+/// This `struct` is created by the [`difference`][crate::set::SgSet::difference] method
+/// on [`SgSet`][crate::set::SgSet]. See its documentation for more.
+pub struct Difference<'a, T: Ord + Default, const N: usize> {
+    pub(crate) inner: ArrayVecIterator<[Idx; N]>,
+    set_this: &'a SgSet<T, N>,
+    total_cnt: usize,
+    spent_cnt: usize,
+}
+
+impl<'a, T: Ord + Default, const N: usize> Difference<'a, T, N> {
+    /// Construct `Difference` iterator.
+    /// Values that are in `this` but not in `other`.
+    pub(crate) fn new(this: &'a SgSet<T, N>, other: &SgSet<T, N>) -> Self {
+        let mut diff = ArrayVec::default();
+        let mut len = 0;
+
+        for (idx, val) in this.iter().enumerate() {
+            if !other.contains(val) {
+                diff.push(Idx::checked_from(idx));
+                len += 1;
+            }
+        }
+
+        Difference {
+            inner: diff.into_iter(),
+            set_this: this,
+            total_cnt: len,
+            spent_cnt: 0,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> Iterator for Difference<'a, T, N> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<&'a T> {
+        match self.inner.next() {
+            Some(idx) => match self.set_this.iter().nth(idx.usize()) {
+                Some(item) => {
+                    self.spent_cnt += 1;
+                    Some(item)
+                }
+                None => None,
+            },
+            None => None,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> ExactSizeIterator for Difference<'a, T, N> {
+    fn len(&self) -> usize {
+        debug_assert!(self.spent_cnt <= self.total_cnt);
+        self.total_cnt - self.spent_cnt
+    }
+}
+
+// Symmetric Difference Iterator ---------------------------------------------------------------------------------------
+
+// TODO: these need more trait implementations for full compatibility
+// TODO: make this a lazy iterator like `std::collections::btree_set::Difference`
+
+/// An iterator producing elements in the symmetric difference of [`SgSet`][crate::set::SgSet]s.
+///
+/// This `struct` is created by the [`symmetric_difference`][crate::set::SgSet::symmetric_difference]
+/// method on [`SgSet`][crate::set::SgSet]. See its documentation for more.
+pub struct SymmetricDifference<'a, T: Ord + Default, const N: usize> {
+    pub(crate) inner: ArrayVecIterator<[(Idx, bool); PLACEHOLDER_2N]>, // TODO: placeholder
+    set_this: &'a SgSet<T, N>,
+    set_other: &'a SgSet<T, N>,
+    total_cnt: usize,
+    spent_cnt: usize,
+}
+
+impl<'a, T: Ord + Default, const N: usize> SymmetricDifference<'a, T, N> {
+    /// Construct `SymmetricDifference` iterator.
+    /// Values that are in `this` or in `other` but not in both.
+    pub(crate) fn new(this: &'a SgSet<T, N>, other: &'a SgSet<T, N>) -> Self {
+        let mut sym_diff = ArrayVec::default();
+        let mut len = 0;
+
+        for (idx, val) in this.iter().enumerate() {
+            if !other.contains(val) {
+                sym_diff.push((Idx::checked_from(idx), true));
+                len += 1;
+            }
+        }
+
+        for (idx, val) in other.iter().enumerate() {
+            if !this.contains(val) {
+                sym_diff.push((Idx::checked_from(idx), false));
+                len += 1;
+            }
+        }
+
+        // Ascending order
+        sym_diff.sort_unstable_by_key(|(idx, in_this): &(Idx, bool)| match in_this {
+            true => this.iter().nth(idx.usize()),
+            false => other.iter().nth(idx.usize()),
+        });
+
+        SymmetricDifference {
+            inner: sym_diff.into_iter(),
+            set_this: this,
+            set_other: other,
+            total_cnt: len,
+            spent_cnt: 0,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> Iterator for SymmetricDifference<'a, T, N> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<&'a T> {
+        match self.inner.next() {
+            Some((idx, in_this)) => match in_this {
+                true => match self.set_this.iter().nth(idx.usize()) {
+                    Some(item) => {
+                        self.spent_cnt += 1;
+                        Some(item)
+                    }
+                    None => None,
+                },
+                false => match self.set_other.iter().nth(idx.usize()) {
+                    Some(item) => {
+                        self.spent_cnt += 1;
+                        Some(item)
+                    }
+                    None => None,
+                },
+            },
+            None => None,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> ExactSizeIterator for SymmetricDifference<'a, T, N> {
+    fn len(&self) -> usize {
+        debug_assert!(self.spent_cnt <= self.total_cnt);
+        self.total_cnt - self.spent_cnt
+    }
+}
+
+// Union Iterator ------------------------------------------------------------------------------------------------------
+
+// TODO: these need more trait implementations for full compatibility
+// TODO: make this a lazy iterator like `std::collections::btree_set::Union`
+
+/// An iterator producing elements in the union of [`SgSet`][crate::set::SgSet]s.
+///
+/// This `struct` is created by the [`union`][crate::set::SgSet::difference] method on [`SgSet`][crate::set::SgSet].
+/// See its documentation for more.
+pub struct Union<'a, T: Ord + Default, const N: usize> {
+    pub(crate) inner: ArrayVecIterator<[(Idx, bool); PLACEHOLDER_2N]>,
+    set_this: &'a SgSet<T, N>,
+    set_other: &'a SgSet<T, N>,
+    total_cnt: usize,
+    spent_cnt: usize,
+}
+
+impl<'a, T: Ord + Default, const N: usize> Union<'a, T, N> {
+    /// Construct `Union` iterator.
+    /// Values in `this` or `other`, without duplicates.
+    pub(crate) fn new(this: &'a SgSet<T, N>, other: &'a SgSet<T, N>) -> Self {
+        let mut uni = ArrayVec::default();
+        let mut len = 0;
+
+        for (idx, _) in this.iter().enumerate() {
+            uni.push((Idx::checked_from(idx), true));
+            len += 1;
+        }
+
+        for (idx, val) in other.iter().enumerate() {
+            if !this.contains(val) {
+                uni.push((Idx::checked_from(idx), false));
+                len += 1;
+            }
+        }
+
+        // Ascending order
+        uni.sort_unstable_by_key(|(idx, in_this): &(Idx, bool)| match in_this {
+            true => this.iter().nth(idx.usize()),
+            false => other.iter().nth(idx.usize()),
+        });
+
+        Union {
+            inner: uni.into_iter(),
+            set_this: this,
+            set_other: other,
+            total_cnt: len,
+            spent_cnt: 0,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> Iterator for Union<'a, T, N> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<&'a T> {
+        match self.inner.next() {
+            Some((idx, in_this)) => match in_this {
+                true => match self.set_this.iter().nth(idx.usize()) {
+                    Some(item) => {
+                        self.spent_cnt += 1;
+                        Some(item)
+                    }
+                    None => None,
+                },
+                false => match self.set_other.iter().nth(idx.usize()) {
+                    Some(item) => {
+                        self.spent_cnt += 1;
+                        Some(item)
+                    }
+                    None => None,
+                },
+            },
+            None => None,
+        }
+    }
+}
+
+impl<'a, T: Ord + Default, const N: usize> ExactSizeIterator for Union<'a, T, N> {
+    fn len(&self) -> usize {
+        debug_assert!(self.spent_cnt <= self.total_cnt);
+        self.total_cnt - self.spent_cnt
+    }
+}
diff --git a/src/tree/arena.rs b/src/tree/arena.rs
index 25eea66..e948f01 100644
--- a/src/tree/arena.rs
+++ b/src/tree/arena.rs
@@ -1,60 +1,78 @@
+use core::ops::{Index, IndexMut};
 use core::slice::{Iter, IterMut};
 
-use super::node::{Node, NodeSwapHistHelper};
+use super::node::{Node, NodeGetHelper, NodeSwapHistHelper};
+use super::node_dispatch::SmallNode;
 
-#[cfg(not(feature = "low_mem_insert"))]
-use super::types::{ArenaVec, Idx, IdxVec, SortMetaVec};
-
-#[cfg(feature = "low_mem_insert")]
-use super::types::{ArenaVec, Idx, SortMetaVec};
+use smallnum::SmallUnsigned;
+use tinyvec::ArrayVec;
 
-use crate::MAX_ELEMS;
+/*
+Note:
 
-use smallnum::SmallUnsigned;
+Structures in this file generic for `U` in a *subset* of the set `(u8, u16, u32, u64, u128)`.
+All members in subset are <= host pointer width in size.
+If caller obeys contract, `U` will be smallest unsigned capable of representing const `N` (e.g. static capacity).
+*/
 
-/// A simple arena allocator.
-#[derive(Clone)]
-pub struct NodeArena<K, V> {
-    arena: ArenaVec<K, V>,
+/// An arena allocator, meta programmable for low memory footprint.
+#[derive(Clone, Debug)]
+pub struct Arena<K: Default, V: Default, U: Default, const N: usize> {
+    vec: ArrayVec<[Option<Node<K, V, U>>; N]>,
 
     #[cfg(not(feature = "low_mem_insert"))]
-    free_list: IdxVec,
+    free_list: ArrayVec<[U; N]>,
 }
 
-impl<K, V> NodeArena<K, V> {
-    // Public API ------------------------------------------------------------------------------------------------------
+impl<
+        K: Default,
+        V: Default,
+        U: Default + Copy + SmallUnsigned + Ord + PartialEq + PartialOrd,
+        const N: usize,
+    > Arena<K, V, U, N>
+{
+    // TODO: is this function necessary?
+    /// Const associated constructor for index scratch vector.
+    pub fn new_idx_vec() -> ArrayVec<[U; N]> {
+        ArrayVec::<[U; N]>::default()
+    }
 
     /// Constructor.
     pub fn new() -> Self {
-        NodeArena {
-            arena: ArenaVec::new(),
+        let a = Arena {
+            vec: ArrayVec::<[Option<Node<K, V, U>>; N]>::new(),
 
             #[cfg(not(feature = "low_mem_insert"))]
-            free_list: IdxVec::new(),
-        }
-    }
+            free_list: ArrayVec::<[U; N]>::new(),
+        };
 
-    /// `#![no_std]`: total capacity, e.g. maximum number of items.
-    /// Attempting to insert items beyond capacity will panic.
-    ///
-    /// If using `std`: fast capacity, e.g. number of map items stored on the stack.
-    /// Items inserted beyond capacity will be stored on the heap.
-    pub fn capacity(&self) -> usize {
-        MAX_ELEMS
-    }
+        #[cfg(not(feature = "low_mem_insert"))]
+        debug_assert_eq!(0, a.free_list.len());
+        debug_assert_eq!(0, a.vec.len());
+
+        #[cfg(not(feature = "low_mem_insert"))]
+        debug_assert_eq!(N, a.free_list.capacity());
+        debug_assert_eq!(N, a.vec.capacity());
 
+        a
+    }
     /// Returns an iterator over immutable arena elements.
-    pub fn iter(&self) -> Iter<'_, Option<Node<K, V>>> {
-        self.arena.iter()
+    pub fn iter(&self) -> Iter<'_, Option<Node<K, V, U>>> {
+        self.vec.iter()
     }
 
     /// Returns an iterator over arena elements that allows modifying each value.
-    pub fn iter_mut(&mut self) -> IterMut<'_, Option<Node<K, V>>> {
-        self.arena.iter_mut()
+    pub fn iter_mut(&mut self) -> IterMut<'_, Option<Node<K, V, U>>> {
+        self.vec.iter_mut()
+    }
+
+    /// Total capacity, e.g. maximum number of items.
+    pub fn capacity(&self) -> usize {
+        N
     }
 
     /// Add node to area, growing if necessary, and return addition index.
-    pub fn add(&mut self, node: Node<K, V>) -> Idx {
+    pub fn add(&mut self, key: K, val: V) -> usize {
         // O(1) find, constant time
         #[cfg(not(feature = "low_mem_insert"))]
         let opt_free_idx = self.free_list.pop();
@@ -62,92 +80,102 @@ impl<K, V> NodeArena<K, V> {
         // O(n) find, linear search
         #[cfg(feature = "low_mem_insert")]
         let opt_free_idx = self
-            .arena
+            .vec
             .iter()
             .position(|x| x.is_none())
-            .map(|i| i as Idx);
+            .map(|i| U::checked_from(i));
 
+        let node = Node::new(key, val);
         match opt_free_idx {
             Some(free_idx) => {
                 debug_assert!(
-                    self.arena[free_idx.usize()].is_none(),
+                    self.vec[free_idx.usize()].is_none(),
                     "Internal invariant failed: overwrite of allocated node!"
                 );
-                self.arena[free_idx.usize()] = Some(node);
-                free_idx
+                self.vec[free_idx.usize()] = Some(node);
+                free_idx.usize()
             }
             None => {
-                self.arena.push(Some(node));
-                (self.arena.len() - 1) as Idx
+                self.vec.push(Some(node));
+                self.vec.len() - 1
             }
         }
     }
 
     /// Remove node at a given index from area, return it.
-    pub fn remove(&mut self, idx: Idx) -> Option<Node<K, V>> {
+    pub fn remove(&mut self, idx: usize) -> Option<Node<K, V, U>> {
         debug_assert!(
-            idx < self.arena.len() as Idx,
+            idx < self.vec.len(),
             "API misuse: requested removal past last index!"
         );
-        if idx < self.arena.len() as Idx {
-            // Move node to back, replacing with None, preserving order
-            self.arena.push(None);
-            let len = self.arena.len();
-            self.arena.swap(idx.usize(), len - 1);
+
+        if self.is_occupied(idx) {
+            // Extract node
+            let node = core::mem::replace(&mut self.vec[idx], None);
 
             // Append removed index to free list
             #[cfg(not(feature = "low_mem_insert"))]
-            self.free_list.push(idx);
-
-            // Retrieve node
-            return match self.arena.pop() {
-                Some(opt_node) => match opt_node {
-                    Some(node) => Some(node),
-                    None => {
-                        debug_assert!(
-                            false,
-                            "Internal invariant failed: removal popped an empty node!"
-                        );
-                        None
-                    }
-                },
-                None => None,
-            };
+            self.free_list.push(U::checked_from(idx));
+
+            return node;
         }
 
         None
     }
 
+    /// Remove node at a known-good index (simpler callsite and error handling) from area.
+    /// This function can panic. If the index might be invalid, use `remove` instead.
+    pub fn hard_remove(&mut self, idx: usize) -> Node<K, V, U> {
+        match self.remove(idx) {
+            Some(node) => node,
+            None => {
+                panic!("Internal invariant failed: attempted removal of node from invalid index.")
+            }
+        }
+    }
+
     /// Sort the arena in caller-requested order and update all tree metadata accordingly
     /// `unwraps` will never panic if caller invariants upheld (checked via `debug_assert`)
-    pub fn sort(&mut self, root_idx: Idx, sort_metadata: SortMetaVec) -> Idx {
-        debug_assert!(sort_metadata.iter().all(|ngh| ngh.node_idx.is_some()));
+    pub fn sort(
+        &mut self,
+        root_idx: usize,
+        sort_metadata: ArrayVec<[NodeGetHelper<usize>; N]>, // `usize` here avoids `U` in tree iter signatures
+    ) -> usize {
+        debug_assert!(sort_metadata.iter().all(|ngh| ngh.node_idx().is_some()));
 
-        let mut swap_history = NodeSwapHistHelper::new();
+        let mut swap_history = NodeSwapHistHelper::<U, N>::new();
 
         // Sort as requested
         for (sorted_idx, ngh) in sort_metadata.iter().enumerate() {
-            let curr_idx = swap_history.curr_idx(ngh.node_idx.unwrap());
-            let sorted_idx = sorted_idx as Idx;
+            let curr_idx = swap_history.curr_idx(ngh.node_idx().unwrap());
             if curr_idx != sorted_idx {
-                self.arena.swap(curr_idx.usize(), sorted_idx.usize());
+                self.vec.swap(curr_idx, sorted_idx);
                 swap_history.add(curr_idx, sorted_idx);
 
+                // TODO: move this out of loop body, should do once at end of func with `swap_history`
                 #[cfg(not(feature = "low_mem_insert"))]
-                self.free_list.retain(|i| *i != sorted_idx);
+                {
+                    let old_free_idx = U::checked_from(sorted_idx);
+                    let new_free_idx = U::checked_from(curr_idx);
+                    self.free_list.iter_mut().for_each(|i| {
+                        if *i == old_free_idx {
+                            *i = new_free_idx;
+                        }
+                    });
+                }
             }
         }
 
         // Update all parent-child relationships
         for ngh in sort_metadata {
-            if let Some(parent_idx) = ngh.parent_idx {
+            if let Some(parent_idx) = ngh.parent_idx() {
                 let curr_parent_idx = swap_history.curr_idx(parent_idx);
-                let curr_child_idx = swap_history.curr_idx(ngh.node_idx.unwrap());
-                let parent_node = self.hard_get_mut(curr_parent_idx);
-                if ngh.is_right_child {
-                    parent_node.right_idx = Some(curr_child_idx);
+                let curr_child_idx = swap_history.curr_idx(ngh.node_idx().unwrap());
+                let parent_node = &mut self[curr_parent_idx];
+                if ngh.is_right_child() {
+                    parent_node.set_right_idx(Some(curr_child_idx));
                 } else {
-                    parent_node.left_idx = Some(curr_child_idx);
+                    parent_node.set_left_idx(Some(curr_child_idx));
                 }
             }
         }
@@ -156,139 +184,186 @@ impl<K, V> NodeArena<K, V> {
         swap_history.curr_idx(root_idx)
     }
 
-    /// Remove node at a known-good index (simpler callsite and error handling) from area.
-    /// This function can panic. If the index might be invalid, use `remove` instead.
-    pub fn hard_remove(&mut self, idx: Idx) -> Node<K, V> {
-        match self.remove(idx) {
+    /// Returns the number of entries in the arena, some of which may be `None`.
+    pub fn len(&self) -> usize {
+        self.vec.len()
+    }
+
+    /// Returns true if the index is occupied, e.g. `Some(node)`.
+    pub fn is_occupied(&self, idx: usize) -> bool {
+        (idx < self.vec.len()) && (self.vec[idx].is_some())
+    }
+
+    /// Get the size of an individual arena node, in bytes.
+    pub fn node_size(&self) -> usize {
+        core::mem::size_of::<Node<K, V, U>>()
+    }
+}
+
+// Convenience Traits --------------------------------------------------------------------------------------------------
+
+/// Immutable indexing.
+/// Indexed location MUST be occupied.
+impl<K: Default, V: Default, U: Default, const N: usize> Index<usize> for Arena<K, V, U, N> {
+    type Output = Node<K, V, U>;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        match &self.vec[index] {
             Some(node) => node,
-            None => {
-                panic!("Internal invariant failed: attempted removal of node from invalid index.")
-            }
+            None => unreachable!(),
         }
     }
+}
 
-    /// Get a reference to a node.
-    pub fn get(&self, idx: Idx) -> Option<&Node<K, V>> {
-        match self.arena.get(idx.usize()) {
-            Some(Some(node)) => Some(node),
-            _ => None,
+/// Mutable indexing
+/// Indexed location MUST be occupied.
+impl<K: Default, V: Default, U: Default, const N: usize> IndexMut<usize> for Arena<K, V, U, N> {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        match self.vec.index_mut(index) {
+            Some(node) => node,
+            None => unreachable!(),
         }
     }
+}
 
-    /// Get mutable reference to a node.
-    pub fn get_mut(&mut self, idx: Idx) -> Option<&mut Node<K, V>> {
-        match self.arena.get_mut(idx.usize()) {
-            Some(Some(node)) => Some(node),
-            _ => None,
-        }
+impl<
+        K: Ord + Default,
+        V: Default,
+        U: Default + Copy + SmallUnsigned + Ord + PartialEq + PartialOrd,
+        const N: usize,
+    > Default for Arena<K, V, U, N>
+{
+    fn default() -> Self {
+        Self::new()
     }
+}
 
-    /// Get reference to a node at a known-good index (simpler callsite and error handling).
-    /// This function can panic. If the index might be invalid, use `get` instead.
-    pub fn hard_get(&self, idx: Idx) -> &Node<K, V> {
-        match self.get(idx) {
-            Some(node) => node,
-            None => {
-                panic!("Internal invariant failed: attempted retrieval of node from invalid index.")
-            }
+/*
+NOTE: This is draft code for upgrades when `feature(generic_const_exprs)` stabilizes.
+
+// Wrapper Iterators ---------------------------------------------------------------------------------------------------
+
+pub struct ArenaIter<'a, K: Default, V: Default, U, const N: usize> {
+    arena_iter: core::slice::Iter<'a, Option<Node<K, V, U>>>,
+}
+
+impl<'a, K: Default, V: Default, U, const N: usize> ArenaIter<'a, K, V, U, N> {
+    pub fn new(arena: &'a Arena<K, V, U, N>) -> Self {
+        ArenaIter {
+            arena_iter: arena.vec.iter(),
         }
     }
+}
 
-    /// Get mutable reference to a node at a known-good index (simpler callsite and error handling).
-    /// This function can panic. If the index might be invalid, use `get_mut` instead.
-    pub fn hard_get_mut(&mut self, idx: Idx) -> &mut Node<K, V> {
-        match self.get_mut(idx) {
-            Some(node) => node,
-            None => panic!("Internal invariant failed: attempted mutable retrieval of node from invalid index."),
+impl<'a, K: Default, V: Default, U: SmallUnsigned + Copy, const N: usize> Iterator for ArenaIter<'a, K, V, U, N> {
+    type Item = (&'a K, &'a V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self.arena_iter.next() {
+            Some(Some(node)) => Some((node.key(), node.val())),
+            _ => None,
         }
     }
+}
 
-    /// Returns the number of entries in the arena, some of which may be `None`.
-    pub fn len(&self) -> usize {
-        self.arena.len()
+pub struct ArenaIterMut<'a, K: Default, V: Default, U, const N: usize> {
+    arena_iter_mut: core::slice::IterMut<'a, Option<Node<K, V, U>>>,
+}
+
+impl<'a, K: Default, V: Default, U, const N: usize> ArenaIterMut<'a, K, V, U, N> {
+    pub fn new(arena: &'a mut Arena<K, V, U, N>) -> Self {
+        ArenaIterMut {
+            arena_iter_mut: arena.vec.iter_mut(),
+        }
     }
 }
 
-impl<K: Ord, V> Default for NodeArena<K, V> {
-    fn default() -> Self {
-        Self::new()
+impl<'a, K: Default, V: Default, U: SmallUnsigned + Copy, const N: usize> Iterator for ArenaIterMut<'a, K, V, U, N> {
+    type Item = (&'a K, &'a mut V);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        match self.arena_iter_mut.next() {
+            Some(Some(node)) => Some(node.get_mut()),
+            _ => None,
+        }
     }
 }
+*/
+
+// Test ----------------------------------------------------------------------------------------------------------------
 
 #[cfg(test)]
 mod tests {
-    use super::{Node, NodeArena};
-    use crate::tree::arena::MAX_ELEMS;
+    use super::Arena;
     use crate::tree::node::NodeGetHelper;
-    use smallvec::smallvec;
+    use crate::tree::node_dispatch::SmallNode;
+    use core::mem::size_of_val;
+    use smallnum::small_unsigned;
+    use tinyvec::array_vec;
+
+    const CAPACITY: usize = 1024;
 
     #[test]
     fn test_add_and_remove() {
-        let n_1 = Node::new(1, "n/a");
-        let n_2 = Node::new(2, "n/a");
-        let n_3 = Node::new(3, "n/a");
+        let mut arena: Arena<isize, &str, small_unsigned!(CAPACITY), CAPACITY> = Arena::new();
 
-        let mut arena = NodeArena::new();
-
-        let n_1_idx = arena.add(n_1);
-        let n_2_idx = arena.add(n_2);
-        let n_3_idx = arena.add(n_3);
+        let n_1_idx = arena.add(1, "n/a");
+        let n_2_idx = arena.add(2, "n/a");
+        let n_3_idx = arena.add(3, "n/a");
 
         assert_eq!(n_1_idx, 0);
         assert_eq!(n_2_idx, 1);
         assert_eq!(n_3_idx, 2);
 
         let n_2_removed = arena.remove(n_2_idx).unwrap();
-        assert_eq!(n_2_removed.key, 2);
-        assert!(arena.arena[1].is_none());
+        assert_eq!(n_2_removed.key(), &2);
+        assert!(arena.vec[1].is_none());
 
-        let n_4 = Node::new(4, "n/a");
-        let n_4_idx = arena.add(n_4);
+        let n_4_idx = arena.add(4, "n/a");
         assert_eq!(n_4_idx, 1);
 
-        let n_5 = Node::new(5, "n/a");
-        let n_5_idx = arena.add(n_5);
+        let n_5_idx = arena.add(5, "n/a");
         assert_eq!(n_5_idx, 3);
     }
 
     #[test]
-    fn test_get_mut() {
-        let n_1 = Node::new(1, "n/a");
-        let mut arena = NodeArena::new();
-        let n_1_idx = arena.add(n_1);
-        assert_eq!(arena.get(n_1_idx).unwrap().val, "n/a");
-        let n_1_mut_ref = arena.get_mut(n_1_idx).unwrap();
-        n_1_mut_ref.val = "This is a value. There are many like it but this one is mine.";
-        assert_ne!(arena.get(n_1_idx).unwrap().val, "n/a");
+    fn test_index_mut() {
+        let mut arena: Arena<isize, &str, small_unsigned!(CAPACITY), CAPACITY> = Arena::new();
+        let n_1_idx = arena.add(1, "n/a");
+        assert_eq!(arena[n_1_idx].val(), &"n/a");
+        let n_1_mut_ref = &mut arena[n_1_idx];
+        n_1_mut_ref.set_val("This is a value. There are many like it but this one is mine.");
+        assert_ne!(arena[n_1_idx].val(), &"n/a");
     }
 
     #[test]
-    fn test_hard_get_1() {
-        let n_1 = Node::new(0xD00DFEED_u64, "n/a");
-        let mut arena = NodeArena::new();
-        let n_1_idx = arena.add(n_1);
-        let n_1_ref = arena.hard_get(n_1_idx);
-        assert_eq!(n_1_ref.key, 0xD00DFEED_u64);
+    fn test_index_1() {
+        let mut arena: Arena<u64, &str, small_unsigned!(CAPACITY), CAPACITY> = Arena::new();
+        let n_1_idx = arena.add(0xD00DFEED_u64, "n/a");
+        let n_1_ref = &arena[n_1_idx];
+        assert_eq!(n_1_ref.key(), &0xD00DFEED_u64);
     }
 
     #[test]
     #[should_panic]
-    fn test_hard_get_2() {
-        let n_1 = Node::new(0xD00DFEED_u64, "n/a");
-        let mut arena = NodeArena::new();
-        arena.add(n_1);
-        arena.hard_get(1); // OOB
+    fn test_index_2() {
+        let mut arena: Arena<u64, &str, small_unsigned!(CAPACITY), CAPACITY> = Arena::new();
+        arena.add(0xD00DFEED_u64, "n/a");
+        let _ = &arena[1]; // OOB
     }
 
     #[test]
     fn test_capacity() {
-        let arena = NodeArena::<i32, &str>::new();
-        assert_eq!(arena.capacity(), MAX_ELEMS);
+        let arena = Arena::<i8, u128, small_unsigned!(CAPACITY), CAPACITY>::new();
+        assert_eq!(arena.capacity(), CAPACITY);
+
+        let arena = Arena::<i32, &str, small_unsigned!(1337), 1337>::new();
+        assert_eq!(arena.capacity(), 1337);
     }
 
     #[test]
     fn test_sort() {
-        let mut arena = NodeArena::<usize, &str>::new();
+        let mut arena = Arena::<usize, &str, small_unsigned!(CAPACITY), CAPACITY>::new();
 
         // Simple 3-node tree:
         //
@@ -298,46 +373,62 @@ mod tests {
         // |       |
         // 1       3
         //
-        let n_1 = Node::new(1, "n/a");
-        let mut n_2 = Node::new(2, "n/a");
-        let n_3 = Node::new(3, "n/a");
-
-        n_2.left_idx = Some(2);
-        n_2.right_idx = Some(0);
+        arena.add(3, "n/a");
+        let n_2_idx = arena.add(2, "n/a");
+        arena.add(1, "n/a");
 
-        arena.add(n_3);
-        arena.add(n_2);
-        arena.add(n_1);
+        let n_2 = &mut arena[n_2_idx];
+        n_2.set_left_idx(Some(2));
+        n_2.set_right_idx(Some(0));
 
         // Unsorted (insertion/"physical" order)
-        assert_eq!(arena.arena[0].as_ref().unwrap().key, 3);
-        assert_eq!(arena.arena[1].as_ref().unwrap().key, 2);
-        assert_eq!(arena.arena[2].as_ref().unwrap().key, 1);
+        assert_eq!(arena.vec[0].as_ref().unwrap().key(), &3);
+        assert_eq!(arena.vec[1].as_ref().unwrap().key(), &2);
+        assert_eq!(arena.vec[2].as_ref().unwrap().key(), &1);
 
         // Would be supplied for the above tree
-        let sort_metadata = smallvec! {
-            NodeGetHelper {
-                node_idx: Some(2),
-                parent_idx: Some(1),
-                is_right_child: false,
-            },
-            NodeGetHelper {
-                node_idx: Some(1),
-                parent_idx: None,
-                is_right_child: false,
-            },
-            NodeGetHelper {
-                node_idx: Some(0),
-                parent_idx: Some(1),
-                is_right_child: true,
-            },
+        let sort_metadata = array_vec! { [NodeGetHelper<usize>; CAPACITY] =>
+            NodeGetHelper::new(Some(2), Some(1), false),
+            NodeGetHelper::new(Some(1), None, false),
+            NodeGetHelper::new(Some(0), Some(1), false),
         };
 
         arena.sort(1, sort_metadata);
 
         // Sorted ("logical" order)
-        assert_eq!(arena.arena[0].as_ref().unwrap().key, 1);
-        assert_eq!(arena.arena[1].as_ref().unwrap().key, 2);
-        assert_eq!(arena.arena[2].as_ref().unwrap().key, 3);
+        assert_eq!(arena.vec[0].as_ref().unwrap().key(), &1);
+        assert_eq!(arena.vec[1].as_ref().unwrap().key(), &2);
+        assert_eq!(arena.vec[2].as_ref().unwrap().key(), &3);
+    }
+
+    #[test]
+    fn test_node_packing() {
+        const SMALL_CAPACITY: usize = 100;
+        const LARGE_CAPACITY: usize = 1_000;
+
+        let small_arena = Arena::<u64, u64, small_unsigned!(SMALL_CAPACITY), SMALL_CAPACITY>::new();
+        let large_arena = Arena::<u64, u64, small_unsigned!(LARGE_CAPACITY), LARGE_CAPACITY>::new();
+
+        let small_arena_size = size_of_val(&small_arena);
+        let large_arena_size = size_of_val(&large_arena);
+
+        println!("\nArena sizes:");
+        println!("\tSmall: {} bytes", small_arena_size);
+        println!("\tBig: {} bytes", large_arena_size);
+
+        assert!(small_arena_size < large_arena_size);
+
+        /*
+        NOTE: This is draft code for upgrades when `feature(generic_const_exprs)` stabilizes.
+
+        let small_node_size = small_arena.node_size();
+        let large_node_size = large_arena.node_size();
+
+        println!("\nNode sizes:");
+        println!("\tSmall: {} bytes", small_node_size);
+        println!("\tBig: {} bytes", large_node_size);
+
+        assert!(small_node_size < large_node_size);
+        */
     }
 }
diff --git a/src/tree/error.rs b/src/tree/error.rs
index ecd7d5e..d7f2b0f 100644
--- a/src/tree/error.rs
+++ b/src/tree/error.rs
@@ -1,17 +1,16 @@
-// TODO: update case to "SgErr" in v2.0.0
 /// Errors for fallible operations.
 #[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum SGErr {
+pub enum SgError {
+    /// Cannot construct instance, maximum supported capacity exceeded.
+    MaximumCapacityExceeded,
+
     /// Requested operation cannot complete, stack storage is full.
-    /// This error is unique to the `high_assurance` feature.
     StackCapacityExceeded,
 
-    /// Invalid rebalance factor requested, cannot set.
-    RebalanceFactorOutOfRange,
-
-    /// Reserved for future use
-    Reserved2,
-
+    /*
+    /// Requested operation cannot complete, heap storage is full.
+    HeapCapacityExceeded,
+    */
     /// Reserved for future use
     Reserved3,
 
@@ -26,4 +25,23 @@ pub enum SGErr {
 
     /// Reserved for future use
     Reserved7,
+
+    /// Invalid rebalance factor requested, cannot set.
+    RebalanceFactorOutOfRange,
+}
+
+/*
+
+Requires nightly feature:
+
+#[cfg(test)]
+mod tests {
+    use crate::SgError;
+    use std::mem::variant_count;
+
+    #[test]
+    fn test_err_var_cnt() {
+        assert_eq!(variant_count::<SgError>(), 8);
+    }
 }
+*/
diff --git a/src/tree/iter.rs b/src/tree/iter.rs
index 645f67b..52cf1b9 100644
--- a/src/tree/iter.rs
+++ b/src/tree/iter.rs
@@ -1,30 +1,34 @@
-use super::node::Node;
-use super::tree::SGTree;
-use super::types::IdxVec;
+use tinyvec::ArrayVec;
 
-// TODO: add pre-order and post-order iterators
+use super::node::Node;
+use super::node_dispatch::SmallNode;
+use super::tree::{Idx, SgTree};
 
-// Immutable Reference iterator ----------------------------------------------------------------------------------------
+// Immutable Reference Iterator ----------------------------------------------------------------------------------------
 
 /// Uses iterative in-order tree traversal algorithm.
 /// Maintains a small stack of arena indexes (won't contain all indexes simultaneously for a balanced tree).
-pub struct Iter<'a, K: Ord, V> {
-    bst: &'a SGTree<K, V>,
-    idx_stack: IdxVec,
+pub struct Iter<'a, K: Default, V: Default, const N: usize> {
+    bst: &'a SgTree<K, V, N>,
+    idx_stack: ArrayVec<[usize; N]>,
+    total_cnt: usize,
+    spent_cnt: usize,
 }
 
-impl<'a, K: Ord, V> Iter<'a, K, V> {
-    pub fn new(bst: &'a SGTree<K, V>) -> Self {
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iter<'a, K, V, N> {
+    pub fn new(bst: &'a SgTree<K, V, N>) -> Self {
         let mut ordered_iter = Iter {
             bst,
-            idx_stack: IdxVec::new(),
+            idx_stack: ArrayVec::<[usize; N]>::new(),
+            total_cnt: bst.len(),
+            spent_cnt: 0,
         };
 
-        if let Some(root_idx) = ordered_iter.bst.root_idx {
+        if let Some(root_idx) = ordered_iter.bst.opt_root_idx {
             let mut curr_idx = root_idx;
             loop {
-                let node = ordered_iter.bst.arena.hard_get(curr_idx);
-                match node.left_idx {
+                let node = &ordered_iter.bst.arena[curr_idx];
+                match node.left_idx() {
                     Some(lt_idx) => {
                         ordered_iter.idx_stack.push(curr_idx);
                         curr_idx = lt_idx;
@@ -41,18 +45,18 @@ impl<'a, K: Ord, V> Iter<'a, K, V> {
     }
 }
 
-impl<'a, K: Ord, V> Iterator for Iter<'a, K, V> {
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iterator for Iter<'a, K, V, N> {
     type Item = (&'a K, &'a V);
 
     fn next(&mut self) -> Option<Self::Item> {
         match self.idx_stack.pop() {
             Some(pop_idx) => {
-                let node = self.bst.arena.hard_get(pop_idx);
-                if let Some(gt_idx) = node.right_idx {
+                let node = &self.bst.arena[pop_idx];
+                if let Some(gt_idx) = node.right_idx() {
                     let mut curr_idx = gt_idx;
                     loop {
-                        let node = self.bst.arena.hard_get(curr_idx);
-                        match node.left_idx {
+                        let node = &self.bst.arena[curr_idx];
+                        match node.left_idx() {
                             Some(lt_idx) => {
                                 self.idx_stack.push(curr_idx);
                                 curr_idx = lt_idx;
@@ -65,22 +69,30 @@ impl<'a, K: Ord, V> Iterator for Iter<'a, K, V> {
                     }
                 }
 
-                let node = self.bst.arena.hard_get(pop_idx);
-                Some((&node.key, &node.val))
+                let node = &self.bst.arena[pop_idx];
+                self.spent_cnt += 1;
+                Some((node.key(), node.val()))
             }
             None => None,
         }
     }
 }
 
-// Mutable Reference iterator ----------------------------------------------------------------------------------------
+impl<'a, K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for Iter<'a, K, V, N> {
+    fn len(&self) -> usize {
+        debug_assert!(self.spent_cnt <= self.total_cnt);
+        self.total_cnt - self.spent_cnt
+    }
+}
+
+// Mutable Reference Iterator ------------------------------------------------------------------------------------------
 
-pub struct IterMut<'a, K: Ord, V> {
-    arena_iter_mut: core::slice::IterMut<'a, Option<Node<K, V>>>,
+pub struct IterMut<'a, K, V, const N: usize> {
+    arena_iter_mut: core::slice::IterMut<'a, Option<Node<K, V, Idx>>>,
 }
 
-impl<'a, K: Ord, V> IterMut<'a, K, V> {
-    pub fn new(bst: &'a mut SGTree<K, V>) -> Self {
+impl<'a, K: Ord + Default, V: Default, const N: usize> IterMut<'a, K, V, N> {
+    pub fn new(bst: &'a mut SgTree<K, V, N>) -> Self {
         bst.sort_arena();
         IterMut {
             arena_iter_mut: bst.arena.iter_mut(),
@@ -88,35 +100,40 @@ impl<'a, K: Ord, V> IterMut<'a, K, V> {
     }
 }
 
-impl<'a, K: Ord, V> Iterator for IterMut<'a, K, V> {
+impl<'a, K: Ord + Default, V: Default, const N: usize> Iterator for IterMut<'a, K, V, N> {
     type Item = (&'a K, &'a mut V);
 
     fn next(&mut self) -> Option<Self::Item> {
         match self.arena_iter_mut.next() {
-            Some(Some(node)) => Some((&node.key, &mut node.val)),
+            Some(Some(node)) => Some(node.get_mut()),
             _ => None,
         }
     }
 }
 
-// Consuming iterator --------------------------------------------------------------------------------------------------
+impl<'a, K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for IterMut<'a, K, V, N> {
+    fn len(&self) -> usize {
+        self.arena_iter_mut.len()
+    }
+}
+
+// Consuming Iterator --------------------------------------------------------------------------------------------------
 
 /// Cheats a little by using internal flattening logic to sort, instead of re-implementing proper traversal.
 /// Maintains a shrinking list of arena indexes, initialized with all of them.
-pub struct IntoIter<K: Ord, V> {
-    bst: SGTree<K, V>,
-    sorted_idxs: IdxVec,
+pub struct IntoIter<K: Default, V: Default, const N: usize> {
+    bst: SgTree<K, V, N>,
+    sorted_idxs: ArrayVec<[usize; N]>,
 }
 
-impl<K: Ord, V> IntoIter<K, V> {
-    /// Constructor
-    pub fn new(bst: SGTree<K, V>) -> Self {
+impl<K: Ord + Default, V: Default, const N: usize> IntoIter<K, V, N> {
+    pub fn new(bst: SgTree<K, V, N>) -> Self {
         let mut ordered_iter = IntoIter {
             bst,
-            sorted_idxs: IdxVec::new(),
+            sorted_idxs: ArrayVec::<[usize; N]>::new(),
         };
 
-        if let Some(root_idx) = ordered_iter.bst.root_idx {
+        if let Some(root_idx) = ordered_iter.bst.opt_root_idx {
             ordered_iter.sorted_idxs = ordered_iter.bst.flatten_subtree_to_sorted_idxs(root_idx);
             ordered_iter.sorted_idxs.reverse();
         }
@@ -125,13 +142,13 @@ impl<K: Ord, V> IntoIter<K, V> {
     }
 }
 
-impl<K: Ord, V> Iterator for IntoIter<K, V> {
+impl<K: Ord + Default, V: Default, const N: usize> Iterator for IntoIter<K, V, N> {
     type Item = (K, V);
 
     fn next(&mut self) -> Option<Self::Item> {
         match self.sorted_idxs.pop() {
             Some(idx) => match self.bst.priv_remove_by_idx(idx) {
-                Some(node) => Some((node.key, node.val)),
+                Some((key, val)) => Some((key, val)),
                 None => {
                     debug_assert!(false, "Use of invalid index in consuming iterator!");
                     None
@@ -141,3 +158,9 @@ impl<K: Ord, V> Iterator for IntoIter<K, V> {
         }
     }
 }
+
+impl<K: Ord + Default, V: Default, const N: usize> ExactSizeIterator for IntoIter<K, V, N> {
+    fn len(&self) -> usize {
+        self.sorted_idxs.len()
+    }
+}
diff --git a/src/tree/mod.rs b/src/tree/mod.rs
index 26c2697..6c1ae4e 100644
--- a/src/tree/mod.rs
+++ b/src/tree/mod.rs
@@ -1,12 +1,11 @@
-mod types;
-pub(crate) use types::{ElemRefIter, ElemRefVec};
+mod node_dispatch;
 
 #[cfg(test)]
 mod test;
 
 mod arena;
 #[cfg(fuzzing)]
-pub use arena::NodeArena;
+pub use arena::Arena;
 
 mod node;
 #[cfg(fuzzing)]
@@ -16,8 +15,8 @@ mod iter;
 pub use iter::{IntoIter, Iter, IterMut};
 
 mod error;
-pub use error::SGErr;
+pub use error::SgError;
 
 #[allow(clippy::module_inception)]
 mod tree;
-pub use tree::SGTree;
+pub use tree::{Idx, SgTree};
diff --git a/src/tree/node.rs b/src/tree/node.rs
index e68ea1c..e19ec2a 100644
--- a/src/tree/node.rs
+++ b/src/tree/node.rs
@@ -1,20 +1,36 @@
-use super::types::{Idx, SortSwapVec};
+use core::ops::Sub;
+
+use super::node_dispatch::SmallNode;
+
+use smallnum::SmallUnsigned;
+use tinyvec::ArrayVec;
+
+/*
+Note:
+
+Structures in this file generic for `U` in a *subset* of the set `(u8, u16, u32, u64, u128)`.
+All members in subset are <= host pointer width in size.
+If caller obeys contract, `U` will be smallest unsigned capable of representing `arena::Arena`'s
+const `N` (e.g. static capacity).
+*/
 
 // Tree Node -----------------------------------------------------------------------------------------------------------
 
-/// Binary tree node.
-#[derive(Clone)]
-pub struct Node<K, V> {
-    pub key: K,
-    pub val: V,
-    pub left_idx: Option<Idx>,
-    pub right_idx: Option<Idx>,
+/// Binary tree node, meta programmable for low memory footprint.
+/// Users of it's APIs only need to declare `U` type or trait bounds at construction.
+/// All APIs take/return `usize` and normalize to `U` internally.
+#[derive(Clone, Debug, Default)]
+pub struct Node<K, V, U> {
+    key: K,
+    val: V,
+    left_idx: Option<U>,
+    right_idx: Option<U>,
 
     #[cfg(feature = "fast_rebalance")]
-    pub subtree_size: Idx,
+    subtree_size: U,
 }
 
-impl<K, V> Node<K, V> {
+impl<K, V, U: SmallUnsigned> Node<K, V, U> {
     /// Constructor.
     pub fn new(key: K, val: V) -> Self {
         Node {
@@ -24,51 +40,135 @@ impl<K, V> Node<K, V> {
             right_idx: None,
 
             #[cfg(feature = "fast_rebalance")]
-            subtree_size: 1,
+            subtree_size: U::checked_from(1),
         }
     }
 }
 
+impl<K: Default, V: Default, U: SmallUnsigned + Copy> SmallNode<K, V> for Node<K, V, U> {
+    fn key(&self) -> &K {
+        &self.key
+    }
+
+    fn set_key(&mut self, key: K) {
+        self.key = key;
+    }
+
+    fn take_key(&mut self) -> K {
+        core::mem::take(&mut self.key)
+    }
+
+    fn val(&self) -> &V {
+        &self.val
+    }
+
+    fn get_mut(&mut self) -> (&K, &mut V) {
+        (&self.key, &mut self.val)
+    }
+
+    fn take_val(&mut self) -> V {
+        core::mem::take(&mut self.val)
+    }
+
+    fn set_val(&mut self, val: V) {
+        self.val = val;
+    }
+
+    fn left_idx(&self) -> Option<usize> {
+        self.left_idx.map(|i| i.usize())
+    }
+
+    fn set_left_idx(&mut self, opt_idx: Option<usize>) {
+        match opt_idx {
+            Some(idx) => self.left_idx = Some(U::checked_from(idx)),
+            None => self.left_idx = None,
+        }
+    }
+
+    fn right_idx(&self) -> Option<usize> {
+        self.right_idx.map(|i| i.usize())
+    }
+
+    fn set_right_idx(&mut self, opt_idx: Option<usize>) {
+        match opt_idx {
+            Some(idx) => self.right_idx = Some(U::checked_from(idx)),
+            None => self.right_idx = None,
+        }
+    }
+
+    #[cfg(feature = "fast_rebalance")]
+    fn subtree_size(&self) -> usize {
+        self.subtree_size.usize()
+    }
+
+    #[cfg(feature = "fast_rebalance")]
+    fn set_subtree_size(&mut self, size: usize) {
+        self.subtree_size = U::checked_from(size);
+    }
+}
+
 // Retrieval Helper ----------------------------------------------------------------------------------------------------
 
 /// Helper for node retrieval, usage eliminates the need a store parent pointer in each node.
-pub struct NodeGetHelper {
-    pub node_idx: Option<Idx>,
-    pub parent_idx: Option<Idx>,
-    pub is_right_child: bool,
+/// Users of it's APIs only need to declare `U` type or trait bounds at construction.
+/// All APIs take/return `usize` and normalize to `U` internally.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct NodeGetHelper<U> {
+    node_idx: Option<U>,
+    parent_idx: Option<U>,
+    is_right_child: bool,
 }
 
-impl NodeGetHelper {
+impl<U: SmallUnsigned + Copy> NodeGetHelper<U> {
     /// Constructor.
-    pub fn new(node_idx: Option<Idx>, parent_idx: Option<Idx>, is_right_child: bool) -> Self {
+    pub fn new(node_idx: Option<usize>, parent_idx: Option<usize>, is_right_child: bool) -> Self {
         NodeGetHelper {
-            node_idx,
-            parent_idx,
+            node_idx: node_idx.map(|i| U::checked_from(i)),
+            parent_idx: parent_idx.map(|i| U::checked_from(i)),
             is_right_child,
         }
     }
+
+    /// Get node index as `usize`
+    pub fn node_idx(&self) -> Option<usize> {
+        self.node_idx.map(|i| i.usize())
+    }
+
+    /// Get parent index as `usize`
+    pub fn parent_idx(&self) -> Option<usize> {
+        self.parent_idx.map(|i| i.usize())
+    }
+
+    // Tell if right or left child
+    pub fn is_right_child(&self) -> bool {
+        self.is_right_child
+    }
 }
 
 // Tree Rebuild Helper -------------------------------------------------------------------------------------------------
 
 /// Helper for in-place iterative rebuild.
-pub struct NodeRebuildHelper {
-    pub low_idx: Idx,
-    pub high_idx: Idx,
-    pub mid_idx: Idx,
+/// Users of it's APIs only need to declare `U` type or trait bounds at construction.
+/// All APIs take/return `usize` and normalize to `U` internally.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct NodeRebuildHelper<U> {
+    pub low_idx: U,
+    pub high_idx: U,
+    pub mid_idx: U,
 }
 
-impl NodeRebuildHelper {
+impl<U: SmallUnsigned + Ord + Sub + Copy> NodeRebuildHelper<U> {
     /// Constructor.
-    pub fn new(low_idx: Idx, high_idx: Idx) -> Self {
+    pub fn new(low_idx: usize, high_idx: usize) -> Self {
         debug_assert!(
             high_idx >= low_idx,
             "Node rebuild helper low/high index reversed!"
         );
+
         NodeRebuildHelper {
-            low_idx,
-            high_idx,
-            mid_idx: low_idx + ((high_idx - low_idx) / 2),
+            low_idx: U::checked_from(low_idx),
+            high_idx: U::checked_from(high_idx),
+            mid_idx: U::checked_from(low_idx + ((high_idx - low_idx) / 2)),
         }
     }
 }
@@ -77,27 +177,33 @@ impl NodeRebuildHelper {
 
 /// A helper "cache" for swap operation history.
 /// If every index swap is logged, tracks mapping of original to current indexes.
-pub struct NodeSwapHistHelper {
+/// Users of it's APIs only need to declare `U` type or trait bounds at construction.
+/// All APIs take/return `usize` and normalize to `U` internally.
+#[derive(Debug, Default)]
+pub struct NodeSwapHistHelper<U: Default, const N: usize> {
     /// Map `original_idx` -> `current_idx`
-    history: SortSwapVec,
+    history: ArrayVec<[(U, U); N]>,
 }
 
-impl NodeSwapHistHelper {
+impl<U: Ord + Default + Copy + SmallUnsigned, const N: usize> NodeSwapHistHelper<U, N> {
     /// Constructor.
-    pub fn new() -> NodeSwapHistHelper {
+    pub fn new() -> Self {
         NodeSwapHistHelper {
-            history: SortSwapVec::new(),
+            history: ArrayVec::<[(U, U); N]>::default(),
         }
     }
 
     /// Log the swap of elements at two indexes.
     /// Every swap performed must be logged with this method for the cache to remain accurate.
-    pub fn add(&mut self, pos_1: Idx, pos_2: Idx) {
+    pub fn add(&mut self, pos_1: usize, pos_2: usize) {
         debug_assert_ne!(pos_1, pos_2);
 
         let mut known_pos_1 = false;
         let mut known_pos_2 = false;
 
+        let pos_1 = U::checked_from(pos_1);
+        let pos_2 = U::checked_from(pos_2);
+
         // Update existing
         for (_, curr_idx) in self.history.iter_mut() {
             if *curr_idx == pos_1 {
@@ -121,70 +227,52 @@ impl NodeSwapHistHelper {
     }
 
     /// Retrieve the current value of an original index from the map.
-    pub fn curr_idx(&self, orig_pos: Idx) -> Idx {
-        debug_assert!(self.history.iter().filter(|(k, _)| *k == orig_pos).count() <= 1);
+    pub fn curr_idx(&self, orig_pos: usize) -> usize {
+        debug_assert!(
+            self.history
+                .iter()
+                .filter(|(k, _)| (*k).usize() == orig_pos)
+                .count()
+                <= 1
+        );
 
         match self
             .history
             .iter()
-            .filter(|(k, _)| *k == orig_pos)
+            .filter(|(k, _)| (*k).usize() == orig_pos)
             .map(|(_, curr)| *curr)
             .next()
         {
-            Some(curr_idx) => curr_idx,
+            Some(curr_idx) => curr_idx.usize(),
             None => orig_pos,
         }
     }
 }
 
+// Test ----------------------------------------------------------------------------------------------------------------
+
 // Note: low_mem_insert feature doesn't affect node size, only arena size.
 #[cfg(not(feature = "low_mem_insert"))]
 #[cfg(test)]
 mod tests {
     use super::Node;
+    use smallnum::small_unsigned;
     use std::mem::size_of;
 
-    #[cfg(feature = "high_assurance")]
-    use crate::MAX_ELEMS;
-
     #[test]
-    fn test_node_packing() {
+    fn test_node_sizing() {
         // No features
         #[cfg(target_pointer_width = "64")]
-        #[cfg(not(feature = "high_assurance"))]
         #[cfg(not(feature = "fast_rebalance"))]
         {
-            assert_eq!(size_of::<Node<u32, u32>>(), 40);
-        }
-
-        // All features
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(feature = "high_assurance")]
-        #[cfg(feature = "fast_rebalance")]
-        {
-            // Assumes `SG_MAX_STACK_ELEMS == 1024` (default)
-            if MAX_ELEMS < u16::MAX.into() {
-                assert_eq!(size_of::<Node<u32, u32>>(), 20);
-            }
+            assert_eq!(size_of::<Node<u32, u32, small_unsigned!(1024)>>(), 16);
         }
 
         // fast_rebalance only
         #[cfg(target_pointer_width = "64")]
-        #[cfg(not(feature = "high_assurance"))]
         #[cfg(feature = "fast_rebalance")]
         {
-            assert_eq!(size_of::<Node<u32, u32>>(), 48);
-        }
-
-        // high_assurance only
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(feature = "high_assurance")]
-        #[cfg(not(feature = "fast_rebalance"))]
-        {
-            // Assumes `SG_MAX_STACK_ELEMS == 1024` (default)
-            if MAX_ELEMS < u16::MAX.into() {
-                assert_eq!(size_of::<Node<u32, u32>>(), 16);
-            }
+            assert_eq!(size_of::<Node<u32, u32, small_unsigned!(1024)>>(), 20);
         }
     }
 }
diff --git a/src/tree/node_dispatch.rs b/src/tree/node_dispatch.rs
new file mode 100644
index 0000000..b29d44d
--- /dev/null
+++ b/src/tree/node_dispatch.rs
@@ -0,0 +1,199 @@
+// Size-optimized Node Trait -------------------------------------------------------------------------------------------
+
+/// Interface encapsulates `U`.
+pub trait SmallNode<K, V: Default> {
+    /// Get key.
+    fn key(&self) -> &K;
+
+    /// Set key.
+    fn set_key(&mut self, key: K);
+
+    // Take key, replacing current with `K::Default()`.
+    fn take_key(&mut self) -> K;
+
+    /// Get value.
+    fn val(&self) -> &V;
+
+    /// Get key and mutable value.
+    fn get_mut(&mut self) -> (&K, &mut V);
+
+    /// Set value.
+    fn set_val(&mut self, val: V);
+
+    // Take value, replacing current with `V::Default()`.
+    fn take_val(&mut self) -> V;
+
+    /// Get left index as `usize`.
+    fn left_idx(&self) -> Option<usize>;
+
+    /// Set left index.
+    fn set_left_idx(&mut self, opt_idx: Option<usize>);
+
+    /// Get right index as `usize`.
+    fn right_idx(&self) -> Option<usize>;
+
+    /// Set right index.
+    fn set_right_idx(&mut self, opt_idx: Option<usize>);
+
+    /// Get subtree size.
+    #[cfg(feature = "fast_rebalance")]
+    fn subtree_size(&self) -> usize;
+
+    /// Set subtree size.
+    #[cfg(feature = "fast_rebalance")]
+    fn set_subtree_size(&mut self, size: usize);
+}
+
+/*
+NOTE: This is draft code for upgrades when `feature(generic_const_exprs)` stabilizes.
+
+use super::node::Node;
+use smallnum::SmallUnsignedLabel;
+
+// Enum Dispatch -------------------------------------------------------------------------------------------------------
+
+#[derive(Clone)]
+pub enum SmallNodeDispatch<K: Default, V: Default> {
+    NodeUSIZE(Node<K, V, usize>),
+    NodeU8(Node<K, V, u8>),
+
+    #[cfg(any(
+        target_pointer_width = "16",
+        target_pointer_width = "32",
+        target_pointer_width = "64",
+        target_pointer_width = "128",
+    ))]
+    NodeU16(Node<K, V, u16>),
+
+    #[cfg(any(
+        target_pointer_width = "32",
+        target_pointer_width = "64",
+        target_pointer_width = "128",
+    ))]
+    NodeU32(Node<K, V, u32>),
+
+    #[cfg(any(target_pointer_width = "64", target_pointer_width = "128",))]
+    NodeU64(Node<K, V, u64>),
+
+    #[cfg(target_pointer_width = "128")]
+    NodeU128(Node<K, V, u128>),
+}
+
+impl<K: Default, V: Default> SmallNodeDispatch<K, V> {
+    pub const fn new(key: K, val: V, uint: SmallUnsignedLabel) -> Self {
+        match uint {
+            SmallUnsignedLabel::USIZE => SmallNodeDispatch::NodeUSIZE(Node::<K, V, usize>::new(key, val)),
+            SmallUnsignedLabel::U8 => SmallNodeDispatch::NodeU8(Node::<K, V, u8>::new(key, val)),
+
+            #[cfg(any(
+                target_pointer_width = "16",
+                target_pointer_width = "32",
+                target_pointer_width = "64",
+                target_pointer_width = "128",
+            ))]
+            SmallUnsignedLabel::U16 => SmallNodeDispatch::NodeU16(Node::<K, V, u16>::new(key, val)),
+
+            #[cfg(any(
+                target_pointer_width = "32",
+                target_pointer_width = "64",
+                target_pointer_width = "128",
+            ))]
+            SmallUnsignedLabel::U32 => SmallNodeDispatch::NodeU32(Node::<K, V, u32>::new(key, val)),
+
+            #[cfg(any(target_pointer_width = "64", target_pointer_width = "128",))]
+            SmallUnsignedLabel::U64 => SmallNodeDispatch::NodeU64(Node::<K, V, u64>::new(key, val)),
+
+            #[cfg(target_pointer_width = "128")]
+            SmallUnsignedLabel::U128 => SmallNodeDispatch::NodeU128(Node::<K, V, u128>::new(key, val)),
+
+            _ => unreachable!()
+        }
+    }
+}
+
+macro_rules! dispatch {
+    ( $self:ident, $func:ident $(, $args:expr)* $(,)? ) => {
+        match $self {
+            SmallNodeDispatch::NodeUSIZE(node) => node.$func($($args,)*),
+            SmallNodeDispatch::NodeU8(node) => node.$func($($args,)*),
+
+            #[cfg(any(
+                target_pointer_width = "16",
+                target_pointer_width = "32",
+                target_pointer_width = "64",
+                target_pointer_width = "128",
+            ))]
+            SmallNodeDispatch::NodeU16(node) => node.$func($($args,)*),
+
+            #[cfg(any(
+                target_pointer_width = "32",
+                target_pointer_width = "64",
+                target_pointer_width = "128",
+            ))]
+            SmallNodeDispatch::NodeU32(node) => node.$func($($args,)*),
+
+            #[cfg(any(target_pointer_width = "64", target_pointer_width = "128",))]
+            SmallNodeDispatch::NodeU64(node) => node.$func($($args,)*),
+
+            #[cfg(target_pointer_width = "128")]
+            SmallNodeDispatch::NodeU128(node) => node.$func($($args,)*),
+        }
+    };
+}
+
+impl<K: Default, V: Default> SmallNode<K, V> for SmallNodeDispatch<K, V> {
+    fn key(&self) -> &K {
+        dispatch!(self, key)
+    }
+
+    fn set_key(&mut self, key: K) {
+        dispatch!(self, set_key, key);
+    }
+
+    fn take_key(&mut self) -> K {
+        dispatch!(self, take_key)
+    }
+
+    fn val(&self) -> &V {
+        dispatch!(self, val)
+    }
+
+    fn get_mut(&mut self) -> (&K, &mut V) {
+        dispatch!(self, get_mut)
+    }
+
+    fn set_val(&mut self, val: V) {
+        dispatch!(self, set_val, val);
+    }
+
+    fn take_val(&mut self) -> V {
+        dispatch!(self, take_val)
+    }
+
+    fn left_idx(&self) -> Option<usize> {
+        dispatch!(self, left_idx)
+    }
+
+    fn set_left_idx(&mut self, opt_idx: Option<usize>) {
+        dispatch!(self, set_left_idx, opt_idx);
+    }
+
+    fn right_idx(&self) -> Option<usize> {
+        dispatch!(self, right_idx)
+    }
+
+    fn set_right_idx(&mut self, opt_idx: Option<usize>) {
+        dispatch!(self, set_right_idx, opt_idx);
+    }
+
+    #[cfg(feature = "fast_rebalance")]
+    fn subtree_size(&self) -> usize {
+        dispatch!(self, subtree_size)
+    }
+
+    #[cfg(feature = "fast_rebalance")]
+    fn set_subtree_size(&mut self, size: usize) {
+        dispatch!(self, set_subtree_size, size);
+    }
+}
+*/
diff --git a/src/tree/tree.rs b/src/tree/tree.rs
index 895d1f7..1fa6fd5 100644
--- a/src/tree/tree.rs
+++ b/src/tree/tree.rs
@@ -4,56 +4,62 @@ use core::fmt::{self, Debug};
 use core::hash::{Hash, Hasher};
 use core::iter::FromIterator;
 use core::mem;
-use core::ops::Index;
+use core::ops::{Index, Sub};
 
-use super::arena::NodeArena;
-use super::error::SGErr;
+use super::arena::Arena;
+use super::error::SgError;
 use super::iter::{IntoIter, Iter, IterMut};
-use super::node::{Node, NodeGetHelper, NodeRebuildHelper};
-use super::types::{
-    Idx, IdxVec, RebuildMetaVec, SortMetaVec, SortNodeRefIdxPairVec, SortNodeRefVec,
-};
-
-use crate::{ALPHA_DENOM, ALPHA_NUM};
+use super::node::{NodeGetHelper, NodeRebuildHelper};
+use super::node_dispatch::SmallNode;
 
 #[allow(unused_imports)] // micromath only used if `no_std`
 use micromath::F32Ext;
 use smallnum::SmallUnsigned;
-use smallvec::smallvec;
+use tinyvec::{array_vec, ArrayVec};
+
+// The `u16::MAX` limit is documented in our main `README.md`.
+pub type Idx = u16;
+
+// See: https://github.com/tnballo/scapegoat/blob/master/CONFIG.md
+const DEFAULT_ALPHA_NUM: f32 = 2.0;
+const DEFAULT_ALPHA_DENOM: f32 = 3.0;
 
 /// A memory-efficient, self-balancing binary search tree.
-#[allow(clippy::upper_case_acronyms)] // TODO: Removal == breaking change, e.g. v2.0
 #[derive(Clone)]
-pub struct SGTree<K: Ord, V> {
+pub struct SgTree<K: Default, V: Default, const N: usize> {
     // Storage
-    pub(crate) arena: NodeArena<K, V>,
-    pub(crate) root_idx: Option<Idx>, // TODO: rename to opt_root_idx
+    pub(crate) arena: Arena<K, V, Idx, N>,
+    pub(crate) opt_root_idx: Option<usize>,
 
     // Query cache
-    max_idx: Idx,
-    min_idx: Idx,
-    curr_size: Idx,
+    max_idx: usize,
+    min_idx: usize,
+    curr_size: usize,
 
     // Balance control
     alpha_num: f32,
     alpha_denom: f32,
-    max_size: Idx,
+    max_size: usize,
     rebal_cnt: usize,
 }
 
-impl<K: Ord, V> SGTree<K, V> {
+impl<K: Ord + Default, V: Default, const N: usize> SgTree<K, V, N> {
     // Public API ------------------------------------------------------------------------------------------------------
 
-    /// Makes a new, empty `SGTree`.
+    /// Makes a new, empty `SgTree`.
     pub fn new() -> Self {
-        SGTree {
-            arena: NodeArena::new(),
-            root_idx: None,
+        if N > SgTree::<K, V, N>::max_capacity() {
+            panic!("Max stack item capacity (0x{:x}) exceeded!", Idx::MAX);
+        }
+
+        SgTree {
+            arena: Arena::<K, V, Idx, N>::default(),
+            opt_root_idx: None,
             max_idx: 0,
             min_idx: 0,
             curr_size: 0,
-            alpha_num: ALPHA_NUM,
-            alpha_denom: ALPHA_DENOM,
+            alpha_num: DEFAULT_ALPHA_NUM,
+            alpha_denom: DEFAULT_ALPHA_DENOM,
             max_size: 0,
             rebal_cnt: 0,
         }
@@ -70,18 +76,7 @@ impl<K: Ord, V> SGTree<K, V> {
     ///     * If `a` reached `1.0`, it'd mean a tree that never rebalances.
     ///
     /// Returns `Err` if `0.5 <= alpha_num / alpha_denom < 1.0` isn't `true` (invalid `a`, out of range).
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use scapegoat::SGTree;
-    ///
-    /// let mut sgt: SGTree<isize, isize> = SGTree::new();
-    ///
-    /// // Set 2/3, e.g. `a = 0.666...` (it's default value).
-    /// assert!(sgt.set_rebal_param(2.0, 3.0).is_ok());
-    /// ```
-    pub fn set_rebal_param(&mut self, alpha_num: f32, alpha_denom: f32) -> Result<(), SGErr> {
+    pub fn set_rebal_param(&mut self, alpha_num: f32, alpha_denom: f32) -> Result<(), SgError> {
         let a = alpha_num / alpha_denom;
         match (0.5..1.0).contains(&a) {
             true => {
@@ -89,42 +84,28 @@ impl<K: Ord, V> SGTree<K, V> {
                 self.alpha_denom = alpha_denom;
                 Ok(())
             }
-            false => Err(SGErr::RebalanceFactorOutOfRange),
+            false => Err(SgError::RebalanceFactorOutOfRange),
         }
     }
 
     /// Get the current rebalance parameter, alpha, as a tuple of `(alpha_numerator, alpha_denominator)`.
-    /// See [the corresponding setter method][SGTree::set_rebal_param] for more details.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use scapegoat::SGTree;
-    ///
-    /// let mut sgt: SGTree<isize, isize> = SGTree::new();
-    ///
-    /// // Set 2/3, e.g. `a = 0.666...` (it's default value).
-    /// assert!(sgt.set_rebal_param(2.0, 3.0).is_ok());
-    ///
-    /// // Get the currently set value
-    /// assert_eq!(sgt.rebal_param(), (2.0, 3.0));
-    /// ```
+    /// See [the corresponding setter method][SgTree::set_rebal_param] for more details.
     pub fn rebal_param(&self) -> (f32, f32) {
         (self.alpha_num, self.alpha_denom)
     }
 
-    /// `#![no_std]`: total capacity, e.g. maximum number of tree pairs.
-    /// Attempting to insert pairs beyond capacity will panic, unless the `high_assurance` feature is enabled.
-    ///
-    /// If using `std`: fast capacity, e.g. number of tree pairs stored on the stack.
-    /// Pairs inserted beyond capacity will be stored on the heap.
+    /// Total capacity, e.g. maximum number of tree pairs.
     pub fn capacity(&self) -> usize {
         self.arena.capacity()
     }
 
+    /// Get the size of an individual node in this tree, in bytes.
+    pub fn node_size(&self) -> usize {
+        self.arena.node_size()
+    }
+
     /// Moves all elements from `other` into `self`, leaving `other` empty.
-    #[cfg(not(feature = "high_assurance"))]
-    pub fn append(&mut self, other: &mut SGTree<K, V>)
+    pub fn append(&mut self, other: &mut SgTree<K, V, N>)
     where
         K: Ord,
     {
@@ -141,16 +122,15 @@ impl<K: Ord, V> SGTree<K, V> {
 
         // Rip elements directly out of other's arena and clear it
         for arena_idx in 0..other.arena.len() {
-            if let Some(node) = other.arena.remove(arena_idx as Idx) {
-                self.insert(node.key, node.val);
+            if let Some(mut node) = other.arena.remove(arena_idx) {
+                self.insert(node.take_key(), node.take_val());
             }
         }
         other.clear();
     }
 
     /// Attempts to move all elements from `other` into `self`, leaving `other` empty.
-    #[cfg(feature = "high_assurance")]
-    pub fn append(&mut self, other: &mut SGTree<K, V>) -> Result<(), SGErr> {
+    pub fn try_append(&mut self, other: &mut SgTree<K, V, N>) -> Result<(), SgError> {
         // Nothing to append!
         if other.is_empty() {
             return Ok(());
@@ -163,17 +143,17 @@ impl<K: Ord, V> SGTree<K, V> {
         }
 
         // Rip elements directly out of other's arena and clear it
-        if (self.len() + other.len()) <= self.capacity() {
+        if (self.len() + other.len() - self.intersect_cnt(other)) <= self.capacity() {
             for arena_idx in 0..other.arena.len() {
-                if let Some(node) = other.arena.remove(arena_idx as Idx) {
-                    self.insert(node.key, node.val)?;
+                if let Some(mut node) = other.arena.remove(arena_idx) {
+                    self.try_insert(node.take_key(), node.take_val())?;
                 }
             }
             other.clear();
         } else {
             // Preemptive - we haven't mutated `self` or `other`!
             // Caller can assume unchanged state.
-            return Err(SGErr::StackCapacityExceeded);
+            return Err(SgError::StackCapacityExceeded);
         }
 
         Ok(())
@@ -183,12 +163,11 @@ impl<K: Ord, V> SGTree<K, V> {
     /// If the tree did not have this key present, `None` is returned.
     /// If the tree did have this key present, the value is updated, the old value is returned,
     /// and the key is updated. This accommodates types that can be `==` without being identical.
-    #[cfg(not(feature = "high_assurance"))]
     pub fn insert(&mut self, key: K, val: V) -> Option<V>
     where
         K: Ord,
     {
-        self.priv_balancing_insert(key, val)
+        self.priv_balancing_insert::<Idx>(key, val)
     }
 
     /// Insert a key-value pair into the tree.
@@ -196,67 +175,50 @@ impl<K: Ord, V> SGTree<K, V> {
     /// * `None` if the tree did not have this key present.
     /// * The old value if the tree did have this key present (both the value and key are updated,
     /// this accommodates types that can be `==` without being identical).
-    #[cfg(feature = "high_assurance")]
-    pub fn insert(&mut self, key: K, val: V) -> Result<Option<V>, SGErr>
+    pub fn try_insert(&mut self, key: K, val: V) -> Result<Option<V>, SgError>
     where
         K: Ord,
     {
-        match self.capacity() > self.len() {
-            true => Ok(self.priv_balancing_insert(key, val)),
-            false => Err(SGErr::StackCapacityExceeded),
+        // Replace current slot or safely fill a new one
+        match self.contains_key(&key) || (self.capacity() > self.len()) {
+            true => Ok(self.priv_balancing_insert::<Idx>(key, val)),
+            false => Err(SgError::StackCapacityExceeded),
+        }
+    }
+
+    // Attempt to extend a collection with the contents of an iterator.
+    pub fn try_extend<I: ExactSizeIterator + IntoIterator<Item = (K, V)>>(
+        &mut self,
+        iter: I,
+    ) -> Result<(), SgError> {
+        if iter.len() <= (self.capacity() - self.len()) {
+            iter.into_iter().for_each(move |(k, v)| {
+                assert!(self.try_insert(k, v).is_ok());
+            });
+            Ok(())
+        } else {
+            Err(SgError::StackCapacityExceeded)
+        }
+    }
+
+    // Attempt conversion from an iterator.
+    /// Will fail if iterator length exceeds `u16::MAX`.
+    pub fn try_from_iter<I: ExactSizeIterator + IntoIterator<Item = (K, V)>>(
+        iter: I,
+    ) -> Result<Self, SgError> {
+        match iter.len() <= SgTree::<K, V, N>::max_capacity() {
+            true => Ok(SgTree::from_iter(iter)),
+            false => Err(SgError::MaximumCapacityExceeded),
         }
     }
 
     /// Gets an iterator over the entries of the tree, sorted by key.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use scapegoat::SGTree;
-    ///
-    /// let mut tree = SGTree::new();
-    /// tree.insert(3, "c");
-    /// tree.insert(2, "b");
-    /// tree.insert(1, "a");
-    ///
-    /// for (key, value) in tree.iter() {
-    ///     println!("{}: {}", key, value);
-    /// }
-    ///
-    /// let (first_key, first_value) = tree.iter().next().unwrap();
-    /// assert_eq!((*first_key, *first_value), (1, "a"));
-    /// ```
-    pub fn iter(&self) -> Iter<'_, K, V> {
+    pub fn iter(&self) -> Iter<'_, K, V, N> {
         Iter::new(self)
     }
 
     /// Gets a mutable iterator over the entries of the tree, sorted by key.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// use scapegoat::SGTree;
-    ///
-    /// let mut tree = SGTree::new();
-    /// tree.insert("a", 1);
-    /// tree.insert("b", 2);
-    /// tree.insert("c", 3);
-    ///
-    /// // Add 10 to the value if the key isn't "a"
-    /// for (key, value) in tree.iter_mut() {
-    ///     if key != &"a" {
-    ///         *value += 10;
-    ///     }
-    /// }
-    ///
-    /// let (second_key, second_value) = tree.iter().skip(1).next().unwrap();
-    /// assert_eq!((*second_key, *second_value), ("b", 12));
-    /// ```
-    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
+    pub fn iter_mut(&mut self) -> IterMut<'_, K, V, N> {
         IterMut::new(self)
     }
 
@@ -270,14 +232,14 @@ impl<K: Ord, V> SGTree<K, V> {
         Q: Ord + ?Sized,
     {
         match self.priv_remove_by_key(key) {
-            Some(node) => {
+            Some((key, val)) => {
                 if self.max_size > (2 * self.curr_size) {
-                    if let Some(root_idx) = self.root_idx {
-                        self.rebuild(root_idx);
+                    if let Some(root_idx) = self.opt_root_idx {
+                        self.rebuild::<Idx>(root_idx);
                         self.max_size = self.curr_size;
                     }
                 }
-                Some((node.key, node.val))
+                Some((key, val))
             }
             None => None,
         }
@@ -322,11 +284,11 @@ impl<K: Ord, V> SGTree<K, V> {
         K: Borrow<Q> + Ord,
         Q: Ord + ?Sized,
     {
-        let ngh = self.priv_get(None, key);
-        match ngh.node_idx {
+        let ngh: NodeGetHelper<Idx> = self.priv_get(None, key);
+        match ngh.node_idx() {
             Some(idx) => {
-                let node = self.arena.hard_get(idx);
-                Some((&node.key, &node.val))
+                let node = &self.arena[idx];
+                Some((node.key(), node.val()))
             }
             None => None,
         }
@@ -353,11 +315,11 @@ impl<K: Ord, V> SGTree<K, V> {
         K: Borrow<Q> + Ord,
         Q: Ord + ?Sized,
     {
-        let ngh = self.priv_get(None, key);
-        match ngh.node_idx {
+        let ngh: NodeGetHelper<Idx> = self.priv_get(None, key);
+        match ngh.node_idx() {
             Some(idx) => {
-                let node = self.arena.hard_get_mut(idx);
-                Some(&mut node.val)
+                let (_, val) = self.arena[idx].get_mut();
+                Some(val)
             }
             None => None,
         }
@@ -367,7 +329,7 @@ impl<K: Ord, V> SGTree<K, V> {
     pub fn clear(&mut self) {
         if !self.is_empty() {
             let rebal_cnt = self.rebal_cnt;
-            *self = SGTree::new();
+            *self = SgTree::new();
             self.rebal_cnt = rebal_cnt;
         }
     }
@@ -386,7 +348,13 @@ impl<K: Ord, V> SGTree<K, V> {
 
     /// Returns `true` if the tree contains no elements.
     pub fn is_empty(&self) -> bool {
-        self.root_idx.is_none()
+        self.opt_root_idx.is_none()
+    }
+
+    /// Returns `true` if the tree's capacity is filled.
+    pub fn is_full(&self) -> bool {
+        debug_assert!(self.len() <= self.capacity());
+        self.len() == self.capacity()
     }
 
     /// Returns a reference to the first key-value pair in the tree.
@@ -395,9 +363,12 @@ impl<K: Ord, V> SGTree<K, V> {
     where
         K: Ord,
     {
-        self.arena
-            .get(self.min_idx)
-            .map(|node| (&node.key, &node.val))
+        if !self.is_empty() {
+            let node = &self.arena[self.min_idx];
+            Some((node.key(), node.val()))
+        } else {
+            None
+        }
     }
 
     /// Returns a reference to the first/minium key in the tree, if any.
@@ -414,10 +385,7 @@ impl<K: Ord, V> SGTree<K, V> {
     where
         K: Ord,
     {
-        match self.priv_remove_by_idx(self.min_idx) {
-            Some(node) => Some((node.key, node.val)),
-            None => None,
-        }
+        self.priv_remove_by_idx(self.min_idx)
     }
 
     /// Returns a reference to the last key-value pair in the tree.
@@ -426,9 +394,12 @@ impl<K: Ord, V> SGTree<K, V> {
     where
         K: Ord,
     {
-        self.arena
-            .get(self.max_idx)
-            .map(|node| (&node.key, &node.val))
+        if !self.is_empty() {
+            let node = &self.arena[self.max_idx];
+            Some((node.key(), node.val()))
+        } else {
+            None
+        }
     }
 
     /// Returns a reference to the last/maximum key in the tree, if any.
@@ -445,15 +416,12 @@ impl<K: Ord, V> SGTree<K, V> {
     where
         K: Ord,
     {
-        match self.priv_remove_by_idx(self.max_idx) {
-            Some(node) => Some((node.key, node.val)),
-            None => None,
-        }
+        self.priv_remove_by_idx(self.max_idx)
     }
 
     /// Returns the number of elements in the tree.
     pub fn len(&self) -> usize {
-        self.curr_size as usize
+        self.curr_size
     }
 
     /// Get the number of times this tree rebalanced itself (for testing and/or performance engineering).
@@ -467,108 +435,127 @@ impl<K: Ord, V> SGTree<K, V> {
     // Remove a node by index.
     // A wrapper for by-key removal, traversal is still required to determine node parent.
     #[cfg(not(feature = "fast_rebalance"))]
-    pub(crate) fn priv_remove_by_idx(&mut self, idx: Idx) -> Option<Node<K, V>> {
-        match self.arena.get(idx) {
-            Some(node) => {
-                let ngh = self.priv_get(None, &node.key);
-                debug_assert!(
-                    ngh.node_idx.unwrap() == idx,
-                    "By-key retrieval index doesn't match arena storage index!"
-                );
-                self.priv_remove(None, ngh)
-            }
-            None => None,
+    pub(crate) fn priv_remove_by_idx(&mut self, idx: usize) -> Option<(K, V)> {
+        if self.arena.is_occupied(idx) {
+            let node = &self.arena[idx];
+            let ngh: NodeGetHelper<Idx> = self.priv_get(None, node.key());
+            debug_assert!(
+                ngh.node_idx().unwrap() == idx,
+                "By-key retrieval index doesn't match arena storage index!"
+            );
+            self.priv_remove(None, ngh)
+        } else {
+            None
         }
     }
 
     // Remove a node by index.
     // A wrapper for by-key removal, traversal is still required to determine node parent.
     #[cfg(feature = "fast_rebalance")]
-    pub(crate) fn priv_remove_by_idx(&mut self, idx: Idx) -> Option<Node<K, V>> {
-        match self.arena.get(idx) {
-            Some(node) => {
-                let mut path = IdxVec::new();
-                let ngh = self.priv_get(Some(&mut path), &node.key);
-                debug_assert!(
-                    ngh.node_idx.unwrap() == idx,
-                    "By-key retrieval index doesn't match arena storage index!"
-                );
-                self.priv_remove(Some(&path), ngh)
-            }
-            None => None,
+    pub(crate) fn priv_remove_by_idx(&mut self, idx: usize) -> Option<(K, V)> {
+        if self.arena.is_occupied(idx) {
+            let node = &self.arena[idx];
+            let mut path = Arena::<K, V, Idx, N>::new_idx_vec();
+            let ngh = self.priv_get(Some(&mut path), node.key());
+            debug_assert!(
+                ngh.node_idx().unwrap() == idx,
+                "By-key retrieval index doesn't match arena storage index!"
+            );
+            self.priv_remove(Some(&path), ngh)
+        } else {
+            None
         }
     }
 
-    // Flatten subtree into array of node indexs sorted by node key
-    pub(crate) fn flatten_subtree_to_sorted_idxs(&self, idx: Idx) -> IdxVec {
-        let mut subtree_node_idx_pairs: SortNodeRefIdxPairVec<K, V> =
-            smallvec![(self.arena.hard_get(idx), idx)];
-        let mut subtree_worklist: SortNodeRefVec<K, V> = smallvec![self.arena.hard_get(idx)];
-
-        while let Some(node) = subtree_worklist.pop() {
-            if let Some(left_idx) = node.left_idx {
-                let left_child_node = self.arena.hard_get(left_idx);
-                subtree_node_idx_pairs.push((left_child_node, left_idx));
-                subtree_worklist.push(left_child_node);
+    // Flatten subtree into array of node indexes sorted by node key
+    pub(crate) fn flatten_subtree_to_sorted_idxs<U: SmallUnsigned + Default + Copy>(
+        &self,
+        idx: usize,
+    ) -> ArrayVec<[U; N]> {
+        let mut subtree_worklist = array_vec![[U; N] => U::checked_from(idx)];
+        let mut subtree_flattened = array_vec![[U; N] => U::checked_from(idx)];
+
+        while let Some(idx) = subtree_worklist.pop() {
+            let node = &self.arena[idx.usize()];
+
+            if let Some(left_idx) = node.left_idx() {
+                let left = U::checked_from(left_idx);
+                subtree_worklist.push(left);
+                subtree_flattened.push(left);
             }
 
-            if let Some(right_idx) = node.right_idx {
-                let right_child_node = self.arena.hard_get(right_idx);
-                subtree_node_idx_pairs.push((right_child_node, right_idx));
-                subtree_worklist.push(right_child_node);
+            if let Some(right_idx) = node.right_idx() {
+                let right = U::checked_from(right_idx);
+                subtree_worklist.push(right);
+                subtree_flattened.push(right);
             }
         }
 
-        // Sort by Node key
+        // Sort by key
         // Faster than sort_by() but may not preserve order of equal elements - OK b/c tree won't have equal nodes
-        subtree_node_idx_pairs.sort_unstable_by(|a, b| a.0.key.cmp(&b.0.key));
+        subtree_flattened
+            .sort_unstable_by(|a, b| self.arena[a.usize()].key().cmp(self.arena[b.usize()].key()));
 
-        subtree_node_idx_pairs.iter().map(|(_, idx)| *idx).collect()
+        subtree_flattened
     }
 
     /// Sort the internal arena such that logically contiguous nodes are in-order (by key).
     pub(crate) fn sort_arena(&mut self) {
-        if let Some(root_idx) = self.root_idx {
+        if let Some(root_idx) = self.opt_root_idx {
             let mut sort_metadata = self
                 .arena
                 .iter()
                 .filter(|n| n.is_some())
                 .map(|n| n.as_ref().unwrap())
-                .map(|n| self.priv_get(None, &n.key))
-                .collect::<SortMetaVec>();
+                .map(|n| self.priv_get(None, n.key()))
+                .collect::<ArrayVec<[NodeGetHelper<usize>; N]>>();
 
-            sort_metadata.sort_by_key(|ngh| &self.arena.hard_get(ngh.node_idx.unwrap()).key);
+            sort_metadata.sort_unstable_by_key(|ngh| self.arena[ngh.node_idx().unwrap()].key());
             let sorted_root_idx = self.arena.sort(root_idx, sort_metadata);
 
-            self.root_idx = Some(sorted_root_idx);
+            self.opt_root_idx = Some(sorted_root_idx);
             self.update_max_idx();
             self.update_min_idx();
         }
     }
 
+    /// Total common elements between two trees
+    pub(crate) fn intersect_cnt(&self, other: &SgTree<K, V, N>) -> usize {
+        self.iter().filter(|(k, _)| other.contains_key(k)).count()
+    }
+
+    // Maximum tree capacity (const N value).
+    pub(crate) fn max_capacity() -> usize {
+        Idx::MAX as usize
+    }
+
     // Private API -----------------------------------------------------------------------------------------------------
 
     // Iterative search. If key found, returns node idx, parent idx, and a bool indicating if node is right child
     // `opt_path` is only populated if `Some` and key is found.
-    fn priv_get<Q>(&self, mut opt_path: Option<&mut IdxVec>, key: &Q) -> NodeGetHelper
+    fn priv_get<Q, U: SmallUnsigned + Default + Copy>(
+        &self,
+        mut opt_path: Option<&mut ArrayVec<[U; N]>>,
+        key: &Q,
+    ) -> NodeGetHelper<U>
     where
         K: Borrow<Q> + Ord,
         Q: Ord + ?Sized,
     {
-        match self.root_idx {
+        match self.opt_root_idx {
             Some(root_idx) => {
                 let mut opt_parent_idx = None;
                 let mut curr_idx = root_idx;
                 let mut is_right_child = false;
                 loop {
-                    let node = self.arena.hard_get(curr_idx);
+                    let node = &self.arena[curr_idx];
 
                     if let Some(ref mut path) = opt_path {
-                        path.push(curr_idx);
+                        path.push(U::checked_from(curr_idx));
                     }
 
-                    match key.cmp(node.key.borrow()) {
-                        Ordering::Less => match node.left_idx {
+                    match key.cmp(node.key().borrow()) {
+                        Ordering::Less => match node.left_idx() {
                             Some(lt_idx) => {
                                 opt_parent_idx = Some(curr_idx);
                                 curr_idx = lt_idx;
@@ -593,7 +580,7 @@ impl<K: Ord, V> SGTree<K, V> {
                                 is_right_child,
                             );
                         }
-                        Ordering::Greater => match node.right_idx {
+                        Ordering::Greater => match node.right_idx() {
                             Some(gt_idx) => {
                                 opt_parent_idx = Some(curr_idx);
                                 curr_idx = gt_idx;
@@ -616,26 +603,27 @@ impl<K: Ord, V> SGTree<K, V> {
 
     // Sorted insert of node into the tree (outer).
     // Re-balances the tree if necessary.
-    fn priv_balancing_insert(&mut self, key: K, val: V) -> Option<V> {
-        let mut path = IdxVec::new();
-        let new_node = Node::new(key, val);
-
-        // Insert
-        let opt_val = self.priv_insert(&mut path, new_node);
+    fn priv_balancing_insert<U: Default + Copy + Ord + Sub + SmallUnsigned>(
+        &mut self,
+        key: K,
+        val: V,
+    ) -> Option<V> {
+        let mut path: ArrayVec<[U; N]> = Arena::<K, V, U, N>::new_idx_vec();
+        let opt_val = self.priv_insert(&mut path, key, val);
 
         #[cfg(feature = "fast_rebalance")]
         {
             // Update subtree sizes
             for parent_idx in &path {
-                let parent_node = self.arena.hard_get_mut(*parent_idx);
-                parent_node.subtree_size += 1;
+                let parent_node = &mut self.arena[(*parent_idx).usize()];
+                parent_node.set_subtree_size(parent_node.subtree_size() + 1);
             }
         }
 
         // Potential rebalance
         if path.len() > self.alpha_balance_depth(self.max_size) {
             if let Some(scapegoat_idx) = self.find_scapegoat(&path) {
-                self.rebuild(scapegoat_idx);
+                self.rebuild::<U>(scapegoat_idx);
             }
         }
 
@@ -645,32 +633,37 @@ impl<K: Ord, V> SGTree<K, V> {
     // Sorted insert of node into the tree (inner).
     // Maintains a traversal path to avoid nodes needing to maintain a parent index.
     // If a node with the same key existed, overwrites both that nodes key and value with the new one's and returns the old value.
-    fn priv_insert(&mut self, path: &mut IdxVec, new_node: Node<K, V>) -> Option<V> {
-        match self.root_idx {
+    fn priv_insert<U: SmallUnsigned + Default + Copy>(
+        &mut self,
+        path: &mut ArrayVec<[U; N]>,
+        key: K,
+        val: V,
+    ) -> Option<V> {
+        match self.opt_root_idx {
             // Sorted insert
             Some(idx) => {
                 // Iterative traversal
                 let mut curr_idx = idx;
                 let mut opt_val = None;
-                let ngh;
+                let ngh: NodeGetHelper<U>;
                 loop {
-                    let mut curr_node = self.arena.hard_get_mut(curr_idx);
-                    path.push(curr_idx);
+                    let curr_node = &mut self.arena[curr_idx];
+                    path.push(U::checked_from(curr_idx));
 
-                    match &new_node.key.cmp(&curr_node.key) {
+                    match key.cmp(curr_node.key()) {
                         Ordering::Less => {
-                            match curr_node.left_idx {
+                            match curr_node.left_idx() {
                                 Some(left_idx) => curr_idx = left_idx,
                                 None => {
                                     // New min check
                                     let mut new_min_found = false;
-                                    let min_node = self.arena.hard_get(self.min_idx);
-                                    if new_node.key < min_node.key {
+                                    let min_node = &self.arena[self.min_idx];
+                                    if &key < min_node.key() {
                                         new_min_found = true;
                                     }
 
                                     // Left insert
-                                    let new_node_idx = self.arena.add(new_node);
+                                    let new_node_idx = self.arena.add(key, val);
 
                                     // New min update
                                     if new_min_found {
@@ -687,24 +680,30 @@ impl<K: Ord, V> SGTree<K, V> {
                             }
                         }
                         Ordering::Equal => {
-                            curr_node.key = new_node.key; // Necessary b/c Eq may not consider all struct members
-                            opt_val = Some(mem::replace(&mut curr_node.val, new_node.val)); // Overwrite value
+                            // Replacing key necessary b/c custom Eq impl may not consider all K's fields
+                            curr_node.set_key(key);
+
+                            // Replacing val necessary b/c it may be different
+                            opt_val = Some(curr_node.take_val());
+                            curr_node.set_val(val);
+
+                            // Key/val updated "in-place": no need to update `curr_node`'s parent or children
                             ngh = NodeGetHelper::new(None, None, false);
                             break;
                         }
                         Ordering::Greater => {
-                            match curr_node.right_idx {
+                            match curr_node.right_idx() {
                                 Some(right_idx) => curr_idx = right_idx,
                                 None => {
                                     // New max check
                                     let mut new_max_found = false;
-                                    let max_node = self.arena.hard_get(self.max_idx);
-                                    if new_node.key > max_node.key {
+                                    let max_node = &self.arena[self.max_idx];
+                                    if &key > max_node.key() {
                                         new_max_found = true;
                                     }
 
                                     // Right insert
-                                    let new_node_idx = self.arena.add(new_node);
+                                    let new_node_idx = self.arena.add(key, val);
 
                                     // New max update
                                     if new_max_found {
@@ -724,15 +723,15 @@ impl<K: Ord, V> SGTree<K, V> {
                 }
 
                 // Link to parent
-                if let Some(parent_idx) = ngh.parent_idx {
+                if let Some(parent_idx) = ngh.parent_idx() {
                     self.curr_size += 1;
                     self.max_size += 1;
 
-                    let parent_node = self.arena.hard_get_mut(parent_idx);
-                    if ngh.is_right_child {
-                        parent_node.right_idx = ngh.node_idx;
+                    let parent_node = &mut self.arena[parent_idx];
+                    if ngh.is_right_child() {
+                        parent_node.set_right_idx(ngh.node_idx());
                     } else {
-                        parent_node.left_idx = ngh.node_idx;
+                        parent_node.set_left_idx(ngh.node_idx());
                     }
                 }
 
@@ -746,8 +745,8 @@ impl<K: Ord, V> SGTree<K, V> {
                 self.curr_size += 1;
                 self.max_size += 1;
 
-                let root_idx = self.arena.add(new_node);
-                self.root_idx = Some(root_idx);
+                let root_idx = self.arena.add(key, val);
+                self.opt_root_idx = Some(root_idx);
                 self.max_idx = root_idx;
                 self.min_idx = root_idx;
 
@@ -758,37 +757,41 @@ impl<K: Ord, V> SGTree<K, V> {
 
     // Remove a node by key.
     #[cfg(not(feature = "fast_rebalance"))]
-    fn priv_remove_by_key<Q>(&mut self, key: &Q) -> Option<Node<K, V>>
+    fn priv_remove_by_key<Q>(&mut self, key: &Q) -> Option<(K, V)>
     where
         K: Borrow<Q> + Ord,
         Q: Ord + ?Sized,
     {
-        let ngh = self.priv_get(None, key);
+        let ngh: NodeGetHelper<Idx> = self.priv_get(None, key);
         self.priv_remove(None, ngh)
     }
 
     // Remove a node by key.
     #[cfg(feature = "fast_rebalance")]
-    fn priv_remove_by_key<Q>(&mut self, key: &Q) -> Option<Node<K, V>>
+    fn priv_remove_by_key<Q>(&mut self, key: &Q) -> Option<(K, V)>
     where
         K: Borrow<Q> + Ord,
         Q: Ord + ?Sized,
     {
-        let mut path = IdxVec::new();
+        let mut path = Arena::<K, V, Idx, N>::new_idx_vec();
         let ngh = self.priv_get(Some(&mut path), key);
         self.priv_remove(Some(&path), ngh)
     }
 
     // Remove a node from the tree, re-linking remaining nodes as necessary.
     #[allow(unused_variables)] // `opt_path` only used when feature `fast_rebalance` is enabled
-    fn priv_remove(&mut self, opt_path: Option<&IdxVec>, ngh: NodeGetHelper) -> Option<Node<K, V>> {
-        match ngh.node_idx {
+    fn priv_remove<U: SmallUnsigned + Default + Copy>(
+        &mut self,
+        opt_path: Option<&ArrayVec<[U; N]>>,
+        ngh: NodeGetHelper<U>,
+    ) -> Option<(K, V)> {
+        match ngh.node_idx() {
             Some(node_idx) => {
-                let node_to_remove = self.arena.hard_get(node_idx);
+                let node_to_remove = &self.arena[node_idx];
 
                 // Copy out child indexes to reduce scope of above immutable borrow
-                let node_to_remove_left_idx = node_to_remove.left_idx;
-                let mut node_to_remove_right_idx = node_to_remove.right_idx;
+                let node_to_remove_left_idx = node_to_remove.left_idx();
+                let mut node_to_remove_right_idx = node_to_remove.right_idx();
 
                 let new_child = match (node_to_remove_left_idx, node_to_remove_right_idx) {
                     // No children
@@ -806,30 +809,31 @@ impl<K: Ord, V> SGTree<K, V> {
                         let mut min_parent_idx = node_idx;
 
                         #[cfg(feature = "fast_rebalance")]
-                        let min_node_subtree_size = node_to_remove.subtree_size - 1;
+                        let min_node_subtree_size = node_to_remove.subtree_size() - 1;
 
                         loop {
-                            let min_node = self.arena.hard_get(min_idx);
-                            match min_node.left_idx {
+                            let min_node = &self.arena[min_idx];
+                            match min_node.left_idx() {
                                 // Continue search for min node
                                 Some(lt_idx) => {
                                     min_parent_idx = min_idx;
                                     min_idx = lt_idx;
                                 }
                                 // Min node found, unlink it
-                                None => match min_node.right_idx {
+                                None => match min_node.right_idx() {
                                     Some(_) => {
-                                        let unlink_new_child = min_node.right_idx;
+                                        let unlink_new_child = min_node.right_idx();
                                         if min_parent_idx == node_idx {
                                             node_to_remove_right_idx = unlink_new_child;
                                         } else {
-                                            let min_parent_node =
-                                                self.arena.hard_get_mut(min_parent_idx);
-                                            min_parent_node.left_idx = unlink_new_child;
+                                            let min_parent_node = &mut self.arena[min_parent_idx];
+                                            min_parent_node.set_left_idx(unlink_new_child);
 
                                             #[cfg(feature = "fast_rebalance")]
                                             {
-                                                min_parent_node.subtree_size -= 1;
+                                                min_parent_node.set_subtree_size(
+                                                    min_parent_node.subtree_size() - 1,
+                                                );
                                             }
                                         }
                                         break;
@@ -838,13 +842,14 @@ impl<K: Ord, V> SGTree<K, V> {
                                         if min_parent_idx == node_idx {
                                             node_to_remove_right_idx = None;
                                         } else {
-                                            let min_parent_node =
-                                                self.arena.hard_get_mut(min_parent_idx);
-                                            min_parent_node.left_idx = None;
+                                            let min_parent_node = &mut self.arena[min_parent_idx];
+                                            min_parent_node.set_left_idx(None);
 
                                             #[cfg(feature = "fast_rebalance")]
                                             {
-                                                min_parent_node.subtree_size -= 1;
+                                                min_parent_node.set_subtree_size(
+                                                    min_parent_node.subtree_size() - 1,
+                                                );
                                             }
                                         }
                                         break;
@@ -854,13 +859,13 @@ impl<K: Ord, V> SGTree<K, V> {
                         }
 
                         // Re-link min node to removed node's children
-                        let min_node = self.arena.hard_get_mut(min_idx);
-                        min_node.right_idx = node_to_remove_right_idx;
-                        min_node.left_idx = node_to_remove_left_idx;
+                        let min_node = &mut self.arena[min_idx];
+                        min_node.set_right_idx(node_to_remove_right_idx);
+                        min_node.set_left_idx(node_to_remove_left_idx);
 
                         #[cfg(feature = "fast_rebalance")]
                         {
-                            min_node.subtree_size = min_node_subtree_size;
+                            min_node.set_subtree_size(min_node_subtree_size);
                         }
 
                         // Return as new child
@@ -869,22 +874,22 @@ impl<K: Ord, V> SGTree<K, V> {
                 };
 
                 // Update parent or root
-                match ngh.parent_idx {
+                match ngh.parent_idx() {
                     Some(parent_idx) => {
-                        let parent_node = self.arena.hard_get_mut(parent_idx);
-                        if ngh.is_right_child {
-                            parent_node.right_idx = new_child;
+                        let parent_node = &mut self.arena[parent_idx];
+                        if ngh.is_right_child() {
+                            parent_node.set_right_idx(new_child);
                         } else {
-                            parent_node.left_idx = new_child;
+                            parent_node.set_left_idx(new_child);
                         }
                     }
                     None => {
-                        self.root_idx = new_child;
+                        self.opt_root_idx = new_child;
                     }
                 }
 
                 // Perform removal
-                let removed_node = self.arena.hard_remove(node_idx);
+                let mut removed_node = self.arena.hard_remove(node_idx);
                 self.curr_size -= 1;
 
                 // Update min/max
@@ -900,14 +905,14 @@ impl<K: Ord, V> SGTree<K, V> {
                     debug_assert!(opt_path.is_some());
                     if let Some(path) = opt_path {
                         for parent_idx in path {
-                            let parent_node = self.arena.hard_get_mut(*parent_idx);
-                            debug_assert!(parent_node.subtree_size > 1);
-                            parent_node.subtree_size -= 1;
+                            let parent_node = &mut self.arena[(*parent_idx).usize()];
+                            debug_assert!(parent_node.subtree_size() > 1);
+                            parent_node.set_subtree_size(parent_node.subtree_size() - 1);
                         }
                     }
                 }
 
-                Some(removed_node)
+                Some((removed_node.take_key(), removed_node.take_val()))
             }
             None => None,
         }
@@ -931,17 +936,17 @@ impl<K: Ord, V> SGTree<K, V> {
 
         // TODO: this implementation is rather inefficient!
 
-        let mut key_idxs = IdxVec::new();
-        let mut remove_idxs = IdxVec::new();
+        let mut key_idxs = Arena::<K, V, Idx, N>::new_idx_vec();
+        let mut remove_idxs = Arena::<K, V, Idx, N>::new_idx_vec();
 
         // Below iter_mut() will want to sort, require want consistent indexes, so do work up front
         self.sort_arena();
 
         // Safely treat mutable ref as immutable, init list of node's arena indexes
         for (k, _) in &(*self) {
-            let ngh = self.priv_get(None, k.borrow());
-            debug_assert!(ngh.node_idx.is_some());
-            key_idxs.push(ngh.node_idx.unwrap());
+            let ngh: NodeGetHelper<Idx> = self.priv_get(None, k.borrow());
+            debug_assert!(ngh.node_idx().is_some());
+            key_idxs.push(Idx::checked_from(ngh.node_idx().unwrap()));
         }
 
         // Filter arena index list to those not matching predicate
@@ -954,15 +959,10 @@ impl<K: Ord, V> SGTree<K, V> {
         // Drain non-matches
         let mut drained_sgt = Self::new();
         for i in remove_idxs {
-            if let Some(node) = self.priv_remove_by_idx(i) {
-                #[cfg(not(feature = "high_assurance"))]
-                {
-                    drained_sgt.insert(node.key, node.val);
-                }
-                #[cfg(feature = "high_assurance")]
-                {
-                    assert!(drained_sgt.insert(node.key, node.val).is_ok());
-                }
+            if let Some((k, v)) = self.priv_remove_by_idx(i.usize()) {
+                drained_sgt
+                    .try_insert(k, v)
+                    .expect("Stack-storage capacity exceeded!");
             }
         }
 
@@ -971,12 +971,12 @@ impl<K: Ord, V> SGTree<K, V> {
 
     /// Minimum update without recursion
     fn update_min_idx(&mut self) {
-        match self.root_idx {
+        match self.opt_root_idx {
             Some(root_idx) => {
                 let mut curr_idx = root_idx;
                 loop {
-                    let node = self.arena.hard_get(curr_idx);
-                    match node.left_idx {
+                    let node = &self.arena[curr_idx];
+                    match node.left_idx() {
                         Some(lt_idx) => curr_idx = lt_idx,
                         None => {
                             self.min_idx = curr_idx;
@@ -991,12 +991,12 @@ impl<K: Ord, V> SGTree<K, V> {
 
     /// Maximum update without recursion
     fn update_max_idx(&mut self) {
-        match self.root_idx {
+        match self.opt_root_idx {
             Some(root_idx) => {
                 let mut curr_idx = root_idx;
                 loop {
-                    let node = self.arena.hard_get(curr_idx);
-                    match node.right_idx {
+                    let node = &self.arena[curr_idx];
+                    match node.right_idx() {
                         Some(gt_idx) => curr_idx = gt_idx,
                         None => {
                             self.max_idx = curr_idx;
@@ -1012,14 +1012,14 @@ impl<K: Ord, V> SGTree<K, V> {
     // Traverse upward, using path information, to find first unbalanced parent.
     // Uses the algorithm proposed in the original paper (Galperin and Rivest, 1993).
     #[cfg(not(feature = "alt_impl"))]
-    fn find_scapegoat(&self, path: &[Idx]) -> Option<Idx> {
+    fn find_scapegoat<U: SmallUnsigned + Default>(&self, path: &[U]) -> Option<usize> {
         if path.len() <= 1 {
             return None;
         }
 
         let mut node_subtree_size = 1; // Newly inserted
         let mut parent_path_idx = path.len() - 1; // Parent of newly inserted
-        let mut parent_subtree_size = self.get_subtree_size(path[parent_path_idx]);
+        let mut parent_subtree_size = self.get_subtree_size::<U>(path[parent_path_idx].usize());
 
         while (parent_path_idx > 0)
             && (self.alpha_denom * node_subtree_size as f32)
@@ -1027,22 +1027,22 @@ impl<K: Ord, V> SGTree<K, V> {
         {
             node_subtree_size = parent_subtree_size;
             parent_path_idx -= 1;
-            parent_subtree_size = self.get_subtree_size_differential(
-                path[parent_path_idx],     // Parent index
-                path[parent_path_idx + 1], // Child index
-                node_subtree_size,         // Child subtree size
+            parent_subtree_size = self.get_subtree_size_differential::<U>(
+                path[parent_path_idx].usize(),     // Parent index
+                path[parent_path_idx + 1].usize(), // Child index
+                node_subtree_size,                 // Child subtree size
             );
 
             debug_assert!(parent_subtree_size > node_subtree_size);
         }
 
-        Some(path[parent_path_idx])
+        Some(path[parent_path_idx].usize())
     }
 
     // Traverse upward, using path information, to find first unbalanced parent.
     // Uses an alternate algorithm proposed in Galperin's PhD thesis (1996).
     #[cfg(feature = "alt_impl")]
-    fn find_scapegoat(&self, path: &[Idx]) -> Option<Idx> {
+    fn find_scapegoat<U: SmallUnsigned>(&self, path: &[U]) -> Option<usize> {
         if path.len() <= 1 {
             return None;
         }
@@ -1050,39 +1050,40 @@ impl<K: Ord, V> SGTree<K, V> {
         let mut i = 0;
         let mut node_subtree_size = 1; // Newly inserted
         let mut parent_path_idx = path.len() - 1; // Parent of newly inserted
-        let mut parent_subtree_size = self.get_subtree_size(path[parent_path_idx]);
+        let mut parent_subtree_size = self.get_subtree_size::<U>(path[parent_path_idx].usize());
 
         while (parent_path_idx > 0) && (i <= self.alpha_balance_depth(node_subtree_size)) {
             node_subtree_size = parent_subtree_size;
             parent_path_idx -= 1;
             i += 1;
-            parent_subtree_size = self.get_subtree_size_differential(
-                path[parent_path_idx],     // Parent index
-                path[parent_path_idx + 1], // Child index
-                node_subtree_size,         // Child subtree size
+            parent_subtree_size = self.get_subtree_size_differential::<U>(
+                path[parent_path_idx].usize(),     // Parent index
+                path[parent_path_idx + 1].usize(), // Child index
+                node_subtree_size,                 // Child subtree size
             );
 
             debug_assert!(parent_subtree_size > node_subtree_size);
         }
 
-        Some(path[parent_path_idx])
+        Some(path[parent_path_idx].usize())
     }
 
     // Iterative subtree size computation
     #[cfg(not(feature = "fast_rebalance"))]
-    fn get_subtree_size(&self, idx: Idx) -> Idx {
-        let mut subtree_worklist: SortNodeRefVec<K, V> = smallvec![self.arena.hard_get(idx)];
+    fn get_subtree_size<U: SmallUnsigned + Default>(&self, idx: usize) -> usize {
+        let mut subtree_worklist = array_vec![[U; N] => U::checked_from(idx)];
         let mut subtree_size = 0;
 
-        while let Some(node) = subtree_worklist.pop() {
+        while let Some(idx) = subtree_worklist.pop() {
+            let node = &self.arena[idx.usize()];
             subtree_size += 1;
 
-            if let Some(left_idx) = node.left_idx {
-                subtree_worklist.push(self.arena.hard_get(left_idx));
+            if let Some(left_idx) = node.left_idx() {
+                subtree_worklist.push(U::checked_from(left_idx));
             }
 
-            if let Some(right_idx) = node.right_idx {
-                subtree_worklist.push(self.arena.hard_get(right_idx));
+            if let Some(right_idx) = node.right_idx() {
+                subtree_worklist.push(U::checked_from(right_idx));
             }
         }
 
@@ -1091,46 +1092,49 @@ impl<K: Ord, V> SGTree<K, V> {
 
     // Retrieve cached subtree size
     #[cfg(feature = "fast_rebalance")]
-    fn get_subtree_size(&self, idx: Idx) -> Idx {
-        self.arena.hard_get(idx).subtree_size
+    fn get_subtree_size<U: SmallUnsigned>(&self, idx: usize) -> usize {
+        self.arena[idx].subtree_size()
     }
 
     // Differential subtree size helper
     #[cfg(not(feature = "fast_rebalance"))]
-    fn get_subtree_size_differential(
+    fn get_subtree_size_differential<U: SmallUnsigned + Default>(
         &self,
-        parent_idx: Idx,
-        child_idx: Idx,
-        child_subtree_size: Idx,
-    ) -> Idx {
-        let parent = self.arena.hard_get(parent_idx);
+        parent_idx: usize,
+        child_idx: usize,
+        child_subtree_size: usize,
+    ) -> usize {
+        let parent = &self.arena[parent_idx];
 
         debug_assert!(
-            (parent.right_idx == Some(child_idx)) || (parent.left_idx == Some(child_idx))
+            (parent.right_idx() == Some(child_idx)) || (parent.left_idx() == Some(child_idx))
         );
 
         let mut is_right_child = false;
-        if let Some(right_child_idx) = parent.right_idx {
+        if let Some(right_child_idx) = parent.right_idx() {
             if right_child_idx == child_idx {
                 is_right_child = true;
             }
         }
 
         let other_child_subtree_size = if is_right_child {
-            match parent.left_idx {
-                Some(idx) => self.get_subtree_size(idx),
+            match parent.left_idx() {
+                Some(idx) => self.get_subtree_size::<U>(idx),
                 None => 0,
             }
         } else {
-            match parent.right_idx {
-                Some(idx) => self.get_subtree_size(idx),
+            match parent.right_idx() {
+                Some(idx) => self.get_subtree_size::<U>(idx),
                 None => 0,
             }
         };
 
         let computed_subtree_size = child_subtree_size + other_child_subtree_size + 1;
 
-        debug_assert_eq!(computed_subtree_size, self.get_subtree_size(parent_idx));
+        debug_assert_eq!(
+            computed_subtree_size,
+            self.get_subtree_size::<U>(parent_idx)
+        );
 
         computed_subtree_size
     }
@@ -1138,66 +1142,66 @@ impl<K: Ord, V> SGTree<K, V> {
     // Subtree size helper
     // Size already cached if `fast_rebalance` is enabled, no need for differential logic
     #[cfg(feature = "fast_rebalance")]
-    fn get_subtree_size_differential(
+    fn get_subtree_size_differential<U: SmallUnsigned>(
         &self,
-        parent_idx: Idx,
-        _child_idx: Idx,
-        _child_subtree_size: Idx,
-    ) -> Idx {
-        self.get_subtree_size(parent_idx)
+        parent_idx: usize,
+        _child_idx: usize,
+        _child_subtree_size: usize,
+    ) -> usize {
+        self.get_subtree_size::<U>(parent_idx)
     }
 
     // Iterative in-place rebuild for balanced subtree
-    fn rebuild(&mut self, idx: Idx) {
+    fn rebuild<U: Copy + Ord + Sub + SmallUnsigned + Default>(&mut self, idx: usize) {
         let sorted_sub = self.flatten_subtree_to_sorted_idxs(idx);
-        self.rebalance_subtree_from_sorted_idxs(idx, &sorted_sub);
+        self.rebalance_subtree_from_sorted_idxs::<U>(idx, &sorted_sub);
         self.rebal_cnt = self.rebal_cnt.wrapping_add(1);
     }
 
     // Height re-balance of subtree (e.g. depth of the two subtrees of every node never differs by more than one).
     // Adapted from public interview question: https://afteracademy.com/blog/sorted-array-to-balanced-bst
-    fn rebalance_subtree_from_sorted_idxs(
+    fn rebalance_subtree_from_sorted_idxs<U: Copy + Ord + Default + Sub + SmallUnsigned>(
         &mut self,
-        old_subtree_root_idx: Idx,
-        sorted_arena_idxs: &[Idx],
+        old_subtree_root_idx: usize,
+        sorted_arena_idxs: &[usize],
     ) {
         if sorted_arena_idxs.len() <= 1 {
             return;
         }
 
         debug_assert!(
-            self.root_idx.is_some(),
+            self.opt_root_idx.is_some(),
             "Internal invariant failed: rebalance of multi-node tree without root!"
         );
 
-        let sorted_last_idx = (sorted_arena_idxs.len() - 1) as Idx;
+        let sorted_last_idx = sorted_arena_idxs.len() - 1;
         let subtree_root_sorted_idx = sorted_last_idx / 2;
-        let subtree_root_arena_idx = sorted_arena_idxs[subtree_root_sorted_idx.usize()];
-        let mut subtree_worklist = RebuildMetaVec::new();
+        let subtree_root_arena_idx = sorted_arena_idxs[subtree_root_sorted_idx];
+        let mut subtree_worklist = ArrayVec::<[(U, NodeRebuildHelper<U>); N]>::default();
 
         // Init worklist with middle node (balanced subtree root)
         subtree_worklist.push((
-            subtree_root_sorted_idx,
+            U::checked_from(subtree_root_sorted_idx),
             NodeRebuildHelper::new(0, sorted_last_idx),
         ));
 
         // Update tree root or subtree parent
-        if let Some(root_idx) = self.root_idx {
+        if let Some(root_idx) = self.opt_root_idx {
             if sorted_arena_idxs.contains(&root_idx) {
-                self.root_idx = Some(subtree_root_arena_idx);
+                self.opt_root_idx = Some(subtree_root_arena_idx);
             } else {
-                let old_subtree_root = self.arena.hard_get(old_subtree_root_idx);
-                let ngh = self.priv_get(None, &old_subtree_root.key);
+                let old_subtree_root = &self.arena[old_subtree_root_idx];
+                let ngh: NodeGetHelper<U> = self.priv_get(None, old_subtree_root.key());
                 debug_assert!(
-                    ngh.parent_idx.is_some(),
+                    ngh.parent_idx().is_some(),
                     "Internal invariant failed: rebalance of non-root parent-less node!"
                 );
-                if let Some(parent_idx) = ngh.parent_idx {
-                    let parent_node = self.arena.hard_get_mut(parent_idx);
-                    if ngh.is_right_child {
-                        parent_node.right_idx = Some(subtree_root_arena_idx);
+                if let Some(parent_idx) = ngh.parent_idx() {
+                    let parent_node = &mut self.arena[parent_idx];
+                    if ngh.is_right_child() {
+                        parent_node.set_right_idx(Some(subtree_root_arena_idx));
                     } else {
-                        parent_node.left_idx = Some(subtree_root_arena_idx);
+                        parent_node.set_left_idx(Some(subtree_root_arena_idx));
                     }
                 }
             }
@@ -1205,45 +1209,50 @@ impl<K: Ord, V> SGTree<K, V> {
 
         // Iteratively re-assign all children
         while let Some((sorted_idx, parent_nrh)) = subtree_worklist.pop() {
-            let parent_node = self
-                .arena
-                .hard_get_mut(sorted_arena_idxs[sorted_idx.usize()]);
+            let parent_node = &mut self.arena[sorted_arena_idxs[sorted_idx.usize()]];
 
-            parent_node.left_idx = None;
-            parent_node.right_idx = None;
+            parent_node.set_left_idx(None);
+            parent_node.set_right_idx(None);
 
             // Set left child
             if parent_nrh.low_idx < parent_nrh.mid_idx {
-                let child_nrh = NodeRebuildHelper::new(parent_nrh.low_idx, parent_nrh.mid_idx - 1);
-                parent_node.left_idx = Some(sorted_arena_idxs[child_nrh.mid_idx.usize()]);
+                let child_nrh: NodeRebuildHelper<U> = NodeRebuildHelper::new(
+                    parent_nrh.low_idx.usize(),
+                    parent_nrh.mid_idx.usize() - 1,
+                );
+                parent_node.set_left_idx(Some(sorted_arena_idxs[child_nrh.mid_idx.usize()]));
                 subtree_worklist.push((child_nrh.mid_idx, child_nrh));
             }
 
             // Set right child
             if parent_nrh.mid_idx < parent_nrh.high_idx {
-                let child_nrh = NodeRebuildHelper::new(parent_nrh.mid_idx + 1, parent_nrh.high_idx);
-                parent_node.right_idx = Some(sorted_arena_idxs[child_nrh.mid_idx.usize()]);
+                let child_nrh: NodeRebuildHelper<U> = NodeRebuildHelper::new(
+                    parent_nrh.mid_idx.usize() + 1,
+                    parent_nrh.high_idx.usize(),
+                );
+                parent_node.set_right_idx(Some(sorted_arena_idxs[child_nrh.mid_idx.usize()]));
                 subtree_worklist.push((child_nrh.mid_idx, child_nrh));
             }
 
             // Set subtree size
             #[cfg(feature = "fast_rebalance")]
             {
-                parent_node.subtree_size = parent_nrh.high_idx - parent_nrh.low_idx + 1;
-                debug_assert!(parent_node.subtree_size >= 1);
+                parent_node
+                    .set_subtree_size(parent_nrh.high_idx.usize() - parent_nrh.low_idx.usize() + 1);
+                debug_assert!(parent_node.subtree_size() >= 1);
             }
         }
 
         debug_assert!(
-            self.get_subtree_size(subtree_root_arena_idx) == (sorted_arena_idxs.len() as Idx),
+            self.get_subtree_size::<U>(subtree_root_arena_idx) == (sorted_arena_idxs.len()),
             "Internal invariant failed: rebalance changed node count! {} -> {}",
-            self.get_subtree_size(subtree_root_arena_idx),
+            self.get_subtree_size::<U>(subtree_root_arena_idx),
             sorted_arena_idxs.len()
         );
     }
 
     // Alpha weight balance computation helper.
-    fn alpha_balance_depth(&self, val: Idx) -> usize {
+    fn alpha_balance_depth(&self, val: usize) -> usize {
         // log base (1/alpha), hence (denom/num)
         (val as f32).log(self.alpha_denom / self.alpha_num).floor() as usize
     }
@@ -1252,10 +1261,10 @@ impl<K: Ord, V> SGTree<K, V> {
 // Convenience Traits --------------------------------------------------------------------------------------------------
 
 // Debug
-impl<K, V> Debug for SGTree<K, V>
+impl<K, V, const N: usize> Debug for SgTree<K, V, N>
 where
-    K: Ord + Debug,
-    V: Debug,
+    K: Ord + Debug + Default,
+    V: Debug + Default,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_map().entries(self.iter()).finish()
@@ -1263,9 +1272,10 @@ where
 }
 
 // Default
-impl<K, V> Default for SGTree<K, V>
+impl<K, V, const N: usize> Default for SgTree<K, V, N>
 where
-    K: Ord,
+    K: Ord + Default,
+    V: Default,
 {
     fn default() -> Self {
         Self::new()
@@ -1273,27 +1283,51 @@ where
 }
 
 // From array
-impl<K, V, const N: usize> From<[(K, V); N]> for SGTree<K, V>
+impl<K, V, const N: usize> From<[(K, V); N]> for SgTree<K, V, N>
 where
-    K: Ord,
+    K: Ord + Default,
+    V: Default,
 {
-    /// ```
-    /// use scapegoat::SGTree;
-    ///
-    /// let tree1 = SGTree::from([(1, 2), (3, 4)]);
-    /// let tree2: SGTree<_, _> = [(1, 2), (3, 4)].into();
-    /// assert_eq!(tree1, tree2);
-    /// ```
     fn from(arr: [(K, V); N]) -> Self {
-        core::array::IntoIter::new(arr).collect()
+        IntoIterator::into_iter(arr).collect()
+    }
+}
+
+/*
+Error excerpt:
+
+     = note: conflicting implementation in crate `core`:
+             - impl<T, U> TryFrom<U> for T
+               where U: Into<T>;
+
+For more information about this error, try `rustc --explain E0119`.
+
+TODO: Currently a limitation of Rust's trait system? No workaround?
+See issue from 2018: https://github.com/rust-lang/rust/issues/50133#issuecomment-64690839
+
+// TryFrom array
+impl<K, V, const N: usize> TryFrom<[(K, V); N]> for SgTree<K, V, N>
+where
+    K: Ord + Default,
+    V: Default,
+{
+    type Error = SgError;
+
+    fn try_from(arr: [(K, V); N]) -> Result<Self, Self::Error> {
+        match arr.len() <= Idx::MAX {
+            true => Ok(IntoIterator::into_iter(arr).collect()),
+            false => Err(SgError::StackCapacityExceeded)
+        }
     }
 }
+*/
 
 // Indexing
-impl<K, V, Q> Index<&Q> for SGTree<K, V>
+impl<K, V, Q, const N: usize> Index<&Q> for SgTree<K, V, N>
 where
-    K: Borrow<Q> + Ord,
+    K: Borrow<Q> + Ord + Default,
     Q: Ord + ?Sized,
+    V: Default,
 {
     type Output = V;
 
@@ -1301,33 +1335,31 @@ where
     ///
     /// # Panics
     ///
-    /// Panics if the key is not present in the `SGTree`.
+    /// Panics if the key is not present in the `SgTree`.
     fn index(&self, key: &Q) -> &Self::Output {
         self.get(key).expect("No value found for key")
     }
 }
 
 // Extension from iterator.
-impl<K, V> Extend<(K, V)> for SGTree<K, V>
+impl<K, V, const N: usize> Extend<(K, V)> for SgTree<K, V, N>
 where
-    K: Ord,
+    K: Ord + Default,
+    V: Default,
 {
-    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
+    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
         iter.into_iter().for_each(move |(k, v)| {
-            #[cfg(not(feature = "high_assurance"))]
-            self.insert(k, v);
-
-            #[cfg(feature = "high_assurance")]
-            self.insert(k, v).expect("Stack-storage capacity exceeded!");
+            self.try_insert(k, v)
+                .expect("Stack-storage capacity exceeded!");
         });
     }
 }
 
 // Extension from reference iterator.
-impl<'a, K, V> Extend<(&'a K, &'a V)> for SGTree<K, V>
+impl<'a, K, V, const N: usize> Extend<(&'a K, &'a V)> for SgTree<K, V, N>
 where
-    K: Ord + Copy,
-    V: Copy,
+    K: Ord + Copy + Default,
+    V: Copy + Default,
 {
     fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
         self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
@@ -1335,51 +1367,51 @@ where
 }
 
 // PartialEq
-impl<K, V> PartialEq for SGTree<K, V>
+impl<K, V, const N: usize> PartialEq for SgTree<K, V, N>
 where
-    K: Ord + PartialEq,
-    V: PartialEq,
+    K: Ord + PartialEq + Default,
+    V: PartialEq + Default,
 {
-    fn eq(&self, other: &SGTree<K, V>) -> bool {
+    fn eq(&self, other: &SgTree<K, V, N>) -> bool {
         self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b)
     }
 }
 
 // Eq
-impl<K, V> Eq for SGTree<K, V>
+impl<K, V, const N: usize> Eq for SgTree<K, V, N>
 where
-    K: Ord + Eq,
-    V: Eq,
+    K: Ord + Eq + Default,
+    V: Eq + Default,
 {
 }
 
 // PartialOrd
-impl<K, V> PartialOrd for SGTree<K, V>
+impl<K, V, const N: usize> PartialOrd for SgTree<K, V, N>
 where
-    K: Ord + PartialOrd,
-    V: PartialOrd,
+    K: Ord + PartialOrd + Default,
+    V: PartialOrd + Default,
 {
-    fn partial_cmp(&self, other: &SGTree<K, V>) -> Option<Ordering> {
+    fn partial_cmp(&self, other: &SgTree<K, V, N>) -> Option<Ordering> {
         self.iter().partial_cmp(other.iter())
     }
 }
 
 // Ord
-impl<K, V> Ord for SGTree<K, V>
+impl<K, V, const N: usize> Ord for SgTree<K, V, N>
 where
-    K: Ord,
-    V: Ord,
+    K: Ord + Default,
+    V: Ord + Default,
 {
-    fn cmp(&self, other: &SGTree<K, V>) -> Ordering {
+    fn cmp(&self, other: &SgTree<K, V, N>) -> Ordering {
         self.iter().cmp(other.iter())
     }
 }
 
 // Hash
-impl<K, V> Hash for SGTree<K, V>
+impl<K, V, const N: usize> Hash for SgTree<K, V, N>
 where
-    K: Ord + Hash,
-    V: Hash,
+    K: Ord + Hash + Default,
+    V: Hash + Default,
 {
     fn hash<H: Hasher>(&self, state: &mut H) {
         for i in self {
@@ -1391,16 +1423,17 @@ where
 // Iterators -----------------------------------------------------------------------------------------------------------
 
 // Construct from iterator.
-impl<K: Ord, V> FromIterator<(K, V)> for SGTree<K, V> {
+impl<K, V, const N: usize> FromIterator<(K, V)> for SgTree<K, V, N>
+where
+    K: Ord + Default,
+    V: Default,
+{
     fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
-        let mut sgt = SGTree::new();
+        let mut sgt = SgTree::new();
 
         for (k, v) in iter {
-            #[cfg(not(feature = "high_assurance"))]
-            sgt.insert(k, v);
-
-            #[cfg(feature = "high_assurance")]
-            sgt.insert(k, v).expect("Stack-storage capacity exceeded!");
+            sgt.try_insert(k, v)
+                .expect("Stack-storage capacity exceeded!");
         }
 
         sgt
@@ -1408,9 +1441,13 @@ impl<K: Ord, V> FromIterator<(K, V)> for SGTree<K, V> {
 }
 
 // Reference iterator, mutable
-impl<'a, K: Ord, V> IntoIterator for &'a mut SGTree<K, V> {
+impl<'a, K, V, const N: usize> IntoIterator for &'a mut SgTree<K, V, N>
+where
+    K: Ord + Default,
+    V: Default,
+{
     type Item = (&'a K, &'a mut V);
-    type IntoIter = IterMut<'a, K, V>;
+    type IntoIter = IterMut<'a, K, V, N>;
 
     fn into_iter(self) -> Self::IntoIter {
         self.iter_mut()
@@ -1418,9 +1455,13 @@ impl<'a, K: Ord, V> IntoIterator for &'a mut SGTree<K, V> {
 }
 
 // Reference iterator, immutable
-impl<'a, K: Ord, V> IntoIterator for &'a SGTree<K, V> {
+impl<'a, K, V, const N: usize> IntoIterator for &'a SgTree<K, V, N>
+where
+    K: Ord + Default,
+    V: Default,
+{
     type Item = (&'a K, &'a V);
-    type IntoIter = Iter<'a, K, V>;
+    type IntoIter = Iter<'a, K, V, N>;
 
     fn into_iter(self) -> Self::IntoIter {
         self.iter()
@@ -1428,9 +1469,13 @@ impl<'a, K: Ord, V> IntoIterator for &'a SGTree<K, V> {
 }
 
 // Consuming iterator
-impl<K: Ord, V> IntoIterator for SGTree<K, V> {
+impl<K, V, const N: usize> IntoIterator for SgTree<K, V, N>
+where
+    K: Ord + Default,
+    V: Default,
+{
     type Item = (K, V);
-    type IntoIter = IntoIter<K, V>;
+    type IntoIter = IntoIter<K, V, N>;
 
     fn into_iter(self) -> Self::IntoIter {
         IntoIter::new(self)
diff --git a/src/tree/types.rs b/src/tree/types.rs
deleted file mode 100644
index fa4d927..0000000
--- a/src/tree/types.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-use super::node::{Node, NodeGetHelper, NodeRebuildHelper};
-use crate::MAX_ELEMS;
-
-use smallnum::small_unsigned;
-use smallvec::{IntoIter, SmallVec};
-
-// Index Variable ------------------------------------------------------------------------------------------------------
-
-#[cfg(not(feature = "high_assurance"))]
-pub type Idx = small_unsigned!(usize::MAX);
-
-#[cfg(feature = "high_assurance")]
-pub type Idx = small_unsigned!(MAX_ELEMS);
-
-// Arena Internals -----------------------------------------------------------------------------------------------------
-
-pub type ArenaVec<K, V> = SmallVec<[Option<Node<K, V>>; MAX_ELEMS]>;
-
-// Sorting Internals ---------------------------------------------------------------------------------------------------
-
-/// Working set of arena indexes
-pub type IdxVec = SmallVec<[Idx; MAX_ELEMS]>;
-
-/// Metadata for sorting the arena
-pub type SortMetaVec = SmallVec<[NodeGetHelper; MAX_ELEMS]>;
-
-/// Map of a sort's swap history
-pub type SortSwapVec = SmallVec<[(Idx, Idx); MAX_ELEMS]>;
-
-// List of node references
-pub type SortNodeRefVec<'a, K, V> = SmallVec<[&'a Node<K, V>; MAX_ELEMS]>;
-
-// List of (node reference, index) pairs
-pub type SortNodeRefIdxPairVec<'a, K, V> = SmallVec<[(&'a Node<K, V>, Idx); MAX_ELEMS]>;
-
-// List of (index, node rebuild helper) pairs
-pub type RebuildMetaVec = SmallVec<[(Idx, NodeRebuildHelper); MAX_ELEMS]>;
-
-// Set -----------------------------------------------------------------------------------------------------------------
-
-// List of element references
-pub type ElemRefVec<'a, T> = SmallVec<[&'a T; MAX_ELEMS]>;
-
-// Iterator for element references
-pub type ElemRefIter<'a, T> = IntoIter<[&'a T; MAX_ELEMS]>;


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index d2e428d..15c5370 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -38,8 +38,8 @@ jobs:
         command: run
         args: --example static_strs
 
-    - name: run --example ha_insert --all-features
+    - name: run --example try_insert
       uses: actions-rs/cargo@v1
       with:
         command: run
-        args: --example ha_insert --all-features
\ No newline at end of file
+        args: --example try_insert
\ No newline at end of file
diff --git a/benches/test_data.rs b/benches/test_data.rs
index 031a851..189c807 100644
--- a/benches/test_data.rs
+++ b/benches/test_data.rs
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
 use std::iter::FromIterator;
 
 use rand::Rng;
-use scapegoat::SGSet;
+use scapegoat::SgSet;
 
 // Random Test Data ----------------------------------------------------------------------------------------------------
 
@@ -33,9 +33,9 @@ lazy_static::lazy_static! {
 }
 
 lazy_static::lazy_static! {
-    pub static ref SGS_100_RAND: SGSet<usize> = SGSet::from_iter(RAND_100.keys.clone());
-    pub static ref SGS_1_000_RAND: SGSet<usize> = SGSet::from_iter(RAND_1_000.keys.clone());
-    pub static ref SGS_10_000_RAND: SGSet<usize> = SGSet::from_iter(RAND_10_000.keys.clone());
+    pub static ref SGS_100_RAND: SgSet<usize, 100> = SgSet::from_iter(RAND_100.keys.clone());
+    pub static ref SGS_1_000_RAND: SgSet<usize, 1_000> = SgSet::from_iter(RAND_1_000.keys.clone());
+    pub static ref SGS_10_000_RAND: SgSet<usize, 10_000> = SgSet::from_iter(RAND_10_000.keys.clone());
 
     pub static ref STD_100_RAND: BTreeSet<usize> = BTreeSet::from_iter(RAND_100.keys.clone());
     pub static ref STD_1_000_RAND: BTreeSet<usize> = BTreeSet::from_iter(RAND_1_000.keys.clone());
@@ -69,9 +69,9 @@ lazy_static::lazy_static! {
 }
 
 lazy_static::lazy_static! {
-    pub static ref SGS_100_SEQ: SGSet<usize> = SGSet::from_iter(SEQ_100.keys.clone());
-    pub static ref SGS_1_000_SEQ: SGSet<usize> = SGSet::from_iter(SEQ_1_000.keys.clone());
-    pub static ref SGS_10_000_SEQ: SGSet<usize> = SGSet::from_iter(SEQ_10_000.keys.clone());
+    pub static ref SGS_100_SEQ: SgSet<usize, 100> = SgSet::from_iter(SEQ_100.keys.clone());
+    pub static ref SGS_1_000_SEQ: SgSet<usize, 1_000> = SgSet::from_iter(SEQ_1_000.keys.clone());
+    pub static ref SGS_10_000_SEQ: SgSet<usize, 10_000> = SgSet::from_iter(SEQ_10_000.keys.clone());
 
     pub static ref STD_100_SEQ: BTreeSet<usize> = BTreeSet::from_iter(SEQ_100.keys.clone());
     pub static ref STD_1_000_SEQ: BTreeSet<usize> = BTreeSet::from_iter(SEQ_1_000.keys.clone());
diff --git a/src/tree/test.rs b/src/tree/test.rs
index 4d7c3c3..99ead6e 100644
--- a/src/tree/test.rs
+++ b/src/tree/test.rs
@@ -2,33 +2,27 @@ use core::fmt::Debug;
 use core::iter::FromIterator;
 use std::collections::{BTreeMap, BTreeSet, HashSet};
 
-use super::SGTree;
-
-#[cfg(not(feature = "alt_impl"))]
-use super::SGErr;
+use super::node_dispatch::SmallNode;
+use super::tree::{Idx, SgTree};
+use super::SgError;
 
 use rand::rngs::SmallRng;
 use rand::{Rng, SeedableRng};
-use smallvec::{smallvec, SmallVec};
+use tinyvec::array_vec;
 
-use crate::MAX_ELEMS;
+const CAPACITY: usize = 1024;
 
 // Test Helpers --------------------------------------------------------------------------------------------------------
 
 // Build a small tree for testing.
-pub fn get_test_tree_and_keys() -> (SGTree<usize, &'static str>, Vec<usize>) {
+pub fn get_test_tree_and_keys() -> (SgTree<usize, &'static str, CAPACITY>, Vec<usize>) {
     let keys = vec![2, 1, 6, 5, 15, 4, 12, 16, 3, 9, 13, 17, 7, 11, 14, 18, 10];
-    let mut sgt = SGTree::new();
+    let mut sgt = SgTree::new();
 
     assert!(sgt.is_empty());
 
     for k in &keys {
-        #[cfg(not(feature = "high_assurance"))]
         sgt.insert(*k, "n/a");
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt.insert(*k, "n/a").is_ok());
-
         assert_logical_invariants(&sgt);
     }
 
@@ -46,30 +40,30 @@ pub fn get_test_tree_and_keys() -> (SGTree<usize, &'static str>, Vec<usize>) {
 // 1. A right child node's key is always greater than it's parent's key.
 // 2. A left child node's key is always less than it's parent's key.
 // 3. Every node has at most 1 parent.
-fn assert_logical_invariants<K: Ord, V>(sgt: &SGTree<K, V>) {
-    if let Some(root_idx) = sgt.root_idx {
+fn assert_logical_invariants<K: Ord + Default, V: Default, const N: usize>(sgt: &SgTree<K, V, N>) {
+    if let Some(root_idx) = sgt.opt_root_idx {
         let mut child_idxs = vec![root_idx]; // Count as "child" to make sure there's no other ref to this index
-        let mut subtree_worklist = vec![sgt.arena.hard_get(root_idx)];
+        let mut subtree_worklist = vec![&sgt.arena[root_idx]];
 
         while let Some(node) = subtree_worklist.pop() {
-            if let Some(left_idx) = node.left_idx {
-                let left_child_node = sgt.arena.hard_get(left_idx);
+            if let Some(left_idx) = node.left_idx() {
+                let left_child_node = &sgt.arena[left_idx];
                 assert!(
-                    left_child_node.key < node.key,
+                    left_child_node.key() < node.key(),
                     "Internal invariant failed: left child >= parent!"
                 );
                 child_idxs.push(left_idx);
-                subtree_worklist.push(left_child_node);
+                subtree_worklist.push(&left_child_node);
             }
 
-            if let Some(right_idx) = node.right_idx {
-                let right_child_node = sgt.arena.hard_get(right_idx);
+            if let Some(right_idx) = node.right_idx() {
+                let right_child_node = &sgt.arena[right_idx];
                 assert!(
-                    right_child_node.key > node.key,
+                    right_child_node.key() > node.key(),
                     "Internal invariant failed: right child <= parent!"
                 );
                 child_idxs.push(right_idx);
-                subtree_worklist.push(right_child_node);
+                subtree_worklist.push(&right_child_node);
             }
         }
 
@@ -83,14 +77,17 @@ fn assert_logical_invariants<K: Ord, V>(sgt: &SGTree<K, V>) {
     }
 }
 
-// Inserts random keys, and randomly removes 20%.
-fn logical_fuzz(iter_cnt: usize, check_invars: bool) {
-    let mut sgt = SGTree::new();
-    let mut shadow_keys = BTreeSet::new();
+// Inserts random `usize` keys, and randomly removes 20%.
+fn logical_fuzz<const N: usize>(
+    sgt: &mut SgTree<usize, &str, N>,
+    iter_cnt: usize,
+    check_invars: bool,
+) {
+    let mut shadow_keys = BTreeSet::<usize>::new();
     let mut fast_rng = SmallRng::from_entropy();
     let mut slow_rng = rand::thread_rng();
 
-    for _ in 0..iter_cnt {
+    for i in 0..iter_cnt {
         let rand_key: usize;
         if check_invars {
             rand_key = slow_rng.gen();
@@ -100,16 +97,19 @@ fn logical_fuzz(iter_cnt: usize, check_invars: bool) {
 
         // Rand value insert
         shadow_keys.insert(rand_key);
-
-        #[cfg(not(feature = "high_assurance"))]
         sgt.insert(rand_key, "n/a");
 
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt.insert(rand_key, "n/a").is_ok());
-
         // Verify internal state post-insert
         if check_invars {
             assert_logical_invariants(&sgt);
+            assert_eq!(
+                sgt.len(),
+                shadow_keys.len(),
+                "sgt_len ({}) != shadow_key_len ({}), iter: {}",
+                sgt.len(),
+                shadow_keys.len(),
+                i
+            );
         }
 
         // Randomly scheduled removal
@@ -122,39 +122,50 @@ fn logical_fuzz(iter_cnt: usize, check_invars: bool) {
             // Verify internal state post-remove
             if check_invars {
                 assert_logical_invariants(&sgt);
+                assert_eq!(
+                    sgt.len(),
+                    shadow_keys.len(),
+                    "sgt_len ({}) != shadow_key_len ({}), iter: {}",
+                    sgt.len(),
+                    shadow_keys.len(),
+                    i
+                );
             }
         }
     }
 
-    let final_keys = sgt.into_iter().map(|(k, _)| k).collect::<BTreeSet<usize>>();
+    let final_keys = sgt
+        .into_iter()
+        .map(|(k, _)| *k)
+        .collect::<BTreeSet<usize>>();
 
     if final_keys != shadow_keys {
         let diff_this: Vec<usize> = final_keys.difference(&shadow_keys).cloned().collect();
         let diff_other: Vec<usize> = shadow_keys.difference(&final_keys).cloned().collect();
-        println!("Keys in SGTree and NOT in reference BTree: {:?}", diff_this);
+        println!("Keys in SgTree and NOT in reference BTree: {:?}", diff_this);
         println!(
-            "Keys in reference BTree and NOT in SGTree: {:?}",
+            "Keys in reference BTree and NOT in SgTree: {:?}",
             diff_other
         );
-        panic!("Keys do not match shadow set!");
+        panic!(
+            "Keys ({}) do not match shadow set ({})!",
+            final_keys.len(),
+            shadow_keys.len()
+        );
     }
 }
 
 // Identity permutation fill: (0, 0), (1, 1), (2, 2), ... , (n, n)
 // This does a bunch of dynamic checks for testing purposes.
 #[allow(dead_code)]
-fn id_perm_fill<K, V>(sgt: &mut SGTree<K, V>)
+fn id_perm_fill<K, V, const N: usize>(sgt: &mut SgTree<K, V, N>)
 where
-    K: From<usize> + Eq + Debug + Ord,
-    V: From<usize> + Eq + Debug,
+    K: From<usize> + Eq + Debug + Ord + Default,
+    V: From<usize> + Eq + Debug + Default,
 {
     sgt.clear();
     for i in 0..sgt.capacity() {
-        #[cfg(not(feature = "high_assurance"))]
         assert!(sgt.insert(K::from(i), V::from(i)).is_none());
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt.insert(K::from(i), V::from(i)).is_ok());
     }
 
     assert_eq!(sgt.len(), sgt.capacity());
@@ -169,61 +180,79 @@ where
 
 #[test]
 fn test_tree_packing() {
-    // Assumes `SG_MAX_STACK_ELEMS == 1024` (default)
-    if MAX_ELEMS == 1024 {
-        // No features
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(not(feature = "high_assurance"))]
-        #[cfg(not(feature = "low_mem_insert"))]
-        #[cfg(not(feature = "fast_rebalance"))]
-        {
-            assert_eq!(core::mem::size_of::<SGTree<u32, u32>>(), 49_248);
-        }
+    const SMALL_CAPACITY: usize = 100;
+    const MED_CAPACITY: usize = 1_000;
+    //const LARGE_CAPACITY: usize = 100_000;
 
-        // All features
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(feature = "high_assurance")]
-        #[cfg(feature = "low_mem_insert")]
-        #[cfg(feature = "fast_rebalance")]
-        {
-            assert_eq!(core::mem::size_of::<SGTree<u32, u32>>(), 20_528);
-        }
+    let small_tree = SgTree::<u32, u32, SMALL_CAPACITY>::new();
+    let med_tree = SgTree::<u32, u32, MED_CAPACITY>::new();
+    //let large_tree = SgTree::<u32, u32, LARGE_CAPACITY>::new();
 
-        // low_mem_insert only
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(not(feature = "high_assurance"))]
-        #[cfg(feature = "low_mem_insert")]
-        #[cfg(not(feature = "fast_rebalance"))]
-        {
-            assert_eq!(core::mem::size_of::<SGTree<u32, u32>>(), 41_040);
-        }
+    let small_tree_size = core::mem::size_of_val(&small_tree);
+    let med_tree_size = core::mem::size_of_val(&med_tree);
+    //let large_tree_size = core::mem::size_of_val(&large_tree);
 
-        // high_assurance only
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(feature = "high_assurance")]
-        #[cfg(not(feature = "low_mem_insert"))]
-        #[cfg(not(feature = "fast_rebalance"))]
-        {
-            assert_eq!(core::mem::size_of::<SGTree<u32, u32>>(), 18_496);
-        }
+    assert!(small_tree_size < med_tree_size);
+    //assert!(med_tree_size < large_tree_size);
 
-        // fast_rebalance only
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(not(feature = "high_assurance"))]
-        #[cfg(not(feature = "low_mem_insert"))]
-        #[cfg(feature = "fast_rebalance")]
-        {
-            assert_eq!(core::mem::size_of::<SGTree<u32, u32>>(), 57_440);
-        }
+    println!("Tree sizes:\n");
+    println!(
+        "SgTree<u32, u32, {}> -> {} bytes",
+        SMALL_CAPACITY, small_tree_size
+    );
+    println!(
+        "SgTree<u32, u32, {}> -> {} bytes",
+        MED_CAPACITY, med_tree_size
+    );
+    //println!("SgTree<u32, u32, {}> -> {} bytes", LARGE_CAPACITY, large_tree_size);
 
-        // Optimize for size
-        #[cfg(target_pointer_width = "64")]
-        #[cfg(feature = "high_assurance")]
-        #[cfg(feature = "low_mem_insert")]
-        #[cfg(not(feature = "fast_rebalance"))]
-        {
-            assert_eq!(core::mem::size_of::<SGTree<u32, u32>>(), 16_432);
-        }
+    /*
+    NOTE: This is draft code for upgrades when `feature(generic_const_exprs)` stabilizes.
+
+    println!("\nNode sizes:\n");
+    println!("SgTree<u32, u32, {}> -> {} bytes", SMALL_CAPACITY, small_tree.node_size());
+    println!("SgTree<u32, u32, {}> -> {} bytes", MED_CAPACITY, med_tree.node_size());
+    //println!("SgTree<u32, u32, {}> -> {} bytes", LARGE_CAPACITY, large_tree.node_size());
+
+    assert!(small_tree.node_size() < med_tree.node_size());
+    //assert!(med_tree.node_size() < large_tree.node_size());
+    */
+}
+
+#[test]
+fn test_tree_sizing() {
+    assert_eq!(CAPACITY, 1024);
+
+    // No features
+    #[cfg(target_pointer_width = "64")]
+    #[cfg(not(feature = "low_mem_insert"))]
+    #[cfg(not(feature = "fast_rebalance"))]
+    {
+        assert_eq!(core::mem::size_of::<SgTree<u32, u32, CAPACITY>>(), 18_504);
+    }
+
+    // All features
+    #[cfg(target_pointer_width = "64")]
+    #[cfg(feature = "low_mem_insert")]
+    #[cfg(feature = "fast_rebalance")]
+    {
+        assert_eq!(core::mem::size_of::<SgTree<u32, u32, CAPACITY>>(), 20_552);
+    }
+
+    // low_mem_insert only
+    #[cfg(target_pointer_width = "64")]
+    #[cfg(feature = "low_mem_insert")]
+    #[cfg(not(feature = "fast_rebalance"))]
+    {
+        assert_eq!(core::mem::size_of::<SgTree<u32, u32, CAPACITY>>(), 16_456);
+    }
+
+    // fast_rebalance only
+    #[cfg(target_pointer_width = "64")]
+    #[cfg(not(feature = "low_mem_insert"))]
+    #[cfg(feature = "fast_rebalance")]
+    {
+        assert_eq!(core::mem::size_of::<SgTree<u32, u32, CAPACITY>>(), 22_600);
     }
 }
 
@@ -264,7 +293,7 @@ fn test_from_iter() {
     key_val_tuples.push((2, "2"));
     key_val_tuples.push((3, "3"));
 
-    let sgt = SGTree::from_iter(key_val_tuples.into_iter());
+    let sgt = SgTree::<_, _, CAPACITY>::from_iter(key_val_tuples.into_iter());
 
     assert!(sgt.len() == 3);
     assert_eq!(
@@ -273,50 +302,27 @@ fn test_from_iter() {
     );
 }
 
-#[cfg(feature = "high_assurance")]
 #[should_panic(expected = "Stack-storage capacity exceeded!")]
 #[test]
 fn test_from_iter_panic() {
-    let sgt_temp: SGTree<isize, isize> = SGTree::new();
-    let max_capacity = sgt_temp.capacity();
-    let _ = SGTree::from_iter((0..(max_capacity + 1)).map(|val| (val, val)));
+    let _: SgTree<usize, usize, CAPACITY> =
+        SgTree::from_iter((0..(CAPACITY + 1)).map(|val| (val, val)));
 }
 
 #[test]
 fn test_append() {
-    let mut a = SGTree::new();
+    let mut a = SgTree::new();
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        a.insert(1, "1");
-        a.insert(2, "2");
-        a.insert(3, "3");
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(a.insert(1, "1").is_ok());
-        assert!(a.insert(2, "2").is_ok());
-        assert!(a.insert(3, "3").is_ok());
-    }
-
-    let mut b = SGTree::new();
+    a.insert(1, "1");
+    a.insert(2, "2");
+    a.insert(3, "3");
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        b.insert(4, "4");
-        b.insert(5, "5");
-        b.insert(6, "6");
-        a.append(&mut b);
-    }
+    let mut b = SgTree::<_, _, CAPACITY>::new();
 
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(b.insert(4, "4").is_ok());
-        assert!(b.insert(5, "5").is_ok());
-        assert!(b.insert(6, "6").is_ok());
-        assert!(a.append(&mut b).is_ok());
-    }
+    b.insert(4, "4");
+    b.insert(5, "5");
+    b.insert(6, "6");
+    a.append(&mut b);
 
     assert!(b.is_empty());
     assert_eq!(a.len(), 6);
@@ -327,23 +333,45 @@ fn test_append() {
     );
 }
 
+#[test]
+fn test_flatten() {
+    let keys = vec![2, 1, 3];
+    let mut sgt = SgTree::<_, _, CAPACITY>::new();
+
+    for k in &keys {
+        sgt.insert(*k, "n/a");
+    }
+
+    let root_idx = sgt.opt_root_idx.unwrap();
+    let sorted_idxs = sgt.flatten_subtree_to_sorted_idxs::<u16>(root_idx);
+
+    assert_eq!(sorted_idxs, array_vec![[u16; CAPACITY] => 1, 0, 2]);
+
+    sgt.remove(&2);
+
+    let root_idx = sgt.opt_root_idx.unwrap();
+    let sorted_idxs = sgt.flatten_subtree_to_sorted_idxs::<u16>(root_idx);
+
+    assert_eq!(sorted_idxs, array_vec![[u16; CAPACITY] => 1, 2]);
+}
+
 #[test]
 fn test_two_child_removal_case_1() {
     let keys = vec![2, 1, 3];
-    let mut sgt = SGTree::new();
+    let mut sgt = SgTree::<_, _, CAPACITY>::new();
     let to_remove = 2;
 
     for k in &keys {
-        #[cfg(not(feature = "high_assurance"))]
         sgt.insert(*k, "n/a");
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt.insert(*k, "n/a").is_ok());
     }
 
+    println!("Arena, pre-remove: {:#?}", sgt.arena);
+
     sgt.remove(&to_remove);
     assert_logical_invariants(&sgt);
 
+    println!("Arena, post-remove: {:#?}", sgt.arena);
+
     assert_eq!(
         sgt.into_iter().map(|(k, _)| k).collect::<Vec<usize>>(),
         vec![1, 3]
@@ -353,20 +381,20 @@ fn test_two_child_removal_case_1() {
 #[test]
 fn test_two_child_removal_case_2() {
     let keys = vec![2, 1, 4, 3];
-    let mut sgt = SGTree::new();
+    let mut sgt = SgTree::<_, _, CAPACITY>::new();
     let to_remove = 2;
 
     for k in &keys {
-        #[cfg(not(feature = "high_assurance"))]
         sgt.insert(*k, "n/a");
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt.insert(*k, "n/a").is_ok());
     }
 
+    println!("Arena, pre-remove: {:#?}", sgt.arena);
+
     sgt.remove(&to_remove);
     assert_logical_invariants(&sgt);
 
+    println!("Arena, post-remove: {:#?}", sgt.arena);
+
     assert_eq!(
         sgt.into_iter().map(|(k, _)| k).collect::<Vec<usize>>(),
         vec![1, 3, 4]
@@ -376,15 +404,11 @@ fn test_two_child_removal_case_2() {
 #[test]
 fn test_two_child_removal_case_3() {
     let keys = vec![2, 1, 5, 4, 3, 6];
-    let mut sgt = SGTree::new();
+    let mut sgt = SgTree::<_, _, CAPACITY>::new();
     let to_remove = 3;
 
     for k in &keys {
-        #[cfg(not(feature = "high_assurance"))]
         sgt.insert(*k, "n/a");
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt.insert(*k, "n/a").is_ok());
     }
 
     sgt.remove(&to_remove);
@@ -449,14 +473,9 @@ fn test_len() {
 #[test]
 fn test_first_last() {
     let keys = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    let mut sgt = SGTree::new();
+    let mut sgt = SgTree::<_, _, CAPACITY>::new();
     for k in &keys {
-        #[cfg(not(feature = "high_assurance"))]
         sgt.insert(*k, "n/a");
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt.insert(*k, "n/a").is_ok());
-
         assert_logical_invariants(&sgt);
         sgt.contains_key(k);
     }
@@ -477,63 +496,30 @@ fn test_first_last() {
 
 #[test]
 fn test_subtree_rebalance() {
-    let mut sgt: SGTree<usize, &str> = SGTree::new();
-
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sgt.insert(237197427728999687, "n/a");
-        sgt.insert(2328219650045037451, "n/a");
-        sgt.insert(13658362701324851025, "n/a");
-    }
+    let mut sgt: SgTree<usize, &str, CAPACITY> = SgTree::new();
 
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sgt.insert(237197427728999687, "n/a").is_ok());
-        assert!(sgt.insert(2328219650045037451, "n/a").is_ok());
-        assert!(sgt.insert(13658362701324851025, "n/a").is_ok());
-    }
+    sgt.insert(237197427728999687, "n/a");
+    sgt.insert(2328219650045037451, "n/a");
+    sgt.insert(13658362701324851025, "n/a");
 
     sgt.remove(&13658362701324851025);
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sgt.insert(2239831466376212988, "n/a");
-        sgt.insert(15954331640746224573, "n/a");
-        sgt.insert(8202281457156668544, "n/a");
-        sgt.insert(5226917524540172628, "n/a");
-        sgt.insert(11823668523937575827, "n/a");
-        sgt.insert(13519144312507908668, "n/a");
-        sgt.insert(17799627035639903362, "n/a");
-        sgt.insert(17491737414383996868, "n/a");
-        sgt.insert(2247619647701733096, "n/a");
-        sgt.insert(15122725631405182851, "n/a");
-        sgt.insert(9837932133859010449, "n/a");
-        sgt.insert(15426779056379992972, "n/a");
-        sgt.insert(1963900452029117196, "n/a");
-        sgt.insert(1328762018325194497, "n/a");
-        sgt.insert(7471075696232724572, "n/a");
-        sgt.insert(9350363297060113585, "n/a");
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sgt.insert(2239831466376212988, "n/a").is_ok());
-        assert!(sgt.insert(15954331640746224573, "n/a").is_ok());
-        assert!(sgt.insert(8202281457156668544, "n/a").is_ok());
-        assert!(sgt.insert(5226917524540172628, "n/a").is_ok());
-        assert!(sgt.insert(11823668523937575827, "n/a").is_ok());
-        assert!(sgt.insert(13519144312507908668, "n/a").is_ok());
-        assert!(sgt.insert(17799627035639903362, "n/a").is_ok());
-        assert!(sgt.insert(17491737414383996868, "n/a").is_ok());
-        assert!(sgt.insert(2247619647701733096, "n/a").is_ok());
-        assert!(sgt.insert(15122725631405182851, "n/a").is_ok());
-        assert!(sgt.insert(9837932133859010449, "n/a").is_ok());
-        assert!(sgt.insert(15426779056379992972, "n/a").is_ok());
-        assert!(sgt.insert(1963900452029117196, "n/a").is_ok());
-        assert!(sgt.insert(1328762018325194497, "n/a").is_ok());
-        assert!(sgt.insert(7471075696232724572, "n/a").is_ok());
-        assert!(sgt.insert(9350363297060113585, "n/a").is_ok());
-    }
+    sgt.insert(2239831466376212988, "n/a");
+    sgt.insert(15954331640746224573, "n/a");
+    sgt.insert(8202281457156668544, "n/a");
+    sgt.insert(5226917524540172628, "n/a");
+    sgt.insert(11823668523937575827, "n/a");
+    sgt.insert(13519144312507908668, "n/a");
+    sgt.insert(17799627035639903362, "n/a");
+    sgt.insert(17491737414383996868, "n/a");
+    sgt.insert(2247619647701733096, "n/a");
+    sgt.insert(15122725631405182851, "n/a");
+    sgt.insert(9837932133859010449, "n/a");
+    sgt.insert(15426779056379992972, "n/a");
+    sgt.insert(1963900452029117196, "n/a");
+    sgt.insert(1328762018325194497, "n/a");
+    sgt.insert(7471075696232724572, "n/a");
+    sgt.insert(9350363297060113585, "n/a");
 
     sgt.remove(&9350363297060113585);
 
@@ -541,12 +527,8 @@ fn test_subtree_rebalance() {
     assert!(sgt.contains_key(&13519144312507908668));
     let critical_val = 11827258012878092103;
 
-    #[cfg(not(feature = "high_assurance"))]
     sgt.insert(critical_val, "n/a");
 
-    #[cfg(feature = "high_assurance")]
-    assert!(sgt.insert(critical_val, "n/a").is_ok());
-
     assert!(sgt.contains_key(&11823668523937575827));
     assert!(sgt.contains_key(&critical_val));
     assert!(sgt.contains_key(&13519144312507908668));
@@ -556,20 +538,16 @@ fn test_subtree_rebalance() {
 
 #[test]
 fn test_logical_fuzz_fast() {
-    let sgt: SGTree<usize, &str> = SGTree::new();
-    logical_fuzz(sgt.capacity(), false); // Stack-only
-
-    #[cfg(not(feature = "high_assurance"))]
-    logical_fuzz(sgt.capacity() + 2_000, false); // Stack + Heap
+    let mut sgt: SgTree<usize, &str, CAPACITY> = SgTree::new();
+    assert_eq!(CAPACITY, sgt.capacity());
+    logical_fuzz(&mut sgt, CAPACITY, false);
 }
 
 #[test]
 fn test_logical_fuzz_slow() {
-    let sgt: SGTree<usize, &str> = SGTree::new();
-    logical_fuzz(sgt.capacity(), true); // Stack-only
-
-    #[cfg(not(feature = "high_assurance"))]
-    logical_fuzz(sgt.capacity() + 2_000, true); // Stack + Heap
+    let mut sgt: SgTree<usize, &str, CAPACITY> = SgTree::new();
+    assert_eq!(CAPACITY, sgt.capacity());
+    logical_fuzz(&mut sgt, CAPACITY, true);
 }
 
 #[test]
@@ -578,17 +556,9 @@ fn test_retain() {
     bt_map.insert(14987934384537018497, 0);
     bt_map.insert(14483576400934207487, 0);
 
-    let mut sg_map: SGTree<usize, usize> = SGTree::new();
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sg_map.insert(14987934384537018497, 0);
-        sg_map.insert(14483576400934207487, 0);
-    }
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sg_map.insert(14987934384537018497, 0).is_ok());
-        assert!(sg_map.insert(14483576400934207487, 0).is_ok());
-    }
+    let mut sg_map: SgTree<usize, usize, CAPACITY> = SgTree::new();
+    sg_map.insert(14987934384537018497, 0);
+    sg_map.insert(14483576400934207487, 0);
 
     assert!(sg_map.iter().eq(bt_map.iter()));
 
@@ -600,51 +570,41 @@ fn test_retain() {
 
 #[test]
 fn test_extend() {
-    let mut sgt_1 = SGTree::new();
-    let mut sgt_2 = SGTree::new();
+    let mut sgt_1 = SgTree::<_, _, CAPACITY>::new();
+    let mut sgt_2 = SgTree::<_, _, CAPACITY>::new();
 
     for i in 0..5 {
-        #[cfg(not(feature = "high_assurance"))]
         sgt_1.insert(i, i);
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt_1.insert(i, i).is_ok());
     }
 
-    let iterable_1: SmallVec<[(&usize, &usize); 5]> =
-        smallvec![(&0, &0), (&1, &1), (&2, &2), (&3, &3), (&4, &4)];
+    let iterable_1 = array_vec![[(usize, usize); 5] => (0, 0), (1, 1), (2, 2), (3, 3), (4, 4)];
 
-    assert!(sgt_1.iter().eq(iterable_1.into_iter()));
+    assert!(sgt_1.clone().into_iter().eq(iterable_1.into_iter()));
 
     for i in 5..10 {
-        #[cfg(not(feature = "high_assurance"))]
         sgt_2.insert(i, i);
-
-        #[cfg(feature = "high_assurance")]
-        assert!(sgt_2.insert(i, i).is_ok());
     }
 
-    let iterable_2: SmallVec<[(&usize, &usize); 5]> =
-        smallvec![(&5, &5), (&6, &6), (&7, &7), (&8, &8), (&9, &9)];
-
-    assert!(sgt_2.iter().eq(iterable_2.into_iter()));
-
-    let iterable_3: SmallVec<[(&usize, &usize); 10]> = smallvec![
-        (&0, &0),
-        (&1, &1),
-        (&2, &2),
-        (&3, &3),
-        (&4, &4),
-        (&5, &5),
-        (&6, &6),
-        (&7, &7),
-        (&8, &8),
-        (&9, &9)
+    let iterable_2 = array_vec![[(usize, usize); 5] => (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)];
+
+    assert!(sgt_2.clone().into_iter().eq(iterable_2.into_iter()));
+
+    let iterable_3 = array_vec![[(usize, usize); 10] =>
+        (0, 0),
+        (1, 1),
+        (2, 2),
+        (3, 3),
+        (4, 4),
+        (5, 5),
+        (6, 6),
+        (7, 7),
+        (8, 8),
+        (9, 9)
     ];
 
     sgt_1.extend(sgt_2.iter());
     assert_eq!(sgt_2.len(), 5);
-    assert!(sgt_1.iter().eq(iterable_3.into_iter()));
+    assert!(sgt_1.into_iter().eq(iterable_3.into_iter()));
 }
 
 #[test]
@@ -655,17 +615,9 @@ fn test_slice_search() {
     assert_eq!(std::mem::size_of_val(&bad_code), 8);
     assert_eq!(std::mem::size_of_val(&bad_food), 8);
 
-    let mut sgt = SGTree::new();
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sgt.insert(bad_code, "badcode");
-        sgt.insert(bad_food, "badfood");
-    }
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sgt.insert(bad_code, "badcode").is_ok());
-        assert!(sgt.insert(bad_food, "badfood").is_ok());
-    }
+    let mut sgt = SgTree::<_, _, CAPACITY>::new();
+    sgt.insert(bad_code, "badcode");
+    sgt.insert(bad_food, "badfood");
 
     let bad_vec: Vec<u8> = vec![0xB, 0xA, 0xA, 0xD];
     let bad_food_vec: Vec<u8> = vec![0xB, 0xA, 0xA, 0xD, 0xF, 0x0, 0x0, 0xD];
@@ -678,29 +630,27 @@ fn test_slice_search() {
     assert_eq!(sgt.get(&bad_dude_vec[..]), None);
 }
 
-#[cfg(feature = "high_assurance")]
 #[test]
-fn test_high_assurance_insert() {
-    let mut sgt: SGTree<usize, usize> = SGTree::new();
+fn test_fallible_insert() {
+    let mut sgt: SgTree<usize, usize, CAPACITY> = SgTree::new();
     id_perm_fill(&mut sgt);
 
     // Fallible insert
     assert_eq!(
-        sgt.insert(usize::MAX, usize::MAX),
-        Err(super::error::SGErr::StackCapacityExceeded)
+        sgt.try_insert(usize::MAX, usize::MAX),
+        Err(SgError::StackCapacityExceeded)
     );
 }
 
-#[cfg(feature = "high_assurance")]
 #[should_panic(expected = "Stack-storage capacity exceeded!")]
 #[test]
-fn test_high_assurance_extend_panic() {
-    let mut sgt: SGTree<usize, usize> = SGTree::new();
+fn test_extend_panic() {
+    let mut sgt: SgTree<usize, usize, CAPACITY> = SgTree::new();
     id_perm_fill(&mut sgt);
 
-    let mut sgt_2: SGTree<usize, usize> = SGTree::new();
+    let mut sgt_2: SgTree<usize, usize, CAPACITY> = SgTree::new();
     for i in sgt_2.capacity()..(sgt_2.capacity() + 10) {
-        assert!(sgt_2.insert(i, i).is_ok());
+        assert!(sgt_2.try_insert(i, i).is_ok());
     }
 
     // Attempt to extend already full tree
@@ -710,8 +660,8 @@ fn test_high_assurance_extend_panic() {
 
 #[test]
 fn test_from_arr() {
-    let sgt_1 = SGTree::from([(3, 4), (1, 2), (5, 6)]);
-    let sgt_2: SGTree<_, _> = [(1, 2), (3, 4), (5, 6)].into();
+    let sgt_1 = SgTree::from([(3, 4), (1, 2), (5, 6)]);
+    let sgt_2: SgTree<_, _, 3> = [(1, 2), (3, 4), (5, 6)].into();
     assert_eq!(sgt_1, sgt_2);
 
     let btm_1 = BTreeMap::from([(3, 4), (1, 2), (5, 6)]);
@@ -720,7 +670,7 @@ fn test_from_arr() {
 
 #[test]
 fn test_debug() {
-    let sgt = SGTree::from([(3, 4), (1, 2), (5, 6)]);
+    let sgt = SgTree::from([(3, 4), (1, 2), (5, 6)]);
     let btm = BTreeMap::from([(3, 4), (1, 2), (5, 6)]);
     assert!(sgt.iter().eq(btm.iter()));
 
@@ -733,8 +683,8 @@ fn test_debug() {
 
 #[test]
 fn test_hash() {
-    let sgt_1 = SGTree::from([(3, 4), (1, 2), (5, 6)]);
-    let sgt_2: SGTree<_, _> = [(1, 2), (3, 4), (5, 6)].into();
+    let sgt_1 = SgTree::from([(3, 4), (1, 2), (5, 6)]);
+    let sgt_2: SgTree<_, _, 3> = [(1, 2), (3, 4), (5, 6)].into();
     assert_eq!(sgt_1, sgt_2);
 
     let mut hash_set = HashSet::new();
@@ -746,7 +696,7 @@ fn test_hash() {
 
 #[test]
 fn test_clone() {
-    let sgt_1 = SGTree::from([(3, 4), (1, 2), (5, 6)]);
+    let sgt_1 = SgTree::from([(3, 4), (1, 2), (5, 6)]);
     let sgt_2 = sgt_1.clone();
     assert_eq!(sgt_1, sgt_2);
 }
@@ -754,28 +704,24 @@ fn test_clone() {
 #[cfg(not(feature = "alt_impl"))] // This affects rebalance count and is experimental.
 #[test]
 fn test_set_rebal_param() {
-    #[cfg(not(feature = "high_assurance"))]
-    let data: Vec<(usize, usize)> = (0..10_000).map(|x| (x, x)).collect();
-
-    #[cfg(feature = "high_assurance")]
+    assert!(CAPACITY >= 100);
     let data: Vec<(usize, usize)> = (0..100).map(|x| (x, x)).collect();
-
-    let sgt_1 = SGTree::from_iter(data.clone().into_iter());
+    let sgt_1 = SgTree::<_, _, CAPACITY>::from_iter(data.clone().into_iter());
 
     // Lax rebalancing
-    let mut sgt_2 = SGTree::new();
+    let mut sgt_2 = SgTree::<_, _, CAPACITY>::new();
     assert!(sgt_2.set_rebal_param(0.9, 1.0).is_ok());
     sgt_2.extend(data.clone().into_iter());
 
     // Strict rebalancing
-    let mut sgt_3 = SGTree::new();
+    let mut sgt_3 = SgTree::<_, _, CAPACITY>::new();
     assert!(sgt_3.set_rebal_param(1.0, 2.0).is_ok());
     sgt_3.extend(data.into_iter());
 
     // Invalid rebalance factor
     assert_eq!(
         sgt_3.set_rebal_param(2.0, 1.0),
-        Err(SGErr::RebalanceFactorOutOfRange)
+        Err(SgError::RebalanceFactorOutOfRange)
     );
 
     // Alpha tuning OK
@@ -784,17 +730,31 @@ fn test_set_rebal_param() {
     assert!(sgt_3.rebal_cnt() > sgt_1.rebal_cnt());
 
     // Exact counts, useful to verify that different features being enabled don't change these numbers
-    #[cfg(feature = "high_assurance")]
-    {
-        assert_eq!(sgt_1.rebal_cnt(), 52);
-        assert_eq!(sgt_2.rebal_cnt(), 8);
-        assert_eq!(sgt_3.rebal_cnt(), 93);
-    }
+    assert_eq!(sgt_1.rebal_cnt(), 52);
+    assert_eq!(sgt_2.rebal_cnt(), 8);
+    assert_eq!(sgt_3.rebal_cnt(), 93);
+}
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        assert_eq!(sgt_1.rebal_cnt(), 5_475);
-        assert_eq!(sgt_2.rebal_cnt(), 1_192);
-        assert_eq!(sgt_3.rebal_cnt(), 9_987);
-    }
+#[test]
+fn test_intersect_cnt() {
+    let mut sgt_1 = SgTree::from([(3, 4), (1, 2), (5, 6)]);
+    let mut sgt_2: SgTree<_, _, 3> = [(7, 8), (3, 4), (5, 6)].into();
+
+    assert_eq!(sgt_1.intersect_cnt(&sgt_2), 2);
+
+    assert_eq!(sgt_2.pop_last(), Some((7, 8)));
+    assert_eq!(sgt_1.intersect_cnt(&sgt_2), 2);
+
+    assert_eq!(sgt_2.pop_last(), Some((5, 6)));
+    assert_eq!(sgt_1.intersect_cnt(&sgt_2), 1);
+
+    assert_eq!(sgt_1.remove(&3), Some(4));
+    assert_eq!(sgt_1.intersect_cnt(&sgt_2), 0);
+}
+
+#[should_panic(expected = "Max stack item capacity (0xffff) exceeded!")]
+#[test]
+fn test_capacity_exceed() {
+    const OVER_CAP: usize = (Idx::MAX as usize) + 1;
+    let _ = SgTree::<u8, u8, OVER_CAP>::new();
 }
diff --git a/tests/test_map_api.rs b/tests/test_map_api.rs
index f61e8ae..80db4c0 100644
--- a/tests/test_map_api.rs
+++ b/tests/test_map_api.rs
@@ -1,13 +1,17 @@
 use std::collections::BTreeMap;
 use std::iter::FromIterator;
 
-use scapegoat::SGMap;
+use scapegoat::{SgError, SgMap};
 
 use rand::Rng;
 
+const DEFAULT_CAPACITY: usize = 10;
+
+// Normal APIs ---------------------------------------------------------------------------------------------------------
+
 #[test]
 fn test_debug() {
-    let sgm = SGMap::from([(3, 4), (1, 2), (5, 6)]);
+    let sgm = SgMap::from([(3, 4), (1, 2), (5, 6)]);
     let btm = BTreeMap::from([(3, 4), (1, 2), (5, 6)]);
     assert!(sgm.iter().eq(btm.iter()));
 
@@ -20,34 +24,22 @@ fn test_debug() {
 
 #[test]
 fn test_clone() {
-    let sgm_1 = SGMap::from([(3, 4), (1, 2), (5, 6)]);
+    let sgm_1 = SgMap::from([(3, 4), (1, 2), (5, 6)]);
     let sgm_2 = sgm_1.clone();
     assert_eq!(sgm_1, sgm_2);
 }
 
 #[test]
 fn test_basic_map_functionality() {
-    let mut sgm = SGMap::new();
+    let mut sgm = SgMap::<_, _, DEFAULT_CAPACITY>::new();
 
     assert!(sgm.is_empty());
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sgm.insert(1, "1");
-        sgm.insert(2, "2");
-        sgm.insert(3, "3");
-        sgm.insert(4, "4");
-        sgm.insert(5, "5");
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sgm.insert(1, "1").is_ok());
-        assert!(sgm.insert(2, "2").is_ok());
-        assert!(sgm.insert(3, "3").is_ok());
-        assert!(sgm.insert(4, "4").is_ok());
-        assert!(sgm.insert(5, "5").is_ok());
-    }
+    sgm.insert(1, "1");
+    sgm.insert(2, "2");
+    sgm.insert(3, "3");
+    sgm.insert(4, "4");
+    sgm.insert(5, "5");
 
     assert!(!sgm.is_empty());
     assert_eq!(sgm.len(), 5);
@@ -92,19 +84,9 @@ fn test_basic_map_functionality() {
 
     assert_eq!(sgm.len(), 2);
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sgm.insert(0, "0");
-        sgm.insert(3, "3");
-        sgm.insert(10, "10");
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sgm.insert(0, "0").is_ok());
-        assert!(sgm.insert(3, "3").is_ok());
-        assert!(sgm.insert(10, "10").is_ok());
-    }
+    sgm.insert(0, "0");
+    sgm.insert(3, "3");
+    sgm.insert(10, "10");
 
     assert_eq!(sgm.len(), 5);
 
@@ -128,7 +110,7 @@ fn test_basic_map_functionality() {
 #[test]
 fn test_map_from_iter() {
     let key_val_tuples = vec![(1, "1"), (2, "2"), (3, "3")];
-    let sgm = SGMap::from_iter(key_val_tuples.into_iter());
+    let sgm = SgMap::<_, _, 3>::from_iter(key_val_tuples.into_iter());
 
     assert!(sgm.len() == 3);
     assert_eq!(
@@ -137,19 +119,17 @@ fn test_map_from_iter() {
     );
 }
 
-#[cfg(feature = "high_assurance")]
 #[should_panic(expected = "Stack-storage capacity exceeded!")]
 #[test]
 fn test_map_from_iter_panic() {
-    let sgm_temp: SGMap<isize, isize> = SGMap::new();
-    let max_capacity = sgm_temp.capacity();
-    let _ = SGMap::from_iter((0..(max_capacity + 1)).map(|val| (val, val)));
+    let _: SgMap<usize, usize, DEFAULT_CAPACITY> =
+        SgMap::from_iter((0..(DEFAULT_CAPACITY + 1)).map(|val| (val, val)));
 }
 
 #[test]
 fn test_map_iter() {
     let key_val_tuples = vec![(1, "1"), (2, "2"), (3, "3")];
-    let sgm = SGMap::from_iter(key_val_tuples.into_iter());
+    let sgm = SgMap::<_, _, 3>::from_iter(key_val_tuples.into_iter());
     let mut sgm_iter = sgm.iter();
 
     assert_eq!(sgm_iter.next(), Some((&1, &"1")));
@@ -171,7 +151,7 @@ fn test_map_iter_mut() {
         ("c", 3),
     ];
 
-    let mut sgm = SGMap::from_iter(key_val_tuples.into_iter());
+    let mut sgm = SgMap::<_, _, 8>::from_iter(key_val_tuples.into_iter());
     assert_eq!(sgm.len(), 8);
     assert_eq!(sgm.first_key_value(), Some((&"a", &1)));
     assert_eq!(sgm.last_key_value(), Some((&"h", &8)));
@@ -203,17 +183,12 @@ fn test_map_iter_mut() {
 
 #[test]
 fn test_map_iter_mut_rand() {
-    let mut sgm = SGMap::<isize, isize>::new();
+    const CAPACITY: usize = 500;
+    let mut sgm = SgMap::<isize, isize, CAPACITY>::new();
     let mut rng = rand::thread_rng();
 
-    for _ in 0..500 {
-        #[cfg(not(feature = "high_assurance"))]
+    for _ in 0..CAPACITY {
         sgm.insert(rng.gen(), 0);
-
-        #[cfg(feature = "high_assurance")]
-        {
-            assert!(sgm.insert(rng.gen(), 0).is_ok());
-        }
     }
 
     let min_key = *sgm.first_key().unwrap();
@@ -238,45 +213,96 @@ fn test_map_iter_mut_rand() {
 
 #[test]
 fn test_map_append() {
-    let mut a = SGMap::new();
+    let mut a = SgMap::new();
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        a.insert(1, "1");
-        a.insert(2, "2");
-        a.insert(3, "3");
-    }
+    a.insert(1, "1");
+    a.insert(2, "2");
+    a.insert(3, "3");
 
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(a.insert(1, "1").is_ok());
-        assert!(a.insert(2, "2").is_ok());
-        assert!(a.insert(3, "3").is_ok());
-    }
+    let mut b = SgMap::<_, _, DEFAULT_CAPACITY>::new();
 
-    let mut b = SGMap::new();
+    b.insert(4, "4");
+    b.insert(5, "5");
+    b.insert(6, "6");
+    a.append(&mut b);
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        b.insert(4, "4");
-        b.insert(5, "5");
-        b.insert(6, "6");
-        a.append(&mut b);
-    }
+    assert!(b.is_empty());
+    assert_eq!(a.len(), 6);
 
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(b.insert(4, "4").is_ok());
-        assert!(b.insert(5, "5").is_ok());
-        assert!(b.insert(6, "6").is_ok());
-        assert!(a.append(&mut b).is_ok());
-    }
+    assert_eq!(
+        a.into_iter().collect::<Vec<(usize, &str)>>(),
+        vec![(1, "1"), (2, "2"), (3, "3"), (4, "4"), (5, "5"), (6, "6")]
+    );
+}
+
+// Fallible APIs -------------------------------------------------------------------------------------------------------
+
+#[test]
+fn test_map_insert_fallible() {
+    let mut a = SgMap::<_, _, 3>::new();
+
+    assert!(a.try_insert(1, "1A").is_ok());
+    assert!(a.try_insert(2, "2").is_ok());
+
+    assert_eq!(a.try_insert(3, "3"), Ok(None));
+    assert_eq!(a.try_insert(1, "1B"), Ok(Some("1A")));
+    assert_eq!(a.try_insert(4, "4"), Err(SgError::StackCapacityExceeded));
+}
+
+#[test]
+fn test_map_append_fallible() {
+    let mut a = SgMap::<_, _, 6>::new();
+
+    assert!(a.try_insert(1, "1").is_ok());
+    assert!(a.try_insert(2, "2").is_ok());
+    assert!(a.try_insert(3, "3").is_ok());
+
+    let mut b = SgMap::<_, _, 6>::new();
+
+    assert!(b.try_insert(4, "4").is_ok());
+    assert!(b.try_insert(5, "5").is_ok());
+    assert!(b.try_insert(6, "6").is_ok());
+    assert!(a.try_append(&mut b).is_ok());
 
     assert!(b.is_empty());
+    assert_eq!(b.try_insert(7, "7"), Ok(None));
+
     assert_eq!(a.len(), 6);
+    assert_eq!(a.len(), a.capacity());
+    assert_eq!(a.try_insert(7, "7"), Err(SgError::StackCapacityExceeded));
+
+    assert_eq!(a.pop_last(), Some((6, "6")));
+
+    b.clear();
+    assert!(b.try_insert(4, "4").is_ok());
+    assert!(b.try_insert(5, "5").is_ok());
+    assert!(b.try_insert(6, "6").is_ok());
+
+    println!(
+        "a_len: {} of {}, b_len: {}, common_len: {}",
+        a.len(),
+        a.capacity(),
+        b.len(),
+        a.iter().filter(|(k, _)| b.contains_key(&k)).count()
+    );
+
+    assert!(a.try_append(&mut b).is_ok());
 
     assert_eq!(
         a.into_iter().collect::<Vec<(usize, &str)>>(),
         vec![(1, "1"), (2, "2"), (3, "3"), (4, "4"), (5, "5"), (6, "6")]
     );
 }
+
+#[should_panic]
+#[test]
+fn test_map_insert_panic() {
+    let mut a = SgMap::<_, _, 3>::new();
+
+    assert!(a.try_insert(1, "1").is_ok());
+    assert!(a.try_insert(2, "2").is_ok());
+    assert!(a.try_insert(3, "3").is_ok());
+    assert_eq!(a.try_insert(4, "4"), Err(SgError::StackCapacityExceeded));
+
+    a.insert(4, "4"); // panic
+}
diff --git a/tests/test_set_api.rs b/tests/test_set_api.rs
index 7a6c328..62d971e 100644
--- a/tests/test_set_api.rs
+++ b/tests/test_set_api.rs
@@ -1,10 +1,15 @@
-use scapegoat::SGSet;
 use std::collections::BTreeSet;
 use std::iter::FromIterator;
 
+use scapegoat::{SgError, SgSet};
+
+const DEFAULT_CAPACITY: usize = 10;
+
+// Normal APIs ---------------------------------------------------------------------------------------------------------
+
 #[test]
 fn test_debug() {
-    let sgs = SGSet::from([3, 4, 1, 2, 5, 6]);
+    let sgs = SgSet::from([3, 4, 1, 2, 5, 6]);
     let bts = BTreeSet::from([3, 4, 1, 2, 5, 6]);
     assert!(sgs.iter().eq(bts.iter()));
 
@@ -17,34 +22,22 @@ fn test_debug() {
 
 #[test]
 fn test_clone() {
-    let sgs_1 = SGSet::from([3, 4, 1, 2, 5, 6]);
+    let sgs_1 = SgSet::from([3, 4, 1, 2, 5, 6]);
     let sgs_2 = sgs_1.clone();
     assert_eq!(sgs_1, sgs_2);
 }
 
 #[test]
 fn test_basic_set_functionality() {
-    let mut sgs = SGSet::new();
+    let mut sgs = SgSet::<_, 10>::new();
 
     assert!(sgs.is_empty());
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sgs.insert(1);
-        sgs.insert(2);
-        sgs.insert(3);
-        sgs.insert(4);
-        sgs.insert(5);
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sgs.insert(1).is_ok());
-        assert!(sgs.insert(2).is_ok());
-        assert!(sgs.insert(3).is_ok());
-        assert!(sgs.insert(4).is_ok());
-        assert!(sgs.insert(5).is_ok());
-    }
+    sgs.insert(1);
+    sgs.insert(2);
+    sgs.insert(3);
+    sgs.insert(4);
+    sgs.insert(5);
 
     assert!(!sgs.is_empty());
     assert_eq!(sgs.len(), 5);
@@ -75,19 +68,9 @@ fn test_basic_set_functionality() {
 
     assert_eq!(sgs.len(), 2);
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        sgs.insert(0);
-        sgs.insert(3);
-        sgs.insert(10);
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(sgs.insert(0).is_ok());
-        assert!(sgs.insert(3).is_ok());
-        assert!(sgs.insert(10).is_ok());
-    }
+    sgs.insert(0);
+    sgs.insert(3);
+    sgs.insert(10);
 
     assert_eq!(sgs.len(), 5);
 
@@ -108,25 +91,22 @@ fn test_basic_set_functionality() {
 #[test]
 fn test_set_from_iter() {
     let keys = vec![1, 10, 100];
-    let sgs = SGSet::from_iter(keys.into_iter());
+    let sgs = SgSet::<_, 3>::from_iter(keys.into_iter());
 
     assert!(sgs.len() == 3);
     assert_eq!(sgs.into_iter().collect::<Vec<usize>>(), vec![1, 10, 100]);
 }
 
-#[cfg(feature = "high_assurance")]
 #[should_panic(expected = "Stack-storage capacity exceeded!")]
 #[test]
 fn test_set_from_iter_panic() {
-    let sgs_temp: SGSet<isize> = SGSet::new();
-    let max_capacity = sgs_temp.capacity();
-    let _ = SGSet::from_iter(0..(max_capacity + 1));
+    let _: SgSet<usize, DEFAULT_CAPACITY> = SgSet::from_iter(0..(DEFAULT_CAPACITY + 1));
 }
 
 #[test]
 fn test_set_iter() {
     let keys = vec![1, 2, 3];
-    let sgs = SGSet::from_iter(keys.into_iter());
+    let sgs = SgSet::<_, 3>::from_iter(keys.into_iter());
     let mut sgs_iter = sgs.iter();
 
     assert_eq!(sgs_iter.next(), Some(&1));
@@ -137,39 +117,18 @@ fn test_set_iter() {
 
 #[test]
 fn test_set_append() {
-    let mut a = SGSet::new();
-
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        a.insert(1);
-        a.insert(2);
-        a.insert(3);
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(a.insert(1).is_ok());
-        assert!(a.insert(2).is_ok());
-        assert!(a.insert(3).is_ok());
-    }
+    let mut a = SgSet::new();
 
-    let mut b = SGSet::new();
+    a.insert(1);
+    a.insert(2);
+    a.insert(3);
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        b.insert(4);
-        b.insert(5);
-        b.insert(6);
-        a.append(&mut b);
-    }
+    let mut b = SgSet::<_, 10>::new();
 
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(b.insert(4).is_ok());
-        assert!(b.insert(5).is_ok());
-        assert!(b.insert(6).is_ok());
-        assert!(a.append(&mut b).is_ok());
-    }
+    b.insert(4);
+    b.insert(5);
+    b.insert(6);
+    a.append(&mut b);
 
     assert!(b.is_empty());
     assert_eq!(a.len(), 6);
@@ -182,50 +141,26 @@ fn test_set_append() {
 
 #[test]
 fn test_set_intersection() {
-    let mut a = SGSet::new();
-
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        a.insert(2);
-        a.insert(4);
-        a.insert(6);
-        a.insert(8);
-        a.insert(10);
-    }
-
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(a.insert(2).is_ok());
-        assert!(a.insert(4).is_ok());
-        assert!(a.insert(6).is_ok());
-        assert!(a.insert(8).is_ok());
-        assert!(a.insert(10).is_ok());
-    }
+    let mut a = SgSet::new();
 
-    let mut b = SGSet::new();
+    a.insert(2);
+    a.insert(4);
+    a.insert(6);
+    a.insert(8);
+    a.insert(10);
 
-    #[cfg(not(feature = "high_assurance"))]
-    {
-        b.insert(1);
-        b.insert(2);
-        b.insert(3);
-        b.insert(4);
-        b.insert(10);
-    }
+    let mut b = SgSet::new();
 
-    #[cfg(feature = "high_assurance")]
-    {
-        assert!(b.insert(1).is_ok());
-        assert!(b.insert(2).is_ok());
-        assert!(b.insert(3).is_ok());
-        assert!(b.insert(4).is_ok());
-        assert!(b.insert(10).is_ok());
-    }
+    b.insert(1);
+    b.insert(2);
+    b.insert(3);
+    b.insert(4);
+    b.insert(10);
 
     let intersection: Vec<_> = a.intersection(&b).cloned().collect();
     assert_eq!(intersection, [2, 4, 10]);
 
-    let c: SGSet<usize> = SGSet::new();
+    let c: SgSet<usize, 10> = SgSet::new();
     assert!(c.is_empty());
 
     let intersection: Vec<_> = c.intersection(&b).cloned().collect();
@@ -234,39 +169,39 @@ fn test_set_intersection() {
 
 #[test]
 fn test_set_difference() {
-    let a = SGSet::from_iter(&[1, 3, 9, 7]);
-    let b = SGSet::from_iter(&[2, 8, 9, 1]);
+    let a = SgSet::from_iter([1, 3, 9, 7]);
+    let b = SgSet::<_, 4>::from_iter([2, 8, 9, 1]);
     assert_eq!(
-        a.difference(&b).copied().collect::<Vec<&usize>>(),
-        vec![&3, &7]
+        a.difference(&b).copied().collect::<Vec<usize>>(),
+        vec![3, 7]
     );
 }
 
 #[test]
 fn test_set_symmetric_difference() {
-    let a = SGSet::from_iter(&[1, 2, 3, 4, 5]);
-    let b = SGSet::from_iter(&[4, 5, 6, 7, 8]);
+    let a = SgSet::from_iter([1, 2, 3, 4, 5]);
+    let b = SgSet::<_, 5>::from_iter([4, 5, 6, 7, 8]);
     assert_eq!(
-        a.symmetric_difference(&b).copied().collect::<Vec<&usize>>(),
-        vec![&1, &2, &3, &6, &7, &8]
+        a.symmetric_difference(&b).copied().collect::<Vec<usize>>(),
+        vec![1, 2, 3, 6, 7, 8]
     );
 }
 
 #[test]
 fn test_set_union() {
-    let a = SGSet::from_iter(&[1, 3, 9, 7]);
-    let b = SGSet::from_iter(&[2, 8]);
+    let a: SgSet<_, DEFAULT_CAPACITY> = SgSet::from_iter([1, 3, 9, 7]);
+    let b = SgSet::<_, DEFAULT_CAPACITY>::from_iter([2, 8]);
     assert_eq!(
-        a.union(&b).copied().collect::<Vec<&usize>>(),
-        vec![&1, &2, &3, &7, &8, &9]
+        a.union(&b).copied().collect::<Vec<usize>>(),
+        vec![1, 2, 3, 7, 8, 9]
     );
 }
 
 #[test]
 fn test_set_is_superset() {
-    let a = SGSet::from_iter(&[1, 3, 5]);
-    let b = SGSet::from_iter(&[5, 1]);
-    let c = SGSet::from_iter(&[1, 3, 4, 5]);
+    let a = SgSet::from_iter([1, 3, 5]);
+    let b = SgSet::from_iter([5, 1]);
+    let c = SgSet::<_, 4>::from_iter([1, 3, 4, 5]);
     assert!(a.is_superset(&b));
     assert!(!b.is_superset(&a));
     assert!(!a.is_superset(&c));
@@ -274,9 +209,9 @@ fn test_set_is_superset() {
 
 #[test]
 fn test_set_is_subset() {
-    let a = SGSet::from_iter(&[2, 4, 6]);
-    let b = SGSet::from_iter(&[1, 2, 3, 4, 5, 6, 7]);
-    let c = SGSet::from_iter(&[1, 2, 3, 4, 5]);
+    let a = SgSet::from_iter([2, 4, 6]);
+    let b = SgSet::<_, DEFAULT_CAPACITY>::from_iter([1, 2, 3, 4, 5, 6, 7]);
+    let c = SgSet::<_, DEFAULT_CAPACITY>::from_iter([1, 2, 3, 4, 5]);
     assert!(a.is_subset(&b));
     assert!(!b.is_subset(&a));
     assert!(!a.is_subset(&c));
@@ -284,9 +219,81 @@ fn test_set_is_subset() {
 
 #[test]
 fn test_set_is_disjoint() {
-    let a = SGSet::from_iter(&[1, 2, 3]);
-    let b = SGSet::from_iter(&[4, 5, 6]);
-    let c = SGSet::from_iter(&[3, 4, 5]);
+    let a = SgSet::from_iter([1, 2, 3]);
+    let b = SgSet::from_iter([4, 5, 6]);
+    let c = SgSet::<_, 3>::from_iter([3, 4, 5]);
     assert!(a.is_disjoint(&b));
     assert!(!a.is_disjoint(&c));
 }
+
+// Fallible APIs -------------------------------------------------------------------------------------------------------
+
+#[test]
+fn test_map_insert_fallible() {
+    let mut a = SgSet::<_, 3>::new();
+
+    assert!(a.try_insert(1).is_ok());
+    assert!(a.try_insert(2).is_ok());
+
+    assert_eq!(a.try_insert(3), Ok(true));
+    assert_eq!(a.try_insert(1), Ok(false));
+    assert_eq!(a.try_insert(4), Err(SgError::StackCapacityExceeded));
+}
+
+#[test]
+fn test_map_append_fallible() {
+    let mut a = SgSet::<_, 6>::new();
+
+    assert!(a.try_insert(1).is_ok());
+    assert!(a.try_insert(2).is_ok());
+    assert!(a.try_insert(3).is_ok());
+
+    let mut b = SgSet::<_, 6>::new();
+
+    assert!(b.try_insert(4).is_ok());
+    assert!(b.try_insert(5).is_ok());
+    assert!(b.try_insert(6).is_ok());
+    assert!(a.try_append(&mut b).is_ok());
+
+    assert!(b.is_empty());
+    assert_eq!(b.try_insert(7), Ok(true));
+
+    assert_eq!(a.len(), 6);
+    assert_eq!(a.len(), a.capacity());
+    assert_eq!(a.try_insert(7), Err(SgError::StackCapacityExceeded));
+
+    assert_eq!(a.pop_last(), Some(6));
+
+    b.clear();
+    assert!(b.try_insert(4).is_ok());
+    assert!(b.try_insert(5).is_ok());
+    assert!(b.try_insert(6).is_ok());
+
+    println!(
+        "a_len: {} of {}, b_len: {}, common_len: {}",
+        a.len(),
+        a.capacity(),
+        b.len(),
+        a.iter().filter(|k| b.contains(&k)).count()
+    );
+
+    assert!(a.try_append(&mut b).is_ok());
+
+    assert_eq!(
+        a.into_iter().collect::<Vec<usize>>(),
+        vec![1, 2, 3, 4, 5, 6]
+    );
+}
+
+#[should_panic]
+#[test]
+fn test_map_insert_panic() {
+    let mut a = SgSet::<_, 3>::new();
+
+    assert!(a.try_insert(1).is_ok());
+    assert!(a.try_insert(2).is_ok());
+    assert!(a.try_insert(3).is_ok());
+    assert_eq!(a.try_insert(4), Err(SgError::StackCapacityExceeded));
+
+    a.insert(4); // panic
+}
diff --git a/tests/test_traits.rs b/tests/test_traits.rs
new file mode 100644
index 0000000..839e5c5
--- /dev/null
+++ b/tests/test_traits.rs
@@ -0,0 +1,24 @@
+use scapegoat::{SgMap, SgSet};
+
+fn is_auto_trait_friendly<T: Sized + Send + Sync + Unpin>() {}
+fn is_default<T: Default>() {}
+
+#[test]
+fn test_auto_traits_map() {
+    is_auto_trait_friendly::<SgMap<usize, usize, 10>>();
+}
+
+#[test]
+fn test_auto_traits_set() {
+    is_auto_trait_friendly::<SgSet<usize, 10>>();
+}
+
+#[test]
+fn test_default_map() {
+    is_default::<SgMap<usize, usize, 10>>();
+}
+
+#[test]
+fn test_default_set() {
+    is_default::<SgSet<usize, 10>>();
+}