virustotal_rs/iterator_utils/
traits.rs

1//! Core traits for iterator utilities
2
3use std::time::Duration;
4
5/// Generic paginated iterator trait for API responses
6#[async_trait::async_trait]
7pub trait PaginatedIterator<T: Send> {
8    type Error: std::error::Error + Send + Sync + 'static;
9
10    /// Fetch the next batch of items
11    async fn next_batch(&mut self) -> std::result::Result<Vec<T>, Self::Error>;
12
13    /// Check if there are more items to fetch
14    fn has_more(&self) -> bool;
15
16    /// Collect all remaining items
17    async fn collect_all(mut self) -> std::result::Result<Vec<T>, Self::Error>
18    where
19        Self: Sized,
20    {
21        let mut all_items = Vec::new();
22
23        while self.has_more() {
24            let batch = self.next_batch().await?;
25            if batch.is_empty() {
26                break;
27            }
28            all_items.extend(batch);
29        }
30
31        Ok(all_items)
32    }
33
34    /// Get an approximation of items remaining if available
35    fn hint_remaining(&self) -> Option<usize> {
36        None
37    }
38
39    /// Get statistics about fetching
40    fn stats(&self) -> IteratorStats {
41        IteratorStats::default()
42    }
43}
44
45/// Trait for items that can be paged
46pub trait Pageable<T>
47where
48    T: Send,
49{
50    /// Get items for a specific page
51    fn get_page(
52        &self,
53        page: u32,
54        page_size: Option<u32>,
55    ) -> impl std::future::Future<
56        Output = std::result::Result<Vec<T>, Box<dyn std::error::Error + Send + Sync>>,
57    > + Send;
58}
59
60/// Extension trait providing additional iterator functionality
61#[async_trait::async_trait]
62pub trait IteratorExt<T: Send>: PaginatedIterator<T> {
63    /// Map items to a different type
64    fn map<U, F>(self, mapper: F) -> super::adapters::MappedIterator<Self, T, U, F>
65    where
66        Self: Sized,
67        U: Send,
68        F: Fn(T) -> U + Send + Sync,
69    {
70        super::adapters::MappedIterator::new(self, mapper)
71    }
72
73    /// Filter items based on a predicate
74    fn filter<F>(self, predicate: F) -> super::adapters::FilteredIterator<Self, T, F>
75    where
76        Self: Sized,
77        F: Fn(&T) -> bool + Send + Sync,
78    {
79        super::adapters::FilteredIterator::new(self, predicate)
80    }
81
82    /// Take items until a condition is met
83    fn take_until<F>(self, condition: F) -> super::adapters::TakeUntilIterator<Self, T, F>
84    where
85        Self: Sized,
86        F: Fn(&T) -> bool + Send + Sync,
87    {
88        super::adapters::TakeUntilIterator::new(self, condition)
89    }
90
91    /// Batch items into chunks
92    fn batch(self, size: usize) -> super::adapters::BatchIterator<Self, T>
93    where
94        Self: Sized,
95    {
96        super::adapters::BatchIterator::new(self, size)
97    }
98
99    /// Throttle iteration with delays
100    fn throttle(self, delay: Duration) -> super::adapters::ThrottledIterator<Self, T>
101    where
102        Self: Sized,
103    {
104        super::adapters::ThrottledIterator::new(self, delay)
105    }
106
107    /// Add retry logic to iterations
108    fn retry(
109        self,
110        max_retries: u32,
111        base_delay: Duration,
112    ) -> super::adapters::RetryIterator<Self, T>
113    where
114        Self: Sized,
115    {
116        super::adapters::RetryIterator::new(self, max_retries, base_delay)
117    }
118
119    /// Add progress tracking
120    fn with_progress(
121        self,
122        tracker: super::progress::ProgressTracker,
123    ) -> super::adapters::ProgressIterator<Self, T>
124    where
125        Self: Sized,
126    {
127        super::adapters::ProgressIterator::new(self, tracker)
128    }
129
130    /// Cache results for repeated iteration
131    fn cached(self) -> super::adapters::CachedIterator<Self, T>
132    where
133        Self: Sized,
134    {
135        super::adapters::CachedIterator::new(self)
136    }
137
138    /// Skip a number of items
139    fn skip(self, count: usize) -> super::adapters::SkippedIterator<Self, T>
140    where
141        Self: Sized,
142    {
143        super::adapters::SkippedIterator::new(self, count)
144    }
145}
146
147/// Blanket implementation of IteratorExt for all PaginatedIterator types
148impl<I, T: Send> IteratorExt<T> for I where I: PaginatedIterator<T> {}
149
150/// Statistics for iterator performance
151#[derive(Debug, Clone, Default)]
152pub struct IteratorStats {
153    /// Number of batches fetched
154    pub batches_fetched: u64,
155    /// Total items fetched
156    pub items_fetched: u64,
157    /// Total time spent fetching
158    pub fetch_duration: Duration,
159    /// Number of retries performed
160    pub retries: u32,
161}
162
163/// Trait for collecting iterator results
164#[async_trait::async_trait]
165pub trait Collectable<T: Send> {
166    type Error: std::error::Error + Send + Sync + 'static;
167
168    /// Take a specific number of items
169    async fn take(self, n: usize) -> std::result::Result<Vec<T>, Self::Error>
170    where
171        Self: Sized;
172
173    /// Take items while a condition is true
174    async fn take_while<F>(self, predicate: F) -> std::result::Result<Vec<T>, Self::Error>
175    where
176        Self: Sized,
177        F: Fn(&T) -> bool + Send;
178
179    /// Collect all items
180    async fn collect_all(self) -> std::result::Result<Vec<T>, Self::Error>
181    where
182        Self: Sized;
183}
184
185/// Implementation of Collectable for all PaginatedIterator types
186#[async_trait::async_trait]
187impl<I, T> Collectable<T> for I
188where
189    I: PaginatedIterator<T> + Send,
190    T: Send,
191{
192    type Error = I::Error;
193
194    async fn take(mut self, n: usize) -> std::result::Result<Vec<T>, Self::Error> {
195        let mut result = Vec::with_capacity(n.min(1000));
196
197        while result.len() < n && self.has_more() {
198            let batch = self.next_batch().await?;
199            if batch.is_empty() {
200                break;
201            }
202
203            for item in batch {
204                if result.len() >= n {
205                    break;
206                }
207                result.push(item);
208            }
209        }
210
211        Ok(result)
212    }
213
214    async fn take_while<F>(mut self, predicate: F) -> std::result::Result<Vec<T>, Self::Error>
215    where
216        Self: Sized,
217        F: Fn(&T) -> bool + Send,
218    {
219        let mut result = Vec::new();
220
221        while self.has_more() {
222            let batch = self.next_batch().await?;
223            if batch.is_empty() {
224                break;
225            }
226
227            for item in batch {
228                if !predicate(&item) {
229                    return Ok(result);
230                }
231                result.push(item);
232            }
233        }
234
235        Ok(result)
236    }
237
238    async fn collect_all(self) -> std::result::Result<Vec<T>, Self::Error>
239    where
240        Self: Sized,
241    {
242        PaginatedIterator::collect_all(self).await
243    }
244}