Skip to main content

moirai_iter/facade/
mod.rs

1//! Public iterator facade preserving execution context without string dispatch.
2
3use crate::async_iter::{AsyncIterator, AsyncRangeIter};
4use crate::execution::{AsyncContext, ExecutionContext, HybridContext, ParallelContext};
5use crate::parallel::{ParallelIterator, RangeParIter};
6
7/// Main iterator type that adapts to different execution contexts.
8pub struct MoiraiIterator<T> {
9    data: Vec<T>,
10    context: ExecutionContext,
11}
12
13impl<T: Send + 'static> MoiraiIterator<T> {
14    /// Create a new iterator with the given execution context.
15    pub fn new(data: Vec<T>, context: ExecutionContext) -> Self {
16        Self { data, context }
17    }
18
19    /// Create with parallel context.
20    pub fn parallel(data: Vec<T>) -> Self {
21        Self::new(data, ExecutionContext::Parallel(ParallelContext::new()))
22    }
23
24    /// Create with async context.
25    pub fn async_iter(data: Vec<T>) -> Self {
26        Self::new(data, ExecutionContext::Async(AsyncContext::new()))
27    }
28
29    /// Create with hybrid context.
30    pub fn hybrid(data: Vec<T>) -> Self {
31        Self::new(data, ExecutionContext::Hybrid(HybridContext::new()))
32    }
33
34    /// Map operation that preserves the execution context.
35    pub fn map<F, R>(self, func: F) -> MoiraiIterator<R>
36    where
37        F: Fn(T) -> R + Send + Sync + 'static,
38        R: Send + 'static,
39    {
40        let Self { data, context } = self;
41        let results = context
42            .execute_iter(data, func)
43            .expect("iterator map execution must not fail");
44
45        MoiraiIterator::new(results, context)
46    }
47
48    /// Async map operation for I/O-bound transformations.
49    pub async fn map_async<F, Fut, R>(self, func: F) -> MoiraiIterator<R>
50    where
51        F: Fn(T) -> Fut + Send + Sync + 'static,
52        Fut: std::future::Future<Output = R> + Send + 'static,
53        R: Send + 'static,
54    {
55        let Self { data, context } = self;
56        let results = context
57            .execute_async_iter(data, func)
58            .await
59            .expect("async iterator map execution must not fail");
60
61        MoiraiIterator::new(results, context)
62    }
63
64    /// Filter operation.
65    pub fn filter<F>(self, predicate: F) -> MoiraiIterator<T>
66    where
67        F: Fn(&T) -> bool + Send + Sync + 'static,
68    {
69        let Self { data, context } = self;
70        let filtered = data.into_iter().filter(|item| predicate(item)).collect();
71
72        MoiraiIterator::new(filtered, context)
73    }
74
75    /// Async filter operation.
76    pub async fn filter_async<F, Fut>(self, predicate: F) -> MoiraiIterator<T>
77    where
78        F: Fn(&T) -> Fut + Send + Sync + 'static,
79        Fut: std::future::Future<Output = bool> + Send + 'static,
80    {
81        let Self { data, context } = self;
82        let results = context
83            .execute_async_filter(data, predicate)
84            .await
85            .expect("async iterator filter execution must not fail");
86
87        MoiraiIterator::new(results, context)
88    }
89
90    /// Collect the results.
91    pub async fn collect(self) -> Vec<T> {
92        self.data
93    }
94
95    /// Async collect that waits for all tasks to complete.
96    pub async fn collect_async(self) -> Vec<T> {
97        self.collect().await
98    }
99
100    /// Reduce operation.
101    pub async fn reduce<F>(self, func: F) -> Option<T>
102    where
103        F: Fn(T, T) -> T + Send + Sync + 'static,
104    {
105        self.data.into_iter().reduce(func)
106    }
107
108    /// Parallel reduce with work-stealing.
109    pub async fn reduce_parallel<F>(self, func: F) -> Option<T>
110    where
111        F: Fn(T, T) -> T + Send + Sync + 'static,
112    {
113        self.context
114            .execute_reduce(self.data, func)
115            .await
116            .expect("iterator reduce execution must not fail")
117    }
118
119    /// For each operation with side effects.
120    pub async fn for_each<F>(self, func: F)
121    where
122        F: Fn(T) + Send + Sync + 'static,
123    {
124        self.context
125            .execute_iter(self.data, func)
126            .expect("iterator for_each execution must not fail");
127    }
128
129    /// Async for each operation.
130    pub async fn for_each_async<F, Fut>(self, func: F)
131    where
132        F: Fn(T) -> Fut + Send + Sync + 'static,
133        Fut: std::future::Future<Output = ()> + Send + 'static,
134    {
135        self.context
136            .execute_async_for_each(self.data, func)
137            .await
138            .expect("async iterator for_each execution must not fail");
139    }
140
141    /// Convert to async stream for streaming processing.
142    pub fn into_async_stream(self) -> impl futures::Stream<Item = T> + Send + 'static
143    where
144        T: 'static,
145    {
146        futures::stream::iter(self.data)
147    }
148}
149
150/// Convenience function to create a Moirai iterator.
151pub fn moirai_iter<T: Send + 'static>(data: Vec<T>) -> MoiraiIterator<T> {
152    MoiraiIterator::hybrid(data)
153}
154
155/// Create a parallel iterator.
156pub fn moirai_iter_parallel<T: Send + 'static>(data: Vec<T>) -> MoiraiIterator<T> {
157    MoiraiIterator::parallel(data)
158}
159
160/// Create an async iterator.
161pub fn moirai_iter_async<T: Send + 'static>(data: Vec<T>) -> MoiraiIterator<T> {
162    MoiraiIterator::async_iter(data)
163}
164
165/// Create a hybrid iterator.
166pub fn moirai_iter_hybrid<T: Send + 'static>(data: Vec<T>) -> MoiraiIterator<T> {
167    MoiraiIterator::hybrid(data)
168}
169
170/// Parallel range iterator for Moirai's Rayon-style non-indexed subset.
171pub fn par_range(start: usize, end: usize) -> impl ParallelIterator<Item = usize> {
172    RangeParIter::new(start, end)
173}
174
175/// Async range iterator.
176pub fn async_range(start: usize, end: usize) -> impl AsyncIterator<Item = usize> {
177    AsyncRangeIter::new(start, end)
178}
179
180#[cfg(test)]
181mod tests {
182    use super::*;
183
184    #[test]
185    fn map_preserves_context_without_string_dispatch() {
186        let values = MoiraiIterator::parallel(vec![1_u64, 2, 3])
187            .map(|value| value * 2)
188            .context
189            .context_type();
190
191        assert_eq!(values, "Parallel");
192    }
193
194    #[tokio::test]
195    async fn facade_map_filter_reduce_preserve_value_semantics() {
196        let values = moirai_iter_hybrid(vec![1_u64, 2, 3, 4, 5])
197            .map(|value| value * 3)
198            .filter(|value| value % 2 == 1)
199            .collect()
200            .await;
201        assert_eq!(values, vec![3, 9, 15]);
202
203        let reduced = moirai_iter_parallel(vec![1_u64, 2, 3, 4])
204            .reduce_parallel(|left, right| left + right)
205            .await;
206        assert_eq!(reduced, Some(10));
207    }
208}