lastfm_edit/discovery/
discovery_iterator.rs

1use crate::Result;
2use async_trait::async_trait;
3
4/// Async iterator trait for discovering scrobble edits incrementally
5///
6/// This trait is designed for iterators that yield individual results one at a time,
7/// unlike AsyncPaginatedIterator which is designed for page-based iteration.
8/// This is particularly useful for discovery operations that might make many API
9/// requests and need to avoid rate limiting by yielding results incrementally.
10#[async_trait(?Send)]
11pub trait AsyncDiscoveryIterator<T> {
12    /// Get the next item from the iterator
13    ///
14    /// Returns `Ok(Some(item))` if there's a next item available,
15    /// `Ok(None)` if the iterator is exhausted, or `Err(e)` if an error occurred.
16    async fn next(&mut self) -> Result<Option<T>>;
17
18    /// Collect all remaining items from the iterator into a Vec
19    ///
20    /// This is a convenience method that calls `next()` repeatedly until
21    /// the iterator is exhausted and collects all results.
22    async fn collect_all(&mut self) -> Result<Vec<T>> {
23        let mut items = Vec::new();
24        while let Some(item) = self.next().await? {
25            items.push(item);
26        }
27        Ok(items)
28    }
29
30    /// Take the first `n` items from the iterator
31    ///
32    /// This stops after collecting `n` items or when the iterator is exhausted,
33    /// whichever comes first.
34    async fn take(&mut self, n: usize) -> Result<Vec<T>> {
35        let mut items = Vec::with_capacity(n);
36        for _ in 0..n {
37            if let Some(item) = self.next().await? {
38                items.push(item);
39            } else {
40                break;
41            }
42        }
43        Ok(items)
44    }
45}