1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![no_std]
4
5extern crate alloc;
6
7use alloc::boxed::Box;
8use alloc::rc::Rc;
9use core::cell::Cell;
10use core::future::Future;
11use core::pin::Pin;
12use core::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
13
14pub struct IterSink<T> {
18 inner: Rc<IterSinkInner<T>>,
19}
20
21impl<T> IterSink<T> {
22 fn new(inner: Rc<IterSinkInner<T>>) -> Self {
23 Self { inner }
24 }
25
26 pub fn yield_value(&self, value: T) -> impl Future<Output = ()> {
47 self.inner.set_value(value);
48 IterYield::new()
49 }
50}
51
52struct IterSinkInner<T> {
57 value: Cell<Option<T>>,
58}
59
60impl<T> IterSinkInner<T> {
61 fn new() -> Self {
62 Self {
63 value: Cell::new(None),
64 }
65 }
66
67 fn set_value(&self, value: T) {
68 self.value.set(Some(value));
69 }
70
71 fn take_value(&self) -> Option<T> {
72 self.value.take()
73 }
74}
75
76struct IterYield {
81 suspended: bool,
82}
83
84impl IterYield {
85 fn new() -> Self {
86 Self { suspended: false }
87 }
88}
89
90impl Future for IterYield {
91 type Output = ();
92
93 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
94 if self.suspended {
95 Poll::Ready(())
96 } else {
97 self.get_mut().suspended = true;
98 Poll::Pending
99 }
100 }
101}
102
103fn make_noop_raw_waker() -> RawWaker {
105 fn noop(_: *const ()) {}
106
107 fn noop_clone(_: *const ()) -> RawWaker {
108 make_noop_raw_waker()
109 }
110 static VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
111 RawWaker::new(core::ptr::null(), &VTABLE)
112}
113
114fn make_noop_waker() -> Waker {
116 let raw_waker = make_noop_raw_waker();
117
118 unsafe { Waker::from_raw(raw_waker) }
120}
121
122struct IterAdapter<T, Fut> {
124 iter_sink_inner: Rc<IterSinkInner<T>>,
125 future: Pin<Box<Fut>>,
126}
127
128impl<T, Fut> IterAdapter<T, Fut> {
129 fn new<IntoFut>(into_future: IntoFut) -> Self
130 where
131 IntoFut: FnOnce(IterSink<T>) -> Fut,
132 {
133 let iter_sink_inner = Rc::new(IterSinkInner::new());
134 let iter_sink = IterSink::new(Rc::clone(&iter_sink_inner));
135 let future = Box::pin(into_future(iter_sink));
136 Self {
137 iter_sink_inner,
138 future,
139 }
140 }
141}
142
143impl<T, Fut> Iterator for IterAdapter<T, Fut>
144where
145 Fut: Future<Output = ()>,
146{
147 type Item = T;
148
149 fn next(&mut self) -> Option<Self::Item> {
150 let waker = make_noop_waker();
151 let mut cx = Context::from_waker(&waker);
152 match self.future.as_mut().poll(&mut cx) {
153 Poll::Pending => Some(
154 self.iter_sink_inner
155 .take_value()
156 .expect("Future did not yield a value"),
157 ),
158 Poll::Ready(()) => None,
159 }
160 }
161}
162
163pub fn make_iter<T, Fut, IntoFut>(into_future: IntoFut) -> impl Iterator<Item = T>
196where
197 Fut: Future<Output = ()>,
198 IntoFut: FnOnce(IterSink<T>) -> Fut,
199{
200 IterAdapter::new(into_future)
201}
202
203#[cfg(test)]
204mod tests {
205 use super::{make_iter, IterSink};
206 use alloc::string::String;
207 use alloc::vec::Vec;
208
209 async fn count_up_impl(sink: IterSink<u64>, start: u64) {
210 for i in start.. {
211 sink.yield_value(i).await;
212 }
213 }
214
215 fn count_up(start: u64) -> impl Iterator<Item = u64> {
216 make_iter(move |sink| count_up_impl(sink, start))
217 }
218
219 #[test]
220 fn test_count_up() {
221 let mut iter = count_up(5);
222 assert_eq!(iter.next(), Some(5));
223 assert_eq!(iter.next(), Some(6));
224 assert_eq!(iter.next(), Some(7));
225 assert_eq!(iter.next(), Some(8));
226 assert_eq!(iter.next(), Some(9));
227 assert_eq!(iter.next(), Some(10));
228 assert_eq!(iter.next(), Some(11));
229 assert_eq!(iter.next(), Some(12));
230 }
231
232 async fn join_to_strings_impl(sink: IterSink<String>, chars: impl IntoIterator<Item = char>) {
233 let mut is_whitespace = true;
234 let mut current_string = String::new();
235 for c in chars {
236 match (c.is_whitespace(), is_whitespace) {
237 (true, true) => (),
238 (true, false) => {
239 sink.yield_value(core::mem::take(&mut current_string)).await;
240 is_whitespace = true;
241 }
242 (false, _) => {
243 current_string.push(c);
244 is_whitespace = false;
245 }
246 }
247 }
248
249 if !is_whitespace {
250 sink.yield_value(current_string).await;
251 }
252 }
253
254 fn join_to_strings(chars: impl IntoIterator<Item = char>) -> impl Iterator<Item = String> {
255 make_iter(move |sink| join_to_strings_impl(sink, chars))
256 }
257
258 #[test]
259 fn test_join_to_strings() {
260 let input1 = "Hello world!";
261 let output1 = join_to_strings(input1.chars()).collect::<Vec<_>>();
262 assert_eq!(&output1, &[String::from("Hello"), String::from("world!")],);
263
264 let input2 = " test\ton more\n data ";
265 let output2 = join_to_strings(input2.chars()).collect::<Vec<_>>();
266 assert_eq!(
267 &output2,
268 &[
269 String::from("test"),
270 String::from("on"),
271 String::from("more"),
272 String::from("data"),
273 ],
274 );
275 }
276}