Swap arrayvec crate for heapless to use LenT optimization (#47101)

Swaps the `arrayvec` dependency for `heapless`, as the `heapless`
library allows changing the type used for the `len` field, which
`arrayvec` hard-codes to `usize`. This means that, for all the
`ArrayVec`s in Zed, we can save 7 bytes on 64 bit platforms by just
storing the length as a `u8`.

I have not benchmarked this change locally, as I don't know what
benchmarking tools are in this project.

As a small bit of context, I wrote the PR to `heapless` to add this
`LenT` generic after seeing a PR on the `arrayvec` crate that seems to
be dead now. Once I saw some of Zed's blog posts about the `rope` crate
and noticed the usage of `arrayvec`, I thought this might be a welcome
change.

Release Notes:

- N/A

---------

Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
This commit is contained in:
Gnome! 2026-03-21 13:05:30 +00:00 committed by GitHub
parent abec0efce8
commit aabc967b1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 176 additions and 116 deletions

30
Cargo.lock generated
View file

@ -334,7 +334,6 @@ dependencies = [
"agent_settings",
"ai_onboarding",
"anyhow",
"arrayvec",
"assistant_slash_command",
"assistant_slash_commands",
"assistant_text_thread",
@ -363,6 +362,7 @@ dependencies = [
"git",
"gpui",
"gpui_tokio",
"heapless",
"html_to_markdown",
"http_client",
"image",
@ -733,9 +733,6 @@ name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
dependencies = [
"serde",
]
[[package]]
name = "as-raw-xcb-connection"
@ -5238,7 +5235,6 @@ version = "0.1.0"
dependencies = [
"ai_onboarding",
"anyhow",
"arrayvec",
"brotli",
"buffer_diff",
"client",
@ -5256,6 +5252,7 @@ dependencies = [
"fs",
"futures 0.3.31",
"gpui",
"heapless",
"indoc",
"itertools 0.14.0",
"language",
@ -8027,6 +8024,15 @@ dependencies = [
"smallvec",
]
[[package]]
name = "hash32"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
dependencies = [
"byteorder",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -8111,6 +8117,16 @@ dependencies = [
"http 0.2.12",
]
[[package]]
name = "heapless"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed"
dependencies = [
"hash32",
"stable_deref_trait",
]
[[package]]
name = "heck"
version = "0.3.3"
@ -14672,10 +14688,10 @@ dependencies = [
name = "rope"
version = "0.1.0"
dependencies = [
"arrayvec",
"criterion",
"ctor",
"gpui",
"heapless",
"log",
"rand 0.9.2",
"rayon",
@ -16736,8 +16752,8 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
name = "sum_tree"
version = "0.1.0"
dependencies = [
"arrayvec",
"ctor",
"heapless",
"log",
"proptest",
"rand 0.9.2",

View file

@ -480,7 +480,6 @@ aho-corasick = "1.1"
alacritty_terminal = { git = "https://github.com/zed-industries/alacritty", rev = "9d9640d4" }
any_vec = "0.14"
anyhow = "1.0.86"
arrayvec = { version = "0.7.4", features = ["serde"] }
ashpd = { version = "0.13", default-features = false, features = [
"async-io",
"notification",
@ -564,6 +563,7 @@ futures-lite = "1.13"
gh-workflow = { git = "https://github.com/zed-industries/gh-workflow", rev = "37f3c0575d379c218a9c455ee67585184e40d43f" }
git2 = { version = "0.20.1", default-features = false, features = ["vendored-libgit2"] }
globset = "0.4"
heapless = "0.9.2"
handlebars = "4.3"
heck = "0.5"
heed = { version = "0.21.0", features = ["read-txn-no-tls"] }

View file

@ -34,7 +34,7 @@ agent_servers.workspace = true
agent_settings.workspace = true
ai_onboarding.workspace = true
anyhow.workspace = true
arrayvec.workspace = true
heapless.workspace = true
assistant_text_thread.workspace = true
assistant_slash_command.workspace = true
assistant_slash_commands.workspace = true

View file

@ -14,7 +14,6 @@ use agent_servers::AgentServerDelegate;
use agent_servers::{AgentServer, GEMINI_TERMINAL_AUTH_METHOD_ID};
use agent_settings::{AgentProfileId, AgentSettings};
use anyhow::{Result, anyhow};
use arrayvec::ArrayVec;
use audio::{Audio, Sound};
use buffer_diff::BufferDiff;
use client::zed_urls;

View file

@ -8,6 +8,7 @@ use editor::actions::OpenExcerpts;
use crate::StartThreadIn;
use crate::message_editor::SharedSessionCapabilities;
use gpui::{Corner, List};
use heapless::Vec as ArrayVec;
use language_model::{LanguageModelEffortLevel, Speed};
use settings::update_settings_file;
use ui::{ButtonLike, SplitButton, SplitButtonStyle, Tab};
@ -6367,7 +6368,7 @@ impl ThreadView {
focus_handle: &FocusHandle,
cx: &Context<Self>,
) -> Div {
let mut seen_kinds: ArrayVec<acp::PermissionOptionKind, 3> = ArrayVec::new();
let mut seen_kinds: ArrayVec<acp::PermissionOptionKind, 3, u8> = ArrayVec::new();
div()
.p_1()
@ -6417,7 +6418,7 @@ impl ThreadView {
return this;
}
seen_kinds.push(option.kind);
seen_kinds.push(option.kind).unwrap();
this.key_binding(
KeyBinding::for_action_in(action, focus_handle, cx)

View file

@ -17,7 +17,7 @@ cli-support = []
[dependencies]
ai_onboarding.workspace = true
anyhow.workspace = true
arrayvec.workspace = true
heapless.workspace = true
brotli.workspace = true
buffer_diff.workspace = true
client.workspace = true

View file

@ -1,5 +1,4 @@
use anyhow::Result;
use arrayvec::ArrayVec;
use client::{Client, EditPredictionUsage, UserStore};
use cloud_api_types::{OrganizationId, SubmitEditPredictionFeedbackBody};
use cloud_llm_client::predict_edits_v3::{
@ -27,6 +26,7 @@ use gpui::{
http_client::{self, AsyncBody, Method},
prelude::*,
};
use heapless::Vec as ArrayVec;
use language::language_settings::all_language_settings;
use language::{Anchor, Buffer, File, Point, TextBufferSnapshot, ToOffset, ToPoint};
use language::{BufferSnapshot, OffsetRangeExt};
@ -332,7 +332,7 @@ struct ProjectState {
registered_buffers: HashMap<gpui::EntityId, RegisteredBuffer>,
current_prediction: Option<CurrentEditPrediction>,
next_pending_prediction_id: usize,
pending_predictions: ArrayVec<PendingPrediction, 2>,
pending_predictions: ArrayVec<PendingPrediction, 2, u8>,
debug_tx: Option<mpsc::UnboundedSender<DebugEvent>>,
last_edit_prediction_refresh: Option<(EntityId, Instant)>,
last_jump_prediction_refresh: Option<(EntityId, Instant)>,
@ -2311,18 +2311,24 @@ impl EditPredictionStore {
});
if project_state.pending_predictions.len() < max_pending_predictions {
project_state.pending_predictions.push(PendingPrediction {
id: pending_prediction_id,
task,
drop_on_cancel,
});
project_state
.pending_predictions
.push(PendingPrediction {
id: pending_prediction_id,
task,
drop_on_cancel,
})
.unwrap();
} else {
let pending_prediction = project_state.pending_predictions.pop().unwrap();
project_state.pending_predictions.push(PendingPrediction {
id: pending_prediction_id,
task,
drop_on_cancel,
});
project_state
.pending_predictions
.push(PendingPrediction {
id: pending_prediction_id,
task,
drop_on_cancel,
})
.unwrap();
project_state.cancel_pending_prediction(pending_prediction, cx);
}
}

View file

@ -12,7 +12,7 @@ workspace = true
path = "src/rope.rs"
[dependencies]
arrayvec = "0.7.1"
heapless.workspace = true
log.workspace = true
rayon.workspace = true
sum_tree.workspace = true

View file

@ -1,5 +1,5 @@
use crate::{OffsetUtf16, Point, PointUtf16, TextSummary, Unclipped};
use arrayvec::ArrayString;
use heapless::String as ArrayString;
use std::{cmp, ops::Range};
use sum_tree::Bias;
use unicode_segmentation::GraphemeCursor;
@ -29,7 +29,7 @@ pub struct Chunk {
newlines: Bitmap,
/// If bit[i] is set, then the character at index i is an ascii tab.
tabs: Bitmap,
pub text: ArrayString<MAX_BASE>,
pub text: ArrayString<MAX_BASE, u8>,
}
#[inline(always)]
@ -47,7 +47,11 @@ impl Chunk {
#[inline(always)]
pub fn new(text: &str) -> Self {
let text = ArrayString::from(text).unwrap();
let text = {
let mut buf = ArrayString::new();
buf.push_str(text).unwrap();
buf
};
const CHUNK_SIZE: usize = 8;
@ -118,7 +122,7 @@ impl Chunk {
self.chars_utf16 |= slice.chars_utf16 << base_ix;
self.newlines |= slice.newlines << base_ix;
self.tabs |= slice.tabs << base_ix;
self.text.push_str(slice.text);
self.text.push_str(slice.text).unwrap();
}
#[inline(always)]
@ -137,9 +141,9 @@ impl Chunk {
self.newlines = slice.newlines | (self.newlines << shift);
self.tabs = slice.tabs | (self.tabs << shift);
let mut new_text = ArrayString::<MAX_BASE>::new();
new_text.push_str(slice.text);
new_text.push_str(&self.text);
let mut new_text = ArrayString::<MAX_BASE, u8>::new();
new_text.push_str(slice.text).unwrap();
new_text.push_str(&self.text).unwrap();
self.text = new_text;
}

View file

@ -4,7 +4,7 @@ mod point;
mod point_utf16;
mod unclipped;
use arrayvec::ArrayVec;
use heapless::Vec as ArrayVec;
use rayon::iter::{IntoParallelIterator, ParallelIterator as _};
use std::{
cmp, fmt, io, mem,
@ -184,7 +184,7 @@ impl Rope {
return self.push_large(text);
}
// 16 is enough as otherwise we will hit the branch above
let mut new_chunks = ArrayVec::<_, NUM_CHUNKS>::new();
let mut new_chunks = ArrayVec::<_, NUM_CHUNKS, u8>::new();
while !text.is_empty() {
let mut split_ix = cmp::min(chunk::MAX_BASE, text.len());
@ -192,7 +192,7 @@ impl Rope {
split_ix -= 1;
}
let (chunk, remainder) = text.split_at(split_ix);
new_chunks.push(chunk);
new_chunks.push(chunk).unwrap();
text = remainder;
}
self.chunks

View file

@ -14,7 +14,7 @@ path = "src/sum_tree.rs"
doctest = false
[dependencies]
arrayvec = "0.7.1"
heapless.workspace = true
rayon.workspace = true
log.workspace = true
ztracing.workspace = true

View file

@ -1,5 +1,5 @@
use super::*;
use arrayvec::ArrayVec;
use heapless::Vec as ArrayVec;
use std::{cmp::Ordering, mem, sync::Arc};
use ztracing::instrument;
@ -29,7 +29,7 @@ impl<T: Item + fmt::Debug, D: fmt::Debug> fmt::Debug for StackEntry<'_, T, D> {
#[derive(Clone)]
pub struct Cursor<'a, 'b, T: Item, D> {
tree: &'a SumTree<T>,
stack: ArrayVec<StackEntry<'a, T, D>, 16>,
stack: ArrayVec<StackEntry<'a, T, D>, 16, u8>,
pub position: D,
did_seek: bool,
at_end: bool,
@ -53,7 +53,7 @@ where
pub struct Iter<'a, T: Item> {
tree: &'a SumTree<T>,
stack: ArrayVec<StackEntry<'a, T, ()>, 16>,
stack: ArrayVec<StackEntry<'a, T, ()>, 16, u8>,
}
impl<'a, 'b, T, D> Cursor<'a, 'b, T, D>
@ -231,11 +231,13 @@ where
self.position = D::zero(self.cx);
self.at_end = self.tree.is_empty();
if !self.tree.is_empty() {
self.stack.push(StackEntry {
tree: self.tree,
index: self.tree.0.child_summaries().len() as u32,
position: D::from_summary(self.tree.summary(), self.cx),
});
self.stack
.push(StackEntry {
tree: self.tree,
index: self.tree.0.child_summaries().len() as u32,
position: D::from_summary(self.tree.summary(), self.cx),
})
.unwrap_oob();
}
}
@ -267,11 +269,13 @@ where
Node::Internal { child_trees, .. } => {
if descending {
let tree = &child_trees[entry.index()];
self.stack.push(StackEntry {
position: D::zero(self.cx),
tree,
index: tree.0.child_summaries().len() as u32 - 1,
})
self.stack
.push(StackEntry {
position: D::zero(self.cx),
tree,
index: tree.0.child_summaries().len() as u32 - 1,
})
.unwrap_oob();
}
}
Node::Leaf { .. } => {
@ -297,11 +301,13 @@ where
if self.stack.is_empty() {
if !self.at_end {
self.stack.push(StackEntry {
tree: self.tree,
index: 0,
position: D::zero(self.cx),
});
self.stack
.push(StackEntry {
tree: self.tree,
index: 0,
position: D::zero(self.cx),
})
.unwrap_oob();
descend = true;
}
self.did_seek = true;
@ -361,11 +367,13 @@ where
if let Some(subtree) = new_subtree {
descend = true;
self.stack.push(StackEntry {
tree: subtree,
index: 0,
position: self.position.clone(),
});
self.stack
.push(StackEntry {
tree: subtree,
index: 0,
position: self.position.clone(),
})
.unwrap_oob();
} else {
descend = false;
self.stack.pop();
@ -467,11 +475,13 @@ where
if !self.did_seek {
self.did_seek = true;
self.stack.push(StackEntry {
tree: self.tree,
index: 0,
position: D::zero(self.cx),
});
self.stack
.push(StackEntry {
tree: self.tree,
index: 0,
position: D::zero(self.cx),
})
.unwrap_oob();
}
let mut ascending = false;
@ -503,11 +513,13 @@ where
entry.index += 1;
entry.position = self.position.clone();
} else {
self.stack.push(StackEntry {
tree: child_tree,
index: 0,
position: self.position.clone(),
});
self.stack
.push(StackEntry {
tree: child_tree,
index: 0,
position: self.position.clone(),
})
.unwrap_oob();
ascending = false;
continue 'outer;
}
@ -578,11 +590,13 @@ impl<'a, T: Item> Iterator for Iter<'a, T> {
let mut descend = false;
if self.stack.is_empty() {
self.stack.push(StackEntry {
tree: self.tree,
index: 0,
position: (),
});
self.stack
.push(StackEntry {
tree: self.tree,
index: 0,
position: (),
})
.unwrap_oob();
descend = true;
}
@ -611,11 +625,13 @@ impl<'a, T: Item> Iterator for Iter<'a, T> {
if let Some(subtree) = new_subtree {
descend = true;
self.stack.push(StackEntry {
tree: subtree,
index: 0,
position: (),
});
self.stack
.push(StackEntry {
tree: subtree,
index: 0,
position: (),
})
.unwrap_oob();
} else {
descend = false;
self.stack.pop();
@ -748,8 +764,8 @@ trait SeekAggregate<'a, T: Item> {
struct SliceSeekAggregate<T: Item> {
tree: SumTree<T>,
leaf_items: ArrayVec<T, { 2 * TREE_BASE }>,
leaf_item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>,
leaf_items: ArrayVec<T, { 2 * TREE_BASE }, u8>,
leaf_item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>,
leaf_summary: T::Summary,
}
@ -786,8 +802,8 @@ impl<T: Item> SeekAggregate<'_, T> for SliceSeekAggregate<T> {
summary: &T::Summary,
cx: <T::Summary as Summary>::Context<'_>,
) {
self.leaf_items.push(item.clone());
self.leaf_item_summaries.push(summary.clone());
self.leaf_items.push(item.clone()).unwrap_oob();
self.leaf_item_summaries.push(summary.clone()).unwrap_oob();
Summary::add_summary(&mut self.leaf_summary, summary, cx);
}
fn push_tree(

View file

@ -3,8 +3,8 @@ mod cursor;
pub mod property_test;
mod tree_map;
use arrayvec::ArrayVec;
pub use cursor::{Cursor, FilterCursor, Iter};
use heapless::Vec as ArrayVec;
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator as _};
use std::marker::PhantomData;
use std::mem;
@ -17,6 +17,17 @@ pub const TREE_BASE: usize = 2;
#[cfg(not(test))]
pub const TREE_BASE: usize = 6;
// Helper for when we cannot use ArrayVec::<T>::push().unwrap() as T doesn't impl Debug
trait CapacityResultExt {
fn unwrap_oob(self);
}
impl<T> CapacityResultExt for Result<(), T> {
fn unwrap_oob(self) {
self.unwrap_or_else(|_| panic!("item should fit into fixed size ArrayVec"))
}
}
/// An item that can be stored in a [`SumTree`]
///
/// Must be summarized by a type that implements [`Summary`]
@ -243,8 +254,9 @@ impl<T: Item> SumTree<T> {
let mut iter = iter.into_iter().fuse().peekable();
while iter.peek().is_some() {
let items: ArrayVec<T, { 2 * TREE_BASE }> = iter.by_ref().take(2 * TREE_BASE).collect();
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }> =
let items: ArrayVec<T, { 2 * TREE_BASE }, u8> =
iter.by_ref().take(2 * TREE_BASE).collect();
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8> =
items.iter().map(|item| item.summary(cx)).collect();
let mut summary = item_summaries[0].clone();
@ -284,8 +296,8 @@ impl<T: Item> SumTree<T> {
};
let child_summary = child_node.summary();
<T::Summary as Summary>::add_summary(summary, child_summary, cx);
child_summaries.push(child_summary.clone());
child_trees.push(child_node);
child_summaries.push(child_summary.clone()).unwrap_oob();
child_trees.push(child_node.clone()).unwrap_oob();
if child_trees.len() == 2 * TREE_BASE {
parent_nodes.extend(current_parent_node.take());
@ -315,8 +327,8 @@ impl<T: Item> SumTree<T> {
.into_par_iter()
.chunks(2 * TREE_BASE)
.map(|items| {
let items: ArrayVec<T, { 2 * TREE_BASE }> = items.into_iter().collect();
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }> =
let items: ArrayVec<T, { 2 * TREE_BASE }, u8> = items.into_iter().collect();
let item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8> =
items.iter().map(|item| item.summary(cx)).collect();
let mut summary = item_summaries[0].clone();
for item_summary in &item_summaries[1..] {
@ -337,9 +349,9 @@ impl<T: Item> SumTree<T> {
.into_par_iter()
.chunks(2 * TREE_BASE)
.map(|child_nodes| {
let child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }> =
let child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }, u8> =
child_nodes.into_iter().collect();
let child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }> = child_trees
let child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8> = child_trees
.iter()
.map(|child_tree| child_tree.summary().clone())
.collect();
@ -798,14 +810,16 @@ impl<T: Item> SumTree<T> {
<T::Summary as Summary>::add_summary(summary, other_node.summary(), cx);
let height_delta = *height - other_node.height();
let mut summaries_to_append = ArrayVec::<T::Summary, { 2 * TREE_BASE }>::new();
let mut trees_to_append = ArrayVec::<SumTree<T>, { 2 * TREE_BASE }>::new();
let mut summaries_to_append = ArrayVec::<T::Summary, { 2 * TREE_BASE }, u8>::new();
let mut trees_to_append = ArrayVec::<SumTree<T>, { 2 * TREE_BASE }, u8>::new();
if height_delta == 0 {
summaries_to_append.extend(other_node.child_summaries().iter().cloned());
trees_to_append.extend(other_node.child_trees().iter().cloned());
} else if height_delta == 1 && !other_node.is_underflowing() {
summaries_to_append.push(other_node.summary().clone());
trees_to_append.push(other)
summaries_to_append
.push(other_node.summary().clone())
.unwrap_oob();
trees_to_append.push(other).unwrap_oob();
} else {
let tree_to_append = child_trees
.last_mut()
@ -815,15 +829,17 @@ impl<T: Item> SumTree<T> {
child_trees.last().unwrap().0.summary().clone();
if let Some(split_tree) = tree_to_append {
summaries_to_append.push(split_tree.0.summary().clone());
trees_to_append.push(split_tree);
summaries_to_append
.push(split_tree.0.summary().clone())
.unwrap_oob();
trees_to_append.push(split_tree).unwrap_oob();
}
}
let child_count = child_trees.len() + trees_to_append.len();
if child_count > 2 * TREE_BASE {
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }>;
let right_summaries: ArrayVec<_, { 2 * TREE_BASE }>;
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8>;
let right_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8>;
let left_trees;
let right_trees;
@ -868,7 +884,7 @@ impl<T: Item> SumTree<T> {
let left_items;
let right_items;
let left_summaries;
let right_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>;
let right_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>;
let midpoint = (child_count + child_count % 2) / 2;
{
@ -933,8 +949,10 @@ impl<T: Item> SumTree<T> {
*child_summaries.first_mut().unwrap() = first.summary().clone();
if let Some(tree) = res {
if child_trees.len() < 2 * TREE_BASE {
child_summaries.insert(0, tree.summary().clone());
child_trees.insert(0, tree);
child_summaries
.insert(0, tree.summary().clone())
.unwrap_oob();
child_trees.insert(0, tree).unwrap_oob();
None
} else {
let new_child_summaries = {
@ -1016,7 +1034,7 @@ impl<T: Item> SumTree<T> {
.iter()
.chain(child_summaries.iter())
.cloned();
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }> =
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8> =
all_summaries.by_ref().take(midpoint).collect();
*child_summaries = all_summaries.collect();
@ -1065,7 +1083,7 @@ impl<T: Item> SumTree<T> {
.iter()
.chain(item_summaries.iter())
.cloned();
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }> =
let left_summaries: ArrayVec<_, { 2 * TREE_BASE }, u8> =
all_summaries.by_ref().take(midpoint).collect();
*item_summaries = all_summaries.collect();
@ -1088,11 +1106,11 @@ impl<T: Item> SumTree<T> {
) -> Self {
let height = left.0.height() + 1;
let mut child_summaries = ArrayVec::new();
child_summaries.push(left.0.summary().clone());
child_summaries.push(right.0.summary().clone());
child_summaries.push(left.0.summary().clone()).unwrap_oob();
child_summaries.push(right.0.summary().clone()).unwrap_oob();
let mut child_trees = ArrayVec::new();
child_trees.push(left);
child_trees.push(right);
child_trees.push(left).unwrap_oob();
child_trees.push(right).unwrap_oob();
SumTree(Arc::new(Node::Internal {
height,
summary: sum(child_summaries.iter(), cx),
@ -1252,13 +1270,13 @@ pub enum Node<T: Item> {
Internal {
height: u8,
summary: T::Summary,
child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>,
child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }>,
child_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>,
child_trees: ArrayVec<SumTree<T>, { 2 * TREE_BASE }, u8>,
},
Leaf {
summary: T::Summary,
items: ArrayVec<T, { 2 * TREE_BASE }>,
item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }>,
items: ArrayVec<T, { 2 * TREE_BASE }, u8>,
item_summaries: ArrayVec<T::Summary, { 2 * TREE_BASE }, u8>,
},
}
@ -1323,14 +1341,14 @@ impl<T: Item> Node<T> {
}
}
fn child_trees(&self) -> &ArrayVec<SumTree<T>, { 2 * TREE_BASE }> {
fn child_trees(&self) -> &ArrayVec<SumTree<T>, { 2 * TREE_BASE }, u8> {
match self {
Node::Internal { child_trees, .. } => child_trees,
Node::Leaf { .. } => panic!("Leaf nodes have no child trees"),
}
}
fn items(&self) -> &ArrayVec<T, { 2 * TREE_BASE }> {
fn items(&self) -> &ArrayVec<T, { 2 * TREE_BASE }, u8> {
match self {
Node::Leaf { items, .. } => items,
Node::Internal { .. } => panic!("Internal nodes have no items"),