iroh_docs/store/
util.rs

1//! Utilities useful across different store impls.
2
3use super::{AuthorFilter, KeyFilter, Query, QueryKind, SortBy};
4use crate::SignedEntry;
5
6/// A helper for stores that have by-author and by-key indexes for records.
7#[derive(Debug)]
8pub enum IndexKind {
9    AuthorKey {
10        range: AuthorFilter,
11        key_filter: KeyFilter,
12    },
13    KeyAuthor {
14        range: KeyFilter,
15        author_filter: AuthorFilter,
16        latest_per_key: bool,
17    },
18}
19
20impl From<&Query> for IndexKind {
21    fn from(query: &Query) -> Self {
22        match &query.kind {
23            QueryKind::Flat(details) => match (&query.filter_author, details.sort_by) {
24                (AuthorFilter::Any, SortBy::KeyAuthor) => IndexKind::KeyAuthor {
25                    range: query.filter_key.clone(),
26                    author_filter: AuthorFilter::Any,
27                    latest_per_key: false,
28                },
29                _ => IndexKind::AuthorKey {
30                    range: query.filter_author.clone(),
31                    key_filter: query.filter_key.clone(),
32                },
33            },
34            QueryKind::SingleLatestPerKey(_) => IndexKind::KeyAuthor {
35                range: query.filter_key.clone(),
36                author_filter: query.filter_author.clone(),
37                latest_per_key: true,
38            },
39        }
40    }
41}
42
43/// Helper to extract the latest entry per key from an iterator that yields [`SignedEntry`] items.
44///
45/// Items must be pushed in key-sorted order.
46#[derive(Debug, Default)]
47pub struct LatestPerKeySelector(Option<SignedEntry>);
48
49#[allow(clippy::large_enum_variant)]
50pub enum SelectorRes {
51    /// The iterator is finished.
52    Finished,
53    /// The selection is not yet finished, keep pushing more items.
54    Continue,
55    /// The selection yielded an entry.
56    Some(SignedEntry),
57}
58
59impl LatestPerKeySelector {
60    /// Push an entry into the selector.
61    ///
62    /// Entries must be sorted by key beforehand.
63    pub fn push(&mut self, entry: Option<SignedEntry>) -> SelectorRes {
64        let Some(entry) = entry else {
65            return match self.0.take() {
66                Some(entry) => SelectorRes::Some(entry),
67                None => SelectorRes::Finished,
68            };
69        };
70        match self.0.take() {
71            None => {
72                self.0 = Some(entry);
73                SelectorRes::Continue
74            }
75            Some(last) if last.key() == entry.key() => {
76                if entry.timestamp() > last.timestamp() {
77                    self.0 = Some(entry);
78                } else {
79                    self.0 = Some(last);
80                }
81                SelectorRes::Continue
82            }
83            Some(last) => {
84                self.0 = Some(entry);
85                SelectorRes::Some(last)
86            }
87        }
88    }
89}