Skip to content

Commit d8d0576

Browse files
committed
add support for immovable coroutine (self referenced)
1 parent ecbdae4 commit d8d0576

File tree

3 files changed

+173
-6
lines changed

3 files changed

+173
-6
lines changed

src/gen_iter.rs

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ use core::pin::Pin;
55

66
/// an iterator that holds an internal coroutine representing
77
/// the iteration state
8+
///
9+
/// # Example
10+
/// pin a self-referenced coroutine in heap, then use it as `Iterator`
11+
/// ```
12+
/// #![feature(coroutines)]
13+
///
14+
/// use gen_iter::GenIter;
15+
/// use std::boxed::Box;
16+
///
17+
/// let arr = [1, 2];
18+
/// let c = Box::pin(#[coroutine] static move || {
19+
/// let arr = &arr;
20+
/// for i in 0..arr.len() {
21+
/// yield arr[i];
22+
/// }
23+
/// });
24+
/// let mut g = GenIter(c);
25+
///
26+
/// assert_eq!(g.collect::<Vec<i32>>(), [1, 2]);
27+
/// ```
828
#[derive(Copy, Clone, Debug)]
929
pub struct GenIter<T>(pub T)
1030
where
@@ -38,6 +58,7 @@ where
3858

3959
/// macro to simplify iterator - via - coroutine construction
4060
///
61+
/// - movable coroutine as `Iterator`
4162
/// ```
4263
/// #![feature(coroutines)]
4364
///
@@ -48,10 +69,24 @@ where
4869
/// yield 2;
4970
/// });
5071
///
51-
/// assert_eq!(g.next(), Some(1));
52-
/// assert_eq!(g.next(), Some(2));
53-
/// assert_eq!(g.next(), None);
72+
/// assert_eq!(g.collect::<Vec<i32>>(), [1, 2]);
73+
/// ```
74+
///
75+
/// - immovable coroutine (self referenced) as `Iterator`
76+
/// ```
77+
/// #![feature(coroutines)]
78+
///
79+
/// use gen_iter::gen_iter;
80+
///
81+
/// let arr = [1, 2];
82+
/// let mut g = gen_iter!(static move {
83+
/// let arr = &arr;
84+
/// for i in 0..arr.len() {
85+
/// yield arr[i];
86+
/// }
87+
/// });
5488
///
89+
/// assert_eq!(g.collect::<Vec<i32>>(), [1, 2]);
5590
/// ```
5691
#[macro_export]
5792
macro_rules! gen_iter {
@@ -60,7 +95,14 @@ macro_rules! gen_iter {
6095
};
6196
(move $block: block) => {
6297
$crate::GenIter(#[coroutine] move || $block)
63-
}
98+
};
99+
100+
(static $block: block) => {
101+
$crate::GenIter { 0: ::core::pin::pin!(#[coroutine] static || $block) }
102+
};
103+
(static move $block: block) => {
104+
$crate::GenIter { 0: ::core::pin::pin!(#[coroutine] static move || $block) }
105+
};
64106
}
65107

66108

@@ -106,4 +148,50 @@ mod tests {
106148
assert_eq!(g.next(), Some(2));
107149
assert_eq!(g.next(), None);
108150
}
151+
152+
#[test]
153+
fn self_ref_coroutine_in_stack() {
154+
let c = ::core::pin::pin!(#[coroutine] static || {
155+
let v1 = [1, 2];
156+
let v = &v1;
157+
for i in 0..v.len() {
158+
yield v[i];
159+
}
160+
});
161+
let mut g = GenIter(c);
162+
163+
assert_eq!(g.next(), Some(1));
164+
assert_eq!(g.next(), Some(2));
165+
assert_eq!(g.next(), None);
166+
}
167+
168+
#[test]
169+
fn gen_iter_macro_static() {
170+
let mut g = gen_iter!(static {
171+
let v1 = [1, 2];
172+
let v = &v1;
173+
for i in 0..v.len() {
174+
yield v[i];
175+
}
176+
});
177+
178+
assert_eq!(g.next(), Some(1));
179+
assert_eq!(g.next(), Some(2));
180+
assert_eq!(g.next(), None);
181+
}
182+
183+
#[test]
184+
fn gen_iter_macro_static_move() {
185+
let v1 = [1, 2];
186+
let mut g = gen_iter!(static move {
187+
let v = &v1;
188+
for i in 0..v.len() {
189+
yield v[i];
190+
}
191+
});
192+
193+
assert_eq!(g.next(), Some(1));
194+
assert_eq!(g.next(), Some(2));
195+
assert_eq!(g.next(), None);
196+
}
109197
}

src/gen_iter_return.rs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use core::pin::Pin;
1111
/// 2. safe to call `next()` after coroutine is done without panic
1212
/// 3. maybe less efficient than `GenIter<G>`
1313
#[derive(Copy, Clone, Debug)]
14-
pub struct GenIterReturn<G: Coroutine + Unpin>(Result<G::Return, G>);
14+
pub struct GenIterReturn<G: Coroutine + Unpin>(
15+
#[doc(hidden)]
16+
pub Result<G::Return, G>
17+
);
1518

1619
impl<G: Coroutine + Unpin> GenIterReturn<G> {
1720
#[inline]
@@ -72,6 +75,7 @@ impl<G: Coroutine + Unpin> From<G> for GenIterReturn<G> {
7275
}
7376

7477
/// macro to simplify iterator - via - coroutine with return value construction
78+
/// - movable coroutine as `Iterator`
7579
/// ```
7680
/// #![feature(coroutines)]
7781
///
@@ -88,6 +92,26 @@ impl<G: Coroutine + Unpin> From<G> for GenIterReturn<G> {
8892
/// assert_eq!((&mut g).next(), None); // safe to call `next()` after done
8993
/// assert_eq!(g.return_or_self().ok(), Some("done")); // get return value of the coroutine
9094
/// ```
95+
///
96+
/// - immovable coroutine (self referenced) as `Iterator`
97+
/// ```
98+
/// #![feature(coroutines)]
99+
///
100+
/// use gen_iter::gen_iter_return;
101+
///
102+
/// let arr = [1, 2];
103+
/// let mut g = gen_iter_return!(static move {
104+
/// let v = &arr;
105+
/// for i in 0..v.len() {
106+
/// yield v[i];
107+
/// }
108+
/// return v.len();
109+
/// });
110+
///
111+
/// assert_eq!((&mut g).collect::<Vec<i32>>(), [1, 2]);
112+
/// assert_eq!(g.is_done(), true);
113+
/// assert_eq!(g.return_or_self().ok(), Some(2));
114+
/// ```
91115
#[macro_export]
92116
macro_rules! gen_iter_return {
93117
($block: block) => {
@@ -96,6 +120,21 @@ macro_rules! gen_iter_return {
96120
(move $block: block) => {
97121
$crate::GenIterReturn::new(#[coroutine] move || $block)
98122
};
123+
124+
(static $block: block) => {
125+
$crate::GenIterReturn {
126+
0: ::core::result::Result::Err {
127+
0: ::core::pin::pin!(#[coroutine] static || $block)
128+
}
129+
}
130+
};
131+
(static move $block: block) => {
132+
$crate::GenIterReturn {
133+
0: ::core::result::Result::Err {
134+
0: ::core::pin::pin!(#[coroutine] static move || $block)
135+
}
136+
}
137+
};
99138
}
100139

101140
#[cfg(test)]
@@ -149,7 +188,7 @@ mod tests {
149188

150189
/// normal usage using macro `gen_iter_return`
151190
#[test]
152-
fn macro_usage() {
191+
fn macro_gen_iter_return() {
153192
let mut g = gen_iter_return!(move {
154193
yield 1;
155194
yield 2;
@@ -166,4 +205,27 @@ mod tests {
166205
assert_eq!(g.is_done(), true);
167206
assert_eq!(g.return_or_self().ok(), Some("done"));
168207
}
208+
209+
/// use macro `gen_iter_return` to make a immovable coroutine
210+
#[test]
211+
fn macro_gen_iter_return_static_move() {
212+
let arr = [1, 2];
213+
let mut g = gen_iter_return!(static move {
214+
let v = &arr;
215+
for i in 0..v.len() {
216+
yield v[i];
217+
}
218+
return v.len();
219+
});
220+
221+
let (mut sum, mut count) = (0, 0);
222+
for y in &mut g {
223+
sum += y;
224+
count += 1;
225+
}
226+
assert_eq!((sum, count), (3, 2));
227+
228+
assert_eq!(g.is_done(), true);
229+
assert_eq!(g.return_or_self().ok(), Some(2));
230+
}
169231
}

src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@
6060
//! println!("coroutine is_done={}", g.is_done()); // true
6161
//! println!("coroutine returns {}", g.return_or_self().ok().unwrap()); // "done"
6262
//! ```
63+
//!
64+
//! ## support immovable coroutine (self referenced)
65+
//! ```
66+
//! #![feature(coroutines)]
67+
//!
68+
//! use gen_iter::gen_iter;
69+
//!
70+
//! let arr = [1, 2];
71+
//! let mut g = gen_iter!(static move {
72+
//! let v = &arr;
73+
//! for i in 0..v.len() {
74+
//! yield v[i];
75+
//! }
76+
//! });
77+
//!
78+
//! assert_eq!(g.collect::<Vec<i32>>(), [1, 2]);
79+
//! ```
6380
6481
#![no_std]
6582
#![feature(coroutines, coroutine_trait)]

0 commit comments

Comments
 (0)