From aabc967b1c3217380346c07e4c6b244664ac46e6 Mon Sep 17 00:00:00 2001 From: Gnome! Date: Sat, 21 Mar 2026 13:05:30 +0000 Subject: [PATCH] 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> --- Cargo.lock | 30 +++-- Cargo.toml | 2 +- crates/agent_ui/Cargo.toml | 2 +- crates/agent_ui/src/conversation_view.rs | 1 - .../src/conversation_view/thread_view.rs | 5 +- crates/edit_prediction/Cargo.toml | 2 +- crates/edit_prediction/src/edit_prediction.rs | 30 +++-- crates/rope/Cargo.toml | 2 +- crates/rope/src/chunk.rs | 18 +-- crates/rope/src/rope.rs | 6 +- crates/sum_tree/Cargo.toml | 2 +- crates/sum_tree/src/cursor.rs | 110 ++++++++++-------- crates/sum_tree/src/sum_tree.rs | 82 ++++++++----- 13 files changed, 176 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 823c3d05463a8038f0a426b89b0ac3acaca354c5..d76e9f1f40cfb1be27799ee3433957639872b324 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index b31c088581a65070f348cf55195d0db948b33bb0..5f736ef3e83625c89425985e179e973bff4ff67c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } diff --git a/crates/agent_ui/Cargo.toml b/crates/agent_ui/Cargo.toml index 8b06417d2f5812ef2e0fb265e6afa4cfeb26eb3f..b60f2a6b136c5e4dbb131603d95623a719ce7134 100644 --- a/crates/agent_ui/Cargo.toml +++ b/crates/agent_ui/Cargo.toml @@ -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 diff --git a/crates/agent_ui/src/conversation_view.rs b/crates/agent_ui/src/conversation_view.rs index 2ba60eba96ed08bdc276164e01b7480731edf635..d0ccf2dd0116074cbcdfff3162d585e5b3222cbf 100644 --- a/crates/agent_ui/src/conversation_view.rs +++ b/crates/agent_ui/src/conversation_view.rs @@ -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; diff --git a/crates/agent_ui/src/conversation_view/thread_view.rs b/crates/agent_ui/src/conversation_view/thread_view.rs index d086cb91f8204f51dbfa5eaaf2d011a2a9656309..ef8a46e5749966ac0a616ecb7fd2f5b7bc5e4f83 100644 --- a/crates/agent_ui/src/conversation_view/thread_view.rs +++ b/crates/agent_ui/src/conversation_view/thread_view.rs @@ -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, ) -> Div { - let mut seen_kinds: ArrayVec = ArrayVec::new(); + let mut seen_kinds: ArrayVec = 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) diff --git a/crates/edit_prediction/Cargo.toml b/crates/edit_prediction/Cargo.toml index d2a23b8b4ec3425072ffbe9d042ff89d26a56778..a6a7d8777cbf0d52575489e91a5ae03be2d031ea 100644 --- a/crates/edit_prediction/Cargo.toml +++ b/crates/edit_prediction/Cargo.toml @@ -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 diff --git a/crates/edit_prediction/src/edit_prediction.rs b/crates/edit_prediction/src/edit_prediction.rs index bd1bc7a3303a6f80094fd8261e90a2c5e113803d..421a51b055693617a915e622b617298f5f8a01c5 100644 --- a/crates/edit_prediction/src/edit_prediction.rs +++ b/crates/edit_prediction/src/edit_prediction.rs @@ -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, current_prediction: Option, next_pending_prediction_id: usize, - pending_predictions: ArrayVec, + pending_predictions: ArrayVec, debug_tx: Option>, 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); } } diff --git a/crates/rope/Cargo.toml b/crates/rope/Cargo.toml index 9f0fc2be8a021a4cd43679beefb18a3567452dde..a4273c8abff1a4a3bc9b08a72f0c405f3195c75e 100644 --- a/crates/rope/Cargo.toml +++ b/crates/rope/Cargo.toml @@ -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 diff --git a/crates/rope/src/chunk.rs b/crates/rope/src/chunk.rs index 594f8f5c67e2e151c1ba933b59344d8542f381e1..96fc743a33190da9c59c029ace9997b1f9407e63 100644 --- a/crates/rope/src/chunk.rs +++ b/crates/rope/src/chunk.rs @@ -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, + pub text: ArrayString, } #[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::::new(); - new_text.push_str(slice.text); - new_text.push_str(&self.text); + let mut new_text = ArrayString::::new(); + new_text.push_str(slice.text).unwrap(); + new_text.push_str(&self.text).unwrap(); self.text = new_text; } diff --git a/crates/rope/src/rope.rs b/crates/rope/src/rope.rs index d7e27e6f11bce82b43cd37d6915bbc172c32d4f7..d6a4db3396c287e51dceddbc2f67fc0a40cf2c5b 100644 --- a/crates/rope/src/rope.rs +++ b/crates/rope/src/rope.rs @@ -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 diff --git a/crates/sum_tree/Cargo.toml b/crates/sum_tree/Cargo.toml index e4cf78181aa43cce4a6692cc3c6c92e03b7bf9ad..8392baa4678b1f635b1c6955fad50acd76576e86 100644 --- a/crates/sum_tree/Cargo.toml +++ b/crates/sum_tree/Cargo.toml @@ -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 diff --git a/crates/sum_tree/src/cursor.rs b/crates/sum_tree/src/cursor.rs index 494ecbe049993e58357cf5d5606ea8d6624126c4..ec2ded5fcfcdc8400607c64b79ef8712e84e26fc 100644 --- a/crates/sum_tree/src/cursor.rs +++ b/crates/sum_tree/src/cursor.rs @@ -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 fmt::Debug for StackEntry<'_, T, D> { #[derive(Clone)] pub struct Cursor<'a, 'b, T: Item, D> { tree: &'a SumTree, - stack: ArrayVec, 16>, + stack: ArrayVec, 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, - stack: ArrayVec, 16>, + stack: ArrayVec, 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 { tree: SumTree, - leaf_items: ArrayVec, - leaf_item_summaries: ArrayVec, + leaf_items: ArrayVec, + leaf_item_summaries: ArrayVec, leaf_summary: T::Summary, } @@ -786,8 +802,8 @@ impl SeekAggregate<'_, T> for SliceSeekAggregate { summary: &T::Summary, cx: ::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( diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index 8ab9b5ccb1fdb3b28b3aa0dd93c7a732a21645cb..251a194d2c7c984a0caa4d0b478ece41332af6be 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -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::::push().unwrap() as T doesn't impl Debug +trait CapacityResultExt { + fn unwrap_oob(self); +} + +impl 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 SumTree { let mut iter = iter.into_iter().fuse().peekable(); while iter.peek().is_some() { - let items: ArrayVec = iter.by_ref().take(2 * TREE_BASE).collect(); - let item_summaries: ArrayVec = + let items: ArrayVec = + iter.by_ref().take(2 * TREE_BASE).collect(); + let item_summaries: ArrayVec = items.iter().map(|item| item.summary(cx)).collect(); let mut summary = item_summaries[0].clone(); @@ -284,8 +296,8 @@ impl SumTree { }; let child_summary = child_node.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 SumTree { .into_par_iter() .chunks(2 * TREE_BASE) .map(|items| { - let items: ArrayVec = items.into_iter().collect(); - let item_summaries: ArrayVec = + let items: ArrayVec = items.into_iter().collect(); + let item_summaries: ArrayVec = 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 SumTree { .into_par_iter() .chunks(2 * TREE_BASE) .map(|child_nodes| { - let child_trees: ArrayVec, { 2 * TREE_BASE }> = + let child_trees: ArrayVec, { 2 * TREE_BASE }, u8> = child_nodes.into_iter().collect(); - let child_summaries: ArrayVec = child_trees + let child_summaries: ArrayVec = child_trees .iter() .map(|child_tree| child_tree.summary().clone()) .collect(); @@ -798,14 +810,16 @@ impl SumTree { ::add_summary(summary, other_node.summary(), cx); let height_delta = *height - other_node.height(); - let mut summaries_to_append = ArrayVec::::new(); - let mut trees_to_append = ArrayVec::, { 2 * TREE_BASE }>::new(); + let mut summaries_to_append = ArrayVec::::new(); + let mut trees_to_append = ArrayVec::, { 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 SumTree { 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 SumTree { let left_items; let right_items; let left_summaries; - let right_summaries: ArrayVec; + let right_summaries: ArrayVec; let midpoint = (child_count + child_count % 2) / 2; { @@ -933,8 +949,10 @@ impl SumTree { *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 SumTree { .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 SumTree { .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 SumTree { ) -> 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 { Internal { height: u8, summary: T::Summary, - child_summaries: ArrayVec, - child_trees: ArrayVec, { 2 * TREE_BASE }>, + child_summaries: ArrayVec, + child_trees: ArrayVec, { 2 * TREE_BASE }, u8>, }, Leaf { summary: T::Summary, - items: ArrayVec, - item_summaries: ArrayVec, + items: ArrayVec, + item_summaries: ArrayVec, }, } @@ -1323,14 +1341,14 @@ impl Node { } } - fn child_trees(&self) -> &ArrayVec, { 2 * TREE_BASE }> { + fn child_trees(&self) -> &ArrayVec, { 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 { + fn items(&self) -> &ArrayVec { match self { Node::Leaf { items, .. } => items, Node::Internal { .. } => panic!("Internal nodes have no items"),