Skip to main content

firewood_ffi/
iterator.rs

1// Copyright (C) 2025, Ava Labs, Inc. All rights reserved.
2// See the file LICENSE.md for licensing terms.
3
4use std::fmt;
5
6use firewood::api::{self, ArcDynDbView, BoxKeyValueIter};
7use firewood::merkle;
8use firewood_metrics::MetricsContext;
9use std::iter::FusedIterator;
10
11type KeyValueItem = (merkle::Key, merkle::Value);
12
13/// An opaque wrapper around a [`BoxKeyValueIter`] and a reference
14/// to the [`ArcDynDbView`] backing it, preventing the view from
15/// being dropped while iteration is in progress.
16#[derive(Default)]
17pub struct IteratorHandle<'view> {
18    iter: Option<BoxKeyValueIter<'view>>,
19    view: Option<ArcDynDbView>,
20    metrics_context: Option<MetricsContext>,
21}
22
23impl fmt::Debug for IteratorHandle<'_> {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        f.debug_struct("IteratorHandle")
26            .field("metrics_context", &self.metrics_context)
27            .finish_non_exhaustive()
28    }
29}
30
31impl<'view> IteratorHandle<'view> {
32    #[must_use]
33    pub(crate) fn new(
34        view: ArcDynDbView,
35        iter: BoxKeyValueIter<'view>,
36        metrics_context: Option<MetricsContext>,
37    ) -> Self {
38        Self {
39            iter: Some(iter),
40            view: Some(view),
41            metrics_context,
42        }
43    }
44}
45
46impl Iterator for IteratorHandle<'_> {
47    type Item = Result<KeyValueItem, api::Error>;
48
49    fn next(&mut self) -> Option<Self::Item> {
50        let out = self.iter.as_mut()?.next();
51        if out.is_none() {
52            // iterator exhausted; drop it so the NodeStore can be released
53            self.iter = None;
54            self.view = None;
55        }
56        out.map(|res| res.map_err(api::Error::from))
57    }
58}
59
60impl FusedIterator for IteratorHandle<'_> {}
61
62#[expect(clippy::missing_errors_doc)]
63impl IteratorHandle<'_> {
64    pub fn iter_next_n(&mut self, n: usize) -> Result<Vec<KeyValueItem>, api::Error> {
65        self.by_ref().take(n).collect()
66    }
67}
68
69#[derive(Debug, Default)]
70pub struct CreateIteratorResult<'db>(pub IteratorHandle<'db>);
71
72impl crate::MetricsContextExt for IteratorHandle<'_> {
73    fn metrics_context(&self) -> Option<MetricsContext> {
74        self.metrics_context
75    }
76}