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}