Skip to main content

hashtree_index/
lib.rs

1//! Content-addressed B-tree indexes backed by hashtree.
2
3mod search;
4
5use std::cmp::Ordering;
6use std::collections::{BTreeMap, BTreeSet};
7use std::future::Future;
8use std::pin::Pin;
9use std::sync::Arc;
10
11use hashtree_core::{
12    Cid, DirEntry, HashTree, HashTreeConfig, HashTreeError, LinkType, Store, TreeEntry,
13};
14pub use search::{
15    SearchError, SearchIndex, SearchIndexOptions, SearchLinkResult, SearchOptions, SearchResult,
16};
17
18const DEFAULT_ORDER: usize = 32;
19
20#[derive(Debug, Clone, Default)]
21pub struct BTreeOptions {
22    pub order: Option<usize>,
23}
24
25#[derive(Debug, thiserror::Error)]
26pub enum BTreeError {
27    #[error("hash tree error: {0}")]
28    HashTree(#[from] HashTreeError),
29    #[error("value was not valid utf-8: {0}")]
30    Utf8(#[from] std::string::FromUtf8Error),
31}
32
33#[derive(Debug, Clone)]
34struct SplitResult {
35    left: Cid,
36    right: Cid,
37    left_first_key: String,
38    right_first_key: String,
39    left_count: u64,
40    right_count: u64,
41}
42
43#[derive(Debug, Clone)]
44enum InsertValue {
45    String(String),
46    Link(Cid),
47}
48
49type BTreeFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, BTreeError>> + 'a>>;
50
51pub struct BTree<S: Store> {
52    tree: HashTree<S>,
53    max_keys: usize,
54}
55
56#[derive(Debug, Clone)]
57struct BuiltNode {
58    first_key: String,
59    cid: Cid,
60    count: u64,
61}
62
63impl<S: Store> BTree<S> {
64    pub fn new(store: Arc<S>, options: BTreeOptions) -> Self {
65        let order = options.order.unwrap_or(DEFAULT_ORDER).max(2);
66        Self {
67            tree: HashTree::new(HashTreeConfig::new(store)),
68            max_keys: order - 1,
69        }
70    }
71
72    pub async fn insert(
73        &self,
74        root: Option<&Cid>,
75        key: &str,
76        value: &str,
77    ) -> Result<Cid, BTreeError> {
78        if let Some(root) = root {
79            if self.get(Some(root), key).await?.as_deref() == Some(value) {
80                return Ok(root.clone());
81            }
82
83            let result = self
84                .insert_recursive(
85                    root.clone(),
86                    key.to_string(),
87                    InsertValue::String(value.to_string()),
88                )
89                .await?;
90            return self.finish_insert(result).await;
91        }
92
93        self.create_leaf(&[(key.to_string(), value.to_string())])
94            .await
95    }
96
97    pub async fn get(&self, root: Option<&Cid>, key: &str) -> Result<Option<String>, BTreeError> {
98        let Some(root) = root else {
99            return Ok(None);
100        };
101        self.get_recursive(root.clone(), key.to_string()).await
102    }
103
104    pub async fn insert_link(
105        &self,
106        root: Option<&Cid>,
107        key: &str,
108        target_cid: &Cid,
109    ) -> Result<Cid, BTreeError> {
110        if let Some(root) = root {
111            if self
112                .get_link(Some(root), key)
113                .await?
114                .is_some_and(|existing| cid_equals(&existing, target_cid))
115            {
116                return Ok(root.clone());
117            }
118
119            let result = self
120                .insert_recursive(
121                    root.clone(),
122                    key.to_string(),
123                    InsertValue::Link(target_cid.clone()),
124                )
125                .await?;
126            return self.finish_insert(result).await;
127        }
128
129        self.create_leaf_with_links(&[(key.to_string(), target_cid.clone())])
130            .await
131    }
132
133    pub async fn insert_link_unchecked(
134        &self,
135        root: Option<&Cid>,
136        key: &str,
137        target_cid: &Cid,
138    ) -> Result<Cid, BTreeError> {
139        if let Some(root) = root {
140            let result = self
141                .insert_recursive(
142                    root.clone(),
143                    key.to_string(),
144                    InsertValue::Link(target_cid.clone()),
145                )
146                .await?;
147            return self.finish_insert(result).await;
148        }
149
150        self.create_leaf_with_links(&[(key.to_string(), target_cid.clone())])
151            .await
152    }
153
154    pub async fn get_link(&self, root: Option<&Cid>, key: &str) -> Result<Option<Cid>, BTreeError> {
155        let Some(root) = root else {
156            return Ok(None);
157        };
158        self.get_link_recursive(root.clone(), key.to_string()).await
159    }
160
161    /// Resolve many link keys in one tree walk, skipping subtrees that cannot
162    /// contain any requested key.
163    pub async fn get_links<I>(
164        &self,
165        root: Option<&Cid>,
166        keys: I,
167    ) -> Result<BTreeMap<String, Cid>, BTreeError>
168    where
169        I: IntoIterator<Item = String>,
170    {
171        let keys = keys.into_iter().collect::<BTreeSet<_>>();
172        let Some(root) = root else {
173            return Ok(BTreeMap::new());
174        };
175        if keys.is_empty() {
176            return Ok(BTreeMap::new());
177        }
178        self.get_links_recursive(root.clone(), &keys.into_iter().collect::<Vec<_>>())
179            .await
180    }
181
182    pub async fn entries(&self, root: Option<&Cid>) -> Result<Vec<(String, String)>, BTreeError> {
183        let Some(root) = root else {
184            return Ok(Vec::new());
185        };
186        self.traverse_in_order(root.clone()).await
187    }
188
189    pub async fn links_entries(
190        &self,
191        root: Option<&Cid>,
192    ) -> Result<Vec<(String, Cid)>, BTreeError> {
193        let Some(root) = root else {
194            return Ok(Vec::new());
195        };
196        self.traverse_links_in_order(root.clone()).await
197    }
198
199    pub async fn links_entries_limited(
200        &self,
201        root: Option<&Cid>,
202        limit: usize,
203    ) -> Result<Vec<(String, Cid)>, BTreeError> {
204        if limit == 0 {
205            return Ok(Vec::new());
206        }
207        let Some(root) = root else {
208            return Ok(Vec::new());
209        };
210        self.range_link_traverse_limited(root.clone(), None, None, limit)
211            .await
212    }
213
214    /// Count CID links by walking the tree.
215    ///
216    /// Uses stored subtree sizes when available, but scans descendants when
217    /// older roots do not carry complete counts.
218    pub async fn count_links(&self, root: Option<&Cid>) -> Result<u64, BTreeError> {
219        self.scan_links(root).await
220    }
221
222    /// Count CID links by explicitly walking the tree.
223    pub async fn scan_links(&self, root: Option<&Cid>) -> Result<u64, BTreeError> {
224        let Some(root) = root else {
225            return Ok(0);
226        };
227        self.count_links_recursive(root.clone()).await
228    }
229
230    /// Read the stored CID-link count from the root node without scanning.
231    ///
232    /// Returns `Ok(None)` when the root was built by older code that does not
233    /// store complete subtree sizes.
234    pub async fn count_stored_links(&self, root: Option<&Cid>) -> Result<Option<u64>, BTreeError> {
235        let Some(root) = root else {
236            return Ok(Some(0));
237        };
238
239        let entries = self.tree.list_directory(root).await?;
240        if is_leaf_node(&entries) {
241            return Ok(Some(count_link_entries(&entries)));
242        }
243
244        let mut count = 0;
245        for entry in &entries {
246            let Some(child_count) = stored_link_subtree_count(entry) else {
247                return Ok(None);
248            };
249            count += child_count;
250        }
251        Ok(Some(count))
252    }
253
254    pub async fn range(
255        &self,
256        root: &Cid,
257        start: Option<&str>,
258        end: Option<&str>,
259    ) -> Result<Vec<(String, String)>, BTreeError> {
260        self.range_traverse(
261            root.clone(),
262            start.map(ToOwned::to_owned),
263            end.map(ToOwned::to_owned),
264        )
265        .await
266    }
267
268    pub async fn prefix(
269        &self,
270        root: &Cid,
271        prefix: &str,
272    ) -> Result<Vec<(String, String)>, BTreeError> {
273        let end = increment_prefix(prefix);
274        self.range(root, Some(prefix), end.as_deref()).await
275    }
276
277    pub async fn prefix_links(
278        &self,
279        root: &Cid,
280        prefix: &str,
281    ) -> Result<Vec<(String, Cid)>, BTreeError> {
282        let end = increment_prefix(prefix);
283        self.range_link_traverse(root.clone(), Some(prefix.to_string()), end)
284            .await
285    }
286
287    pub async fn prefix_links_limited(
288        &self,
289        root: &Cid,
290        prefix: &str,
291        limit: usize,
292    ) -> Result<Vec<(String, Cid)>, BTreeError> {
293        if limit == 0 {
294            return Ok(Vec::new());
295        }
296        let end = increment_prefix(prefix);
297        self.range_link_traverse_limited(root.clone(), Some(prefix.to_string()), end, limit)
298            .await
299    }
300
301    pub async fn delete(&self, root: &Cid, key: &str) -> Result<Option<Cid>, BTreeError> {
302        self.delete_recursive(root.clone(), key.to_string()).await
303    }
304
305    pub async fn merge(
306        &self,
307        base: Option<&Cid>,
308        other: Option<&Cid>,
309        prefer_other: bool,
310    ) -> Result<Option<Cid>, BTreeError> {
311        let Some(other) = other else {
312            return Ok(base.cloned());
313        };
314        let Some(mut result) = base.cloned().or_else(|| Some(other.clone())) else {
315            return Ok(None);
316        };
317        if base.is_none() {
318            return Ok(Some(result));
319        }
320
321        for (key, value) in self.entries(Some(other)).await? {
322            let existing = self.get(Some(&result), &key).await?;
323            if existing.is_none() || prefer_other {
324                result = self.insert(Some(&result), &key, &value).await?;
325            }
326        }
327
328        Ok(Some(result))
329    }
330
331    pub async fn merge_links(
332        &self,
333        base: Option<&Cid>,
334        other: Option<&Cid>,
335        prefer_other: bool,
336    ) -> Result<Option<Cid>, BTreeError> {
337        let Some(other) = other else {
338            return Ok(base.cloned());
339        };
340        let Some(mut result) = base.cloned().or_else(|| Some(other.clone())) else {
341            return Ok(None);
342        };
343        if base.is_none() {
344            return Ok(Some(result));
345        }
346
347        for (key, value) in self.links_entries(Some(other)).await? {
348            let existing = self.get_link(Some(&result), &key).await?;
349            if existing.is_none() || prefer_other {
350                result = self.insert_link(Some(&result), &key, &value).await?;
351            }
352        }
353
354        Ok(Some(result))
355    }
356
357    pub async fn build<I>(&self, items: I) -> Result<Option<Cid>, BTreeError>
358    where
359        I: IntoIterator<Item = (String, String)>,
360    {
361        let mut sorted: Vec<(String, String)> = items.into_iter().collect();
362        if sorted.is_empty() {
363            return Ok(None);
364        }
365
366        sorted.sort_by(|left, right| left.0.cmp(&right.0));
367
368        let mut deduped = Vec::with_capacity(sorted.len());
369        for (key, value) in sorted {
370            if let Some((last_key, last_value)) = deduped.last_mut() {
371                if *last_key == key {
372                    *last_value = value;
373                    continue;
374                }
375            }
376            deduped.push((key, value));
377        }
378
379        let mut level = Vec::with_capacity(deduped.len().div_ceil(self.max_keys));
380        for chunk in deduped.chunks(self.max_keys) {
381            let cid = self.create_leaf(chunk).await?;
382            level.push(BuiltNode {
383                first_key: chunk[0].0.clone(),
384                cid,
385                count: chunk.len() as u64,
386            });
387        }
388
389        while level.len() > 1 {
390            let mut next_level = Vec::with_capacity(level.len().div_ceil(self.max_keys));
391            for chunk in level.chunks(self.max_keys) {
392                let cid = self.create_internal_node(chunk).await?;
393                next_level.push(BuiltNode {
394                    first_key: chunk[0].first_key.clone(),
395                    cid,
396                    count: chunk.iter().map(|child| child.count).sum(),
397                });
398            }
399            level = next_level;
400        }
401
402        Ok(level.pop().map(|node| node.cid))
403    }
404
405    /// Apply a sorted batch of string insertions and deletions, reusing
406    /// untouched subtrees. Repeated changes for one key use the last value;
407    /// `None` deletes a key.
408    pub async fn update<I>(&self, root: Option<&Cid>, changes: I) -> Result<Option<Cid>, BTreeError>
409    where
410        I: IntoIterator<Item = (String, Option<String>)>,
411    {
412        let changes = changes.into_iter().collect::<BTreeMap<_, _>>();
413        if changes.is_empty() {
414            return Ok(root.cloned());
415        }
416
417        let changes = changes.into_iter().collect::<Vec<_>>();
418        let Some(root) = root else {
419            return self
420                .build(
421                    changes
422                        .into_iter()
423                        .filter_map(|(key, value)| value.map(|value| (key, value))),
424                )
425                .await;
426        };
427
428        let nodes = self.update_string_node(root.clone(), &changes).await?;
429        self.finish_link_node_updates(nodes).await
430    }
431
432    fn update_string_node<'a>(
433        &'a self,
434        node: Cid,
435        changes: &'a [(String, Option<String>)],
436    ) -> BTreeFuture<'a, Vec<BuiltNode>> {
437        Box::pin(async move {
438            let entries = sort_entries(self.tree.list_directory(&node).await?);
439            if is_leaf_node(&entries) {
440                return self.update_string_leaf(entries, changes).await;
441            }
442
443            let mut children = Vec::new();
444            let mut change_start = 0;
445            for (child_index, entry) in entries.iter().enumerate() {
446                let change_end = entries
447                    .get(child_index + 1)
448                    .map(|next| {
449                        let next_key = unescape_key(&next.name);
450                        change_start
451                            + changes[change_start..].partition_point(|(key, _)| key < &next_key)
452                    })
453                    .unwrap_or(changes.len());
454                if change_start == change_end {
455                    let cid = entry_cid(entry);
456                    let count = match stored_link_subtree_count(entry) {
457                        Some(count) => count,
458                        None => self.count_entries_recursive(cid.clone()).await?,
459                    };
460                    children.push(BuiltNode {
461                        first_key: unescape_key(&entry.name),
462                        cid,
463                        count,
464                    });
465                } else {
466                    children.extend(
467                        self.update_string_node(
468                            entry_cid(entry),
469                            &changes[change_start..change_end],
470                        )
471                        .await?,
472                    );
473                }
474                change_start = change_end;
475            }
476
477            self.create_link_node_level(children).await
478        })
479    }
480
481    async fn update_string_leaf(
482        &self,
483        entries: Vec<TreeEntry>,
484        changes: &[(String, Option<String>)],
485    ) -> Result<Vec<BuiltNode>, BTreeError> {
486        let mut final_entries = BTreeMap::new();
487        for entry in entries {
488            if entry.link_type != LinkType::Blob {
489                continue;
490            }
491            let Some(data) = self.tree.get(&entry_cid(&entry), None).await? else {
492                continue;
493            };
494            final_entries.insert(unescape_key(&entry.name), String::from_utf8(data)?);
495        }
496        for (key, value) in changes {
497            match value {
498                Some(value) => {
499                    final_entries.insert(key.clone(), value.clone());
500                }
501                None => {
502                    final_entries.remove(key);
503                }
504            }
505        }
506
507        let final_entries = final_entries.into_iter().collect::<Vec<_>>();
508        let mut nodes = Vec::with_capacity(final_entries.len().div_ceil(self.max_keys));
509        for chunk in final_entries.chunks(self.max_keys) {
510            let cid = self.create_leaf(chunk).await?;
511            nodes.push(BuiltNode {
512                first_key: chunk[0].0.clone(),
513                cid,
514                count: chunk.len() as u64,
515            });
516        }
517        Ok(nodes)
518    }
519
520    pub async fn build_links<I>(&self, items: I) -> Result<Option<Cid>, BTreeError>
521    where
522        I: IntoIterator<Item = (String, Cid)>,
523    {
524        let mut sorted: Vec<(String, Cid)> = items.into_iter().collect();
525        if sorted.is_empty() {
526            return Ok(None);
527        }
528
529        sorted.sort_by(|left, right| left.0.cmp(&right.0));
530
531        let mut deduped = Vec::with_capacity(sorted.len());
532        for (key, cid) in sorted {
533            if let Some((last_key, last_cid)) = deduped.last_mut() {
534                if *last_key == key {
535                    *last_cid = cid;
536                    continue;
537                }
538            }
539            deduped.push((key, cid));
540        }
541
542        let mut level = Vec::with_capacity(deduped.len().div_ceil(self.max_keys));
543        for chunk in deduped.chunks(self.max_keys) {
544            let cid = self.create_leaf_with_links(chunk).await?;
545            level.push(BuiltNode {
546                first_key: chunk[0].0.clone(),
547                cid,
548                count: chunk.len() as u64,
549            });
550        }
551
552        while level.len() > 1 {
553            let mut next_level = Vec::with_capacity(level.len().div_ceil(self.max_keys));
554            for chunk in level.chunks(self.max_keys) {
555                let cid = self.create_internal_node(chunk).await?;
556                next_level.push(BuiltNode {
557                    first_key: chunk[0].first_key.clone(),
558                    cid,
559                    count: chunk.iter().map(|child| child.count).sum(),
560                });
561            }
562            level = next_level;
563        }
564
565        Ok(level.pop().map(|node| node.cid))
566    }
567
568    /// Apply a sorted batch of link insertions and deletions, reusing untouched
569    /// subtrees. Repeated changes for one key use the last value; `None` deletes
570    /// a key.
571    pub async fn update_links<I>(
572        &self,
573        root: Option<&Cid>,
574        changes: I,
575    ) -> Result<Option<Cid>, BTreeError>
576    where
577        I: IntoIterator<Item = (String, Option<Cid>)>,
578    {
579        let changes = changes.into_iter().collect::<BTreeMap<_, _>>();
580        if changes.is_empty() {
581            return Ok(root.cloned());
582        }
583
584        let changes = changes.into_iter().collect::<Vec<_>>();
585        let Some(root) = root else {
586            return self
587                .build_links(
588                    changes
589                        .into_iter()
590                        .filter_map(|(key, cid)| cid.map(|cid| (key, cid))),
591                )
592                .await;
593        };
594
595        let nodes = self.update_link_node(root.clone(), &changes).await?;
596        self.finish_link_node_updates(nodes).await
597    }
598
599    fn update_link_node<'a>(
600        &'a self,
601        node: Cid,
602        changes: &'a [(String, Option<Cid>)],
603    ) -> BTreeFuture<'a, Vec<BuiltNode>> {
604        Box::pin(async move {
605            let entries = sort_entries(self.tree.list_directory(&node).await?);
606            if is_leaf_node(&entries) {
607                return self.update_link_leaf(entries, changes).await;
608            }
609
610            let mut children = Vec::new();
611            let mut change_start = 0;
612            for (child_index, entry) in entries.iter().enumerate() {
613                let change_end = entries
614                    .get(child_index + 1)
615                    .map(|next| {
616                        let next_key = unescape_key(&next.name);
617                        change_start
618                            + changes[change_start..].partition_point(|(key, _)| key < &next_key)
619                    })
620                    .unwrap_or(changes.len());
621                if change_start == change_end {
622                    let cid = entry_cid(entry);
623                    let count = match stored_link_subtree_count(entry) {
624                        Some(count) => count,
625                        None => self.count_links_recursive(cid.clone()).await?,
626                    };
627                    children.push(BuiltNode {
628                        first_key: unescape_key(&entry.name),
629                        cid,
630                        count,
631                    });
632                } else {
633                    children.extend(
634                        self.update_link_node(entry_cid(entry), &changes[change_start..change_end])
635                            .await?,
636                    );
637                }
638                change_start = change_end;
639            }
640
641            self.create_link_node_level(children).await
642        })
643    }
644
645    async fn update_link_leaf(
646        &self,
647        entries: Vec<TreeEntry>,
648        changes: &[(String, Option<Cid>)],
649    ) -> Result<Vec<BuiltNode>, BTreeError> {
650        let mut final_entries = entries
651            .into_iter()
652            .map(|entry| (unescape_key(&entry.name), entry_cid(&entry)))
653            .collect::<BTreeMap<_, _>>();
654        for (key, cid) in changes {
655            match cid {
656                Some(cid) => {
657                    final_entries.insert(key.clone(), cid.clone());
658                }
659                None => {
660                    final_entries.remove(key);
661                }
662            }
663        }
664
665        let final_entries = final_entries.into_iter().collect::<Vec<_>>();
666        let mut nodes = Vec::with_capacity(final_entries.len().div_ceil(self.max_keys));
667        for chunk in final_entries.chunks(self.max_keys) {
668            let cid = self.create_leaf_with_links(chunk).await?;
669            nodes.push(BuiltNode {
670                first_key: chunk[0].0.clone(),
671                cid,
672                count: chunk.len() as u64,
673            });
674        }
675        Ok(nodes)
676    }
677
678    async fn create_link_node_level(
679        &self,
680        children: Vec<BuiltNode>,
681    ) -> Result<Vec<BuiltNode>, BTreeError> {
682        let mut nodes = Vec::with_capacity(children.len().div_ceil(self.max_keys));
683        for chunk in children.chunks(self.max_keys) {
684            let cid = self.create_internal_node(chunk).await?;
685            nodes.push(BuiltNode {
686                first_key: chunk[0].first_key.clone(),
687                cid,
688                count: chunk.iter().map(|child| child.count).sum(),
689            });
690        }
691        Ok(nodes)
692    }
693
694    async fn finish_link_node_updates(
695        &self,
696        mut nodes: Vec<BuiltNode>,
697    ) -> Result<Option<Cid>, BTreeError> {
698        while nodes.len() > 1 {
699            nodes = self.create_link_node_level(nodes).await?;
700        }
701        Ok(nodes.pop().map(|node| node.cid))
702    }
703
704    async fn finish_insert(&self, result: InsertResult) -> Result<Cid, BTreeError> {
705        if let Some(split) = result.split {
706            return self
707                .create_internal_root(
708                    &split.left_first_key,
709                    &split.left,
710                    split.left_count,
711                    &split.right_first_key,
712                    &split.right,
713                    split.right_count,
714                )
715                .await;
716        }
717        Ok(result.cid)
718    }
719
720    fn get_recursive<'a>(&'a self, root: Cid, key: String) -> BTreeFuture<'a, Option<String>> {
721        Box::pin(async move {
722            let entries = self.tree.list_directory(&root).await?;
723            if is_leaf_node(&entries) {
724                let escaped = escape_key(&key);
725                let Some(entry) = entries.iter().find(|entry| entry.name == escaped) else {
726                    return Ok(None);
727                };
728                if entry.link_type != LinkType::Blob {
729                    return Ok(None);
730                }
731
732                let cid = entry_cid(entry);
733                let Some(data) = self.tree.get(&cid, None).await? else {
734                    return Ok(None);
735                };
736                return Ok(Some(String::from_utf8(data)?));
737            }
738
739            let child = find_child(&entries, &key);
740            self.get_recursive(entry_cid(&child), key).await
741        })
742    }
743
744    fn get_link_recursive<'a>(&'a self, root: Cid, key: String) -> BTreeFuture<'a, Option<Cid>> {
745        Box::pin(async move {
746            let entries = self.tree.list_directory(&root).await?;
747            if is_leaf_node(&entries) {
748                let escaped = escape_key(&key);
749                let Some(entry) = entries.iter().find(|entry| entry.name == escaped) else {
750                    return Ok(None);
751                };
752                if entry.link_type != LinkType::File {
753                    return Ok(None);
754                }
755                return Ok(Some(entry_cid(entry)));
756            }
757
758            let child = find_child(&entries, &key);
759            self.get_link_recursive(entry_cid(&child), key).await
760        })
761    }
762
763    fn get_links_recursive<'a>(
764        &'a self,
765        root: Cid,
766        keys: &'a [String],
767    ) -> BTreeFuture<'a, BTreeMap<String, Cid>> {
768        Box::pin(async move {
769            let entries = sort_entries(self.tree.list_directory(&root).await?);
770            if is_leaf_node(&entries) {
771                let links = entries
772                    .into_iter()
773                    .map(|entry| (unescape_key(&entry.name), entry_cid(&entry)))
774                    .collect::<BTreeMap<_, _>>();
775                return Ok(keys
776                    .iter()
777                    .filter_map(|key| links.get(key).cloned().map(|cid| (key.clone(), cid)))
778                    .collect());
779            }
780
781            let mut found = BTreeMap::new();
782            let mut key_start = 0;
783            for (child_index, entry) in entries.iter().enumerate() {
784                let key_end = entries
785                    .get(child_index + 1)
786                    .map(|next| {
787                        let next_key = unescape_key(&next.name);
788                        key_start + keys[key_start..].partition_point(|key| key < &next_key)
789                    })
790                    .unwrap_or(keys.len());
791                if key_start < key_end {
792                    found.extend(
793                        self.get_links_recursive(entry_cid(entry), &keys[key_start..key_end])
794                            .await?,
795                    );
796                }
797                key_start = key_end;
798            }
799            Ok(found)
800        })
801    }
802
803    fn insert_recursive<'a>(
804        &'a self,
805        node: Cid,
806        key: String,
807        value: InsertValue,
808    ) -> BTreeFuture<'a, InsertResult> {
809        Box::pin(async move {
810            let entries = self.tree.list_directory(&node).await?;
811            if is_leaf_node(&entries) {
812                return self.insert_into_leaf(node, entries, key, value).await;
813            }
814            self.insert_into_internal(node, entries, key, value).await
815        })
816    }
817
818    fn insert_into_leaf<'a>(
819        &'a self,
820        node: Cid,
821        _entries: Vec<TreeEntry>,
822        key: String,
823        value: InsertValue,
824    ) -> BTreeFuture<'a, InsertResult> {
825        Box::pin(async move {
826            let escaped_key = escape_key(&key);
827            let (entry_cid, size, link_type) = match value {
828                InsertValue::String(value) => {
829                    let (cid, size) = self.tree.put_file(value.as_bytes()).await?;
830                    (cid, size, LinkType::Blob)
831                }
832                InsertValue::Link(cid) => (cid, 0, LinkType::File),
833            };
834
835            let new_node = self
836                .tree
837                .set_entry(&node, &[], &escaped_key, &entry_cid, size, link_type)
838                .await?;
839
840            let new_entries = self.tree.list_directory(&new_node).await?;
841            if new_entries.len() > self.max_keys {
842                return Ok(InsertResult {
843                    cid: new_node,
844                    count: count_link_entries_or_subtrees(self, &new_entries).await?,
845                    split: Some(self.split_leaf(new_entries).await?),
846                });
847            }
848
849            Ok(InsertResult {
850                cid: new_node,
851                count: count_link_entries_or_subtrees(self, &new_entries).await?,
852                split: None,
853            })
854        })
855    }
856
857    fn insert_into_internal<'a>(
858        &'a self,
859        node: Cid,
860        entries: Vec<TreeEntry>,
861        key: String,
862        value: InsertValue,
863    ) -> BTreeFuture<'a, InsertResult> {
864        Box::pin(async move {
865            let child = find_child(&entries, &key);
866            let child_name = child.name.clone();
867            let child_cid = entry_cid(&child);
868            let result = self.insert_recursive(child_cid, key, value).await?;
869
870            let mut new_node = self
871                .tree
872                .set_entry(
873                    &node,
874                    &[],
875                    &child_name,
876                    &result.cid,
877                    result.count,
878                    LinkType::Dir,
879                )
880                .await?;
881
882            if let Some(split) = result.split {
883                new_node = self.tree.remove_entry(&new_node, &[], &child_name).await?;
884                new_node = self
885                    .tree
886                    .set_entry(
887                        &new_node,
888                        &[],
889                        &escape_key(&split.left_first_key),
890                        &split.left,
891                        split.left_count,
892                        LinkType::Dir,
893                    )
894                    .await?;
895                new_node = self
896                    .tree
897                    .set_entry(
898                        &new_node,
899                        &[],
900                        &escape_key(&split.right_first_key),
901                        &split.right,
902                        split.right_count,
903                        LinkType::Dir,
904                    )
905                    .await?;
906            }
907
908            let new_entries = self.tree.list_directory(&new_node).await?;
909            if new_entries.len() > self.max_keys {
910                return Ok(InsertResult {
911                    cid: new_node,
912                    count: count_link_entries_or_subtrees(self, &new_entries).await?,
913                    split: Some(self.split_internal(new_entries).await?),
914                });
915            }
916
917            Ok(InsertResult {
918                cid: new_node,
919                count: count_link_entries_or_subtrees(self, &new_entries).await?,
920                split: None,
921            })
922        })
923    }
924
925    async fn split_leaf(&self, entries: Vec<TreeEntry>) -> Result<SplitResult, BTreeError> {
926        let sorted = sort_entries(entries);
927        let mid = sorted.len() / 2;
928        let left_entries = &sorted[..mid];
929        let right_entries = &sorted[mid..];
930
931        let left = self.create_node_from_entries(left_entries).await?;
932        let right = self.create_node_from_entries(right_entries).await?;
933
934        Ok(SplitResult {
935            left,
936            right,
937            left_first_key: unescape_key(&left_entries[0].name),
938            right_first_key: unescape_key(&right_entries[0].name),
939            left_count: count_link_entries(left_entries),
940            right_count: count_link_entries(right_entries),
941        })
942    }
943
944    async fn split_internal(&self, entries: Vec<TreeEntry>) -> Result<SplitResult, BTreeError> {
945        let sorted = sort_entries(entries);
946        let mid = sorted.len() / 2;
947        let left_entries = &sorted[..mid];
948        let right_entries = &sorted[mid..];
949
950        let left = self.create_node_from_entries(left_entries).await?;
951        let right = self.create_node_from_entries(right_entries).await?;
952
953        Ok(SplitResult {
954            left,
955            right,
956            left_first_key: unescape_key(&left_entries[0].name),
957            right_first_key: unescape_key(&right_entries[0].name),
958            left_count: count_link_entries_or_subtrees(self, left_entries).await?,
959            right_count: count_link_entries_or_subtrees(self, right_entries).await?,
960        })
961    }
962
963    async fn create_leaf(&self, items: &[(String, String)]) -> Result<Cid, BTreeError> {
964        let mut entries = Vec::with_capacity(items.len());
965        for (key, value) in items {
966            let (cid, size) = self.tree.put_file(value.as_bytes()).await?;
967            entries.push(
968                DirEntry::from_cid(escape_key(key), &cid)
969                    .with_size(size)
970                    .with_link_type(LinkType::Blob),
971            );
972        }
973        Ok(self.tree.put_directory(entries).await?)
974    }
975
976    async fn create_leaf_with_links(&self, items: &[(String, Cid)]) -> Result<Cid, BTreeError> {
977        let entries: Vec<DirEntry> = items
978            .iter()
979            .map(|(key, cid)| {
980                DirEntry::from_cid(escape_key(key), cid).with_link_type(LinkType::File)
981            })
982            .collect();
983        Ok(self.tree.put_directory(entries).await?)
984    }
985
986    async fn create_internal_node(&self, children: &[BuiltNode]) -> Result<Cid, BTreeError> {
987        let entries: Vec<DirEntry> = children
988            .iter()
989            .map(|child| {
990                DirEntry::from_cid(escape_key(&child.first_key), &child.cid)
991                    .with_size(child.count)
992                    .with_link_type(LinkType::Dir)
993            })
994            .collect();
995        Ok(self.tree.put_directory(entries).await?)
996    }
997
998    async fn create_internal_root(
999        &self,
1000        left_key: &str,
1001        left: &Cid,
1002        left_count: u64,
1003        right_key: &str,
1004        right: &Cid,
1005        right_count: u64,
1006    ) -> Result<Cid, BTreeError> {
1007        let entries = vec![
1008            DirEntry::from_cid(escape_key(left_key), left)
1009                .with_size(left_count)
1010                .with_link_type(LinkType::Dir),
1011            DirEntry::from_cid(escape_key(right_key), right)
1012                .with_size(right_count)
1013                .with_link_type(LinkType::Dir),
1014        ];
1015        Ok(self.tree.put_directory(entries).await?)
1016    }
1017
1018    async fn create_node_from_entries(&self, entries: &[TreeEntry]) -> Result<Cid, BTreeError> {
1019        let dir_entries = entries
1020            .iter()
1021            .cloned()
1022            .map(tree_entry_to_dir_entry)
1023            .collect::<Vec<_>>();
1024        Ok(self.tree.put_directory(dir_entries).await?)
1025    }
1026
1027    fn delete_recursive<'a>(&'a self, root: Cid, key: String) -> BTreeFuture<'a, Option<Cid>> {
1028        Box::pin(async move {
1029            let entries = self.tree.list_directory(&root).await?;
1030            if is_leaf_node(&entries) {
1031                let escaped = escape_key(&key);
1032                if !entries.iter().any(|entry| entry.name == escaped) {
1033                    return Ok(Some(root));
1034                }
1035
1036                let new_root = self.tree.remove_entry(&root, &[], &escaped).await?;
1037                let new_entries = self.tree.list_directory(&new_root).await?;
1038                if new_entries.is_empty() {
1039                    return Ok(None);
1040                }
1041                return Ok(Some(new_root));
1042            }
1043
1044            let child = find_child(&entries, &key);
1045            let child_name = child.name.clone();
1046            let new_child = self.delete_recursive(entry_cid(&child), key).await?;
1047
1048            let Some(new_child) = new_child else {
1049                let new_root = self.tree.remove_entry(&root, &[], &child_name).await?;
1050                let new_entries = self.tree.list_directory(&new_root).await?;
1051                if new_entries.is_empty() {
1052                    return Ok(None);
1053                }
1054                if new_entries.len() == 1 && new_entries[0].link_type == LinkType::Dir {
1055                    return Ok(Some(entry_cid(&new_entries[0])));
1056                }
1057                return Ok(Some(new_root));
1058            };
1059
1060            if cid_equals(&new_child, &entry_cid(&child)) {
1061                return Ok(Some(root));
1062            }
1063
1064            let updated = self
1065                .tree
1066                .set_entry(
1067                    &root,
1068                    &[],
1069                    &child_name,
1070                    &new_child,
1071                    count_link_entries_or_subtrees(
1072                        self,
1073                        &self.tree.list_directory(&new_child).await?,
1074                    )
1075                    .await?,
1076                    LinkType::Dir,
1077                )
1078                .await?;
1079            Ok(Some(updated))
1080        })
1081    }
1082
1083    fn traverse_in_order<'a>(&'a self, node: Cid) -> BTreeFuture<'a, Vec<(String, String)>> {
1084        Box::pin(async move {
1085            let entries = self.tree.list_directory(&node).await?;
1086            let sorted = sort_entries(entries);
1087            let mut out = Vec::new();
1088
1089            if is_leaf_node(&sorted) {
1090                for entry in sorted {
1091                    if entry.link_type != LinkType::Blob {
1092                        continue;
1093                    }
1094                    let cid = entry_cid(&entry);
1095                    if let Some(data) = self.tree.get(&cid, None).await? {
1096                        out.push((unescape_key(&entry.name), String::from_utf8(data)?));
1097                    }
1098                }
1099                return Ok(out);
1100            }
1101
1102            for child in sorted {
1103                out.extend(self.traverse_in_order(entry_cid(&child)).await?);
1104            }
1105            Ok(out)
1106        })
1107    }
1108
1109    fn traverse_links_in_order<'a>(&'a self, node: Cid) -> BTreeFuture<'a, Vec<(String, Cid)>> {
1110        Box::pin(async move {
1111            let entries = self.tree.list_directory(&node).await?;
1112            let sorted = sort_entries(entries);
1113            let mut out = Vec::new();
1114
1115            if is_leaf_node(&sorted) {
1116                for entry in sorted {
1117                    if entry.link_type == LinkType::File {
1118                        out.push((unescape_key(&entry.name), entry_cid(&entry)));
1119                    }
1120                }
1121                return Ok(out);
1122            }
1123
1124            for child in sorted {
1125                out.extend(self.traverse_links_in_order(entry_cid(&child)).await?);
1126            }
1127            Ok(out)
1128        })
1129    }
1130
1131    fn range_traverse<'a>(
1132        &'a self,
1133        node: Cid,
1134        start: Option<String>,
1135        end: Option<String>,
1136    ) -> BTreeFuture<'a, Vec<(String, String)>> {
1137        Box::pin(async move {
1138            let entries = self.tree.list_directory(&node).await?;
1139            let sorted = sort_entries(entries);
1140            let mut out = Vec::new();
1141
1142            if is_leaf_node(&sorted) {
1143                for entry in sorted {
1144                    if entry.link_type != LinkType::Blob {
1145                        continue;
1146                    }
1147                    let key = unescape_key(&entry.name);
1148                    if start.as_ref().is_some_and(|start| key < *start) {
1149                        continue;
1150                    }
1151                    if end.as_ref().is_some_and(|end| key >= *end) {
1152                        return Ok(out);
1153                    }
1154
1155                    let cid = entry_cid(&entry);
1156                    if let Some(data) = self.tree.get(&cid, None).await? {
1157                        out.push((key, String::from_utf8(data)?));
1158                    }
1159                }
1160                return Ok(out);
1161            }
1162
1163            for (index, child) in sorted.iter().enumerate() {
1164                let child_min = unescape_key(&child.name);
1165                let child_max = sorted.get(index + 1).map(|entry| unescape_key(&entry.name));
1166
1167                if start.as_ref().is_some_and(|start| {
1168                    child_max
1169                        .as_ref()
1170                        .is_some_and(|child_max| child_max <= start)
1171                }) {
1172                    continue;
1173                }
1174                if end.as_ref().is_some_and(|end| child_min >= *end) {
1175                    return Ok(out);
1176                }
1177
1178                out.extend(
1179                    self.range_traverse(entry_cid(child), start.clone(), end.clone())
1180                        .await?,
1181                );
1182            }
1183
1184            Ok(out)
1185        })
1186    }
1187
1188    fn range_link_traverse<'a>(
1189        &'a self,
1190        node: Cid,
1191        start: Option<String>,
1192        end: Option<String>,
1193    ) -> BTreeFuture<'a, Vec<(String, Cid)>> {
1194        Box::pin(async move {
1195            let entries = self.tree.list_directory(&node).await?;
1196            let sorted = sort_entries(entries);
1197            let mut out = Vec::new();
1198
1199            if is_leaf_node(&sorted) {
1200                for entry in sorted {
1201                    if entry.link_type != LinkType::File {
1202                        continue;
1203                    }
1204                    let key = unescape_key(&entry.name);
1205                    if start.as_ref().is_some_and(|start| key < *start) {
1206                        continue;
1207                    }
1208                    if end.as_ref().is_some_and(|end| key >= *end) {
1209                        return Ok(out);
1210                    }
1211                    out.push((key, entry_cid(&entry)));
1212                }
1213                return Ok(out);
1214            }
1215
1216            for (index, child) in sorted.iter().enumerate() {
1217                let child_min = unescape_key(&child.name);
1218                let child_max = sorted.get(index + 1).map(|entry| unescape_key(&entry.name));
1219
1220                if start.as_ref().is_some_and(|start| {
1221                    child_max
1222                        .as_ref()
1223                        .is_some_and(|child_max| child_max <= start)
1224                }) {
1225                    continue;
1226                }
1227                if end.as_ref().is_some_and(|end| child_min >= *end) {
1228                    return Ok(out);
1229                }
1230
1231                out.extend(
1232                    self.range_link_traverse(entry_cid(child), start.clone(), end.clone())
1233                        .await?,
1234                );
1235            }
1236
1237            Ok(out)
1238        })
1239    }
1240
1241    fn range_link_traverse_limited<'a>(
1242        &'a self,
1243        node: Cid,
1244        start: Option<String>,
1245        end: Option<String>,
1246        limit: usize,
1247    ) -> BTreeFuture<'a, Vec<(String, Cid)>> {
1248        Box::pin(async move {
1249            let entries = self.tree.list_directory(&node).await?;
1250            let sorted = sort_entries(entries);
1251            let mut out = Vec::new();
1252
1253            if is_leaf_node(&sorted) {
1254                for entry in sorted {
1255                    if entry.link_type != LinkType::File {
1256                        continue;
1257                    }
1258                    let key = unescape_key(&entry.name);
1259                    if start.as_ref().is_some_and(|start| key < *start) {
1260                        continue;
1261                    }
1262                    if end.as_ref().is_some_and(|end| key >= *end) {
1263                        return Ok(out);
1264                    }
1265                    out.push((key, entry_cid(&entry)));
1266                    if out.len() >= limit {
1267                        return Ok(out);
1268                    }
1269                }
1270                return Ok(out);
1271            }
1272
1273            for (index, child) in sorted.iter().enumerate() {
1274                let child_min = unescape_key(&child.name);
1275                let child_max = sorted.get(index + 1).map(|entry| unescape_key(&entry.name));
1276
1277                if start.as_ref().is_some_and(|start| {
1278                    child_max
1279                        .as_ref()
1280                        .is_some_and(|child_max| child_max <= start)
1281                }) {
1282                    continue;
1283                }
1284                if end.as_ref().is_some_and(|end| child_min >= *end) {
1285                    return Ok(out);
1286                }
1287
1288                let remaining = limit.saturating_sub(out.len());
1289                if remaining == 0 {
1290                    return Ok(out);
1291                }
1292                out.extend(
1293                    self.range_link_traverse_limited(
1294                        entry_cid(child),
1295                        start.clone(),
1296                        end.clone(),
1297                        remaining,
1298                    )
1299                    .await?,
1300                );
1301                if out.len() >= limit {
1302                    return Ok(out);
1303                }
1304            }
1305
1306            Ok(out)
1307        })
1308    }
1309
1310    fn count_links_recursive<'a>(&'a self, node: Cid) -> BTreeFuture<'a, u64> {
1311        Box::pin(async move {
1312            let entries = self.tree.list_directory(&node).await?;
1313            count_link_entries_or_subtrees(self, &entries).await
1314        })
1315    }
1316
1317    fn count_entries_recursive<'a>(&'a self, node: Cid) -> BTreeFuture<'a, u64> {
1318        Box::pin(async move {
1319            let entries = self.tree.list_directory(&node).await?;
1320            if is_leaf_node(&entries) {
1321                return Ok(entries
1322                    .iter()
1323                    .filter(|entry| entry.link_type == LinkType::Blob)
1324                    .count() as u64);
1325            }
1326
1327            let mut count = 0;
1328            for entry in entries {
1329                count += match stored_link_subtree_count(&entry) {
1330                    Some(child_count) => child_count,
1331                    None => self.count_entries_recursive(entry_cid(&entry)).await?,
1332                };
1333            }
1334            Ok(count)
1335        })
1336    }
1337}
1338
1339#[derive(Debug, Clone)]
1340struct InsertResult {
1341    cid: Cid,
1342    count: u64,
1343    split: Option<SplitResult>,
1344}
1345
1346pub fn escape_key(key: &str) -> String {
1347    key.replace('%', "%25")
1348        .replace('/', "%2F")
1349        .replace('\0', "%00")
1350}
1351
1352pub fn unescape_key(name: &str) -> String {
1353    name.replace("%2F", "/")
1354        .replace("%2f", "/")
1355        .replace("%00", "\0")
1356        .replace("%25", "%")
1357}
1358
1359fn increment_prefix(value: &str) -> Option<String> {
1360    if value.is_empty() {
1361        return Some(String::new());
1362    }
1363
1364    let mut chars: Vec<char> = value.chars().collect();
1365    let last = chars.pop()?;
1366    let next = char::from_u32(last as u32 + 1)?;
1367    chars.push(next);
1368    Some(chars.into_iter().collect())
1369}
1370
1371fn cid_equals(left: &Cid, right: &Cid) -> bool {
1372    left.hash == right.hash && left.key == right.key
1373}
1374
1375fn is_leaf_node(entries: &[TreeEntry]) -> bool {
1376    entries.is_empty() || entries.iter().any(|entry| entry.link_type != LinkType::Dir)
1377}
1378
1379fn sort_entries(mut entries: Vec<TreeEntry>) -> Vec<TreeEntry> {
1380    entries.sort_by(|left, right| compare_unescaped_names(&left.name, &right.name));
1381    entries
1382}
1383
1384fn compare_unescaped_names(left: &str, right: &str) -> Ordering {
1385    unescape_key(left).cmp(&unescape_key(right))
1386}
1387
1388fn find_child(entries: &[TreeEntry], key: &str) -> TreeEntry {
1389    let sorted = sort_entries(entries.to_vec());
1390    for window in sorted.windows(2) {
1391        let next_name = unescape_key(&window[1].name);
1392        if key < next_name.as_str() {
1393            return window[0].clone();
1394        }
1395    }
1396    sorted
1397        .last()
1398        .cloned()
1399        .expect("internal nodes must have children")
1400}
1401
1402fn entry_cid(entry: &TreeEntry) -> Cid {
1403    Cid {
1404        hash: entry.hash,
1405        key: entry.key,
1406    }
1407}
1408
1409fn tree_entry_to_dir_entry(entry: TreeEntry) -> DirEntry {
1410    let mut out = DirEntry::from_cid(&entry.name, &entry_cid(&entry))
1411        .with_size(entry.size)
1412        .with_link_type(entry.link_type);
1413    if let Some(meta) = entry.meta {
1414        out = out.with_meta(meta);
1415    }
1416    out
1417}
1418
1419fn count_link_entries(entries: &[TreeEntry]) -> u64 {
1420    entries
1421        .iter()
1422        .filter(|entry| entry.link_type == LinkType::File)
1423        .count() as u64
1424}
1425
1426fn stored_link_subtree_count(entry: &TreeEntry) -> Option<u64> {
1427    if entry.link_type != LinkType::Dir || entry.size == 0 {
1428        return None;
1429    }
1430    Some(entry.size)
1431}
1432
1433async fn count_link_entries_or_subtrees<S: Store>(
1434    btree: &BTree<S>,
1435    entries: &[TreeEntry],
1436) -> Result<u64, BTreeError> {
1437    if is_leaf_node(entries) {
1438        return Ok(count_link_entries(entries));
1439    }
1440
1441    let mut count = 0;
1442    for entry in entries {
1443        count += match stored_link_subtree_count(entry) {
1444            Some(child_count) => child_count,
1445            None => btree.count_links_recursive(entry_cid(entry)).await?,
1446        };
1447    }
1448    Ok(count)
1449}