diff --git a/Cargo.lock b/Cargo.lock index 0955522..40d122e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,25 +20,26 @@ checksum = "2c61a19d4ab2db23de9a52d0085948e6647c0abd46cf0361de57e6716b65c785" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "event_iterator" -version = "0.2.1" +version = "0.2.2" dependencies = [ "async_main", "futures", "pasts", + "pin-project-lite", "whisk", ] [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -51,9 +52,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -61,15 +62,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -78,15 +79,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -95,21 +96,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -137,9 +138,9 @@ checksum = "efcd36303871fb977a47dabc9af736c75c492bb32a92fa26262b2741531e97ce" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -149,9 +150,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -176,9 +177,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -187,9 +188,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "whisk" diff --git a/Cargo.toml b/Cargo.toml index 3f1fcee..ba9b78e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ categories = ["asynchronous", "no-std", "rust-patterns"] readme = "README.md" rust-version = "1.70" +[dependencies.pin-project-lite] +version = "0.2" + [dev-dependencies.async_main] version = "0.4" features = ["pasts"] diff --git a/examples/empty.rs b/examples/empty.rs index b62a265..e080dd3 100644 --- a/examples/empty.rs +++ b/examples/empty.rs @@ -2,8 +2,8 @@ use event_iterator::{Empty, EventIterator}; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei: Empty = event_iterator::empty(); + let mut ei: Empty = event_iterator::empty(); - assert!(ei.next_unpinned().await.is_none()); - assert!(ei.next_unpinned().await.is_none()); + assert!(ei.next().await.is_none()); + assert!(ei.next().await.is_none()); } diff --git a/examples/enumerate.rs b/examples/enumerate.rs index 4205e7c..dfb850c 100644 --- a/examples/enumerate.rs +++ b/examples/enumerate.rs @@ -2,11 +2,10 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter(['a', 'b', 'c']); - let ei = ei.enumerate(); + let mut ei = event_iterator::from_iter_ref(['a', 'b', 'c']).enumerate(); - assert_eq!(ei.next_unpinned().await, Some((0, 'a'))); - assert_eq!(ei.next_unpinned().await, Some((1, 'b'))); - assert_eq!(ei.next_unpinned().await, Some((2, 'c'))); - assert_eq!(ei.next_unpinned().await, None); + assert_eq!(ei.next().await, Some((0, &'a'))); + assert_eq!(ei.next().await, Some((1, &'b'))); + assert_eq!(ei.next().await, Some((2, &'c'))); + assert_eq!(ei.next().await, None); } diff --git a/examples/filter.rs b/examples/filter.rs index 7e2e8d1..0bc60a1 100644 --- a/examples/filter.rs +++ b/examples/filter.rs @@ -2,11 +2,12 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([1, 2, 3, 4, 5]).filter(|&x| x > 1); + let mut ei = + event_iterator::from_iter_ref([1, 2, 3, 4, 5]).filter(|&x| x > 1); let mut events = Vec::new(); - while let Some(event) = ei.next_unpinned().await { - events.push(event); + while let Some(event) = ei.next().await { + events.push(event.clone()); } println!("{events:?}"); diff --git a/examples/filter_map.rs b/examples/filter_map.rs deleted file mode 100644 index 3619eb2..0000000 --- a/examples/filter_map.rs +++ /dev/null @@ -1,23 +0,0 @@ -use event_iterator::EventIterator; - -#[async_main::async_main] -async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter(["1", "two", "NaN", "four", "5"]); - let ei = ei.filter_map(|s| s.parse().ok()); - - assert_eq!(ei.next_unpinned().await, Some(1)); - assert_eq!(ei.next_unpinned().await, Some(5)); - assert_eq!(ei.next_unpinned().await, None); - - // Here’s the same example, but with `filter()` and `map()`: - - let ei = event_iterator::from_iter(["1", "two", "NaN", "four", "5"]); - let ei = ei - .map(|s| s.parse()) - .filter(|s| s.is_ok()) - .map(|s| s.unwrap()); - - assert_eq!(ei.next_unpinned().await, Some(1)); - assert_eq!(ei.next_unpinned().await, Some(5)); - assert_eq!(ei.next_unpinned().await, None); -} diff --git a/examples/filter_map_ref.rs b/examples/filter_map_ref.rs new file mode 100644 index 0000000..a150447 --- /dev/null +++ b/examples/filter_map_ref.rs @@ -0,0 +1,24 @@ +use event_iterator::EventIterator; + +#[async_main::async_main] +async fn main(_spawner: async_main::LocalSpawner) { + let mut ei = + event_iterator::from_iter_ref(["1", "two", "NaN", "four", "5"]) + .filter_map_ref(|&s| s.parse().ok()); + + assert_eq!(ei.next().await, Some(&1)); + assert_eq!(ei.next().await, Some(&5)); + assert_eq!(ei.next().await, None); + + // Here’s the same example, but with `filter()` and `map_ref()`: + + let mut ei = + event_iterator::from_iter_ref(["1", "two", "NaN", "four", "5"]) + .map_ref(|&s| s.parse()) + .filter(|s| s.is_ok()) + .map_ref(|s| s.clone().unwrap()); + + assert_eq!(ei.next().await, Some(&1)); + assert_eq!(ei.next().await, Some(&5)); + assert_eq!(ei.next().await, None); +} diff --git a/examples/from_fn.rs b/examples/from_fn.rs index d60c2fc..f327516 100644 --- a/examples/from_fn.rs +++ b/examples/from_fn.rs @@ -16,11 +16,11 @@ async fn main(_spawner: async_main::LocalSpawner) { }) }); - assert_eq!(ei.next_unpinned().await, Some(1)); - assert_eq!(ei.next_unpinned().await, Some(2)); - assert_eq!(ei.next_unpinned().await, Some(3)); - assert_eq!(ei.next_unpinned().await, Some(4)); - assert_eq!(ei.next_unpinned().await, Some(5)); - assert_eq!(ei.next_unpinned().await, None); - assert_eq!(ei.next_unpinned().await, None); + assert_eq!(ei.next().await, Some(1)); + assert_eq!(ei.next().await, Some(2)); + assert_eq!(ei.next().await, Some(3)); + assert_eq!(ei.next().await, Some(4)); + assert_eq!(ei.next().await, Some(5)); + assert_eq!(ei.next().await, None); + assert_eq!(ei.next().await, None); } diff --git a/examples/from_iter.rs b/examples/from_iter_ref.rs similarity index 57% rename from examples/from_iter.rs rename to examples/from_iter_ref.rs index c82966b..fe0e97b 100644 --- a/examples/from_iter.rs +++ b/examples/from_iter_ref.rs @@ -2,9 +2,9 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([1, 2, 3, 4, 5]); + let mut ei = event_iterator::from_iter_ref([1, 2, 3, 4, 5]); - while let Some(i) = ei.next_unpinned().await { + while let Some(&i) = ei.next().await { println!("{i}"); } } diff --git a/examples/fuse.rs b/examples/fuse.rs index 10a8efd..4d9ba94 100644 --- a/examples/fuse.rs +++ b/examples/fuse.rs @@ -4,11 +4,11 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([1, 2, 3]).fuse(); + let mut ei = event_iterator::from_iter_ref([1, 2, 3]).fuse(); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(Some(1))); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(Some(2))); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(Some(3))); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(None)); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(None)); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(Some(&1))); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(Some(&2))); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(Some(&3))); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(None)); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(None)); } diff --git a/examples/inspect.rs b/examples/inspect.rs index 85dc4c5..a8e1a7e 100644 --- a/examples/inspect.rs +++ b/examples/inspect.rs @@ -2,11 +2,11 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([1, 2, 3, 4, 5]).inspect(|&x| { + let mut ei = event_iterator::from_iter_ref([1, 2, 3, 4, 5]).inspect(|&x| { let uwu = "uwu".repeat(x); println!("{uwu}"); }); - while ei.next_unpinned().await.is_some() {} + while ei.next().await.is_some() {} } diff --git a/examples/map.rs b/examples/map.rs index d2c4f7b..e840f5f 100644 --- a/examples/map.rs +++ b/examples/map.rs @@ -1,11 +1,25 @@ -use event_iterator::EventIterator; +use event_iterator::{EventIterator, LendAs}; + +#[derive(Copy, Clone)] +struct Uwu<'a>(&'a i32); + +#[derive(Copy, Clone)] +struct LendAsUwu; + +impl LendAs for LendAsUwu { + type From<'a> = &'a i32; + type Into<'a> = Uwu<'a>; + + fn lend_as<'a>(self, from: Self::From<'a>) -> Self::Into<'a> { + Uwu(from) + } +} #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = - event_iterator::from_iter([1, 2, 3, 4, 5]).map(|x| "uwu".repeat(x)); + let mut ei = event_iterator::from_iter_ref([1, 2, 3, 4, 5]).map(LendAsUwu); - while let Some(i) = ei.next_unpinned().await { + while let Some(Uwu(i)) = ei.next().await { println!("{i}"); } } diff --git a/examples/map_ref.rs b/examples/map_ref.rs new file mode 100644 index 0000000..b7e70a8 --- /dev/null +++ b/examples/map_ref.rs @@ -0,0 +1,13 @@ +use event_iterator::EventIterator; + +#[async_main::async_main] +async fn main(_spawner: async_main::LocalSpawner) { + let mut ei = event_iterator::from_iter_ref([1, 2, 3, 4, 5]) + .map_ref(|&x| "uwu".repeat(x)); + + while let Some(i) = ei.next().await { + let i: &String = i; + + println!("{i}"); + } +} diff --git a/examples/next.rs b/examples/next.rs index c9c7d12..7ff5331 100644 --- a/examples/next.rs +++ b/examples/next.rs @@ -1,13 +1,11 @@ -use std::pin::pin; - use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = pin!(event_iterator::from_iter([3, 1, 2])); + let mut ei = event_iterator::from_iter_ref([3, 1, 2]); - assert_eq!(Some(3), ei.as_ref().next().await); - assert_eq!(Some(1), ei.as_ref().next().await); - assert_eq!(Some(2), ei.as_ref().next().await); - assert_eq!(None, ei.as_ref().next().await); + assert_eq!(Some(&3), ei.next().await); + assert_eq!(Some(&1), ei.next().await); + assert_eq!(Some(&2), ei.next().await); + assert_eq!(None, ei.next().await); } diff --git a/examples/next_pinned.rs b/examples/next_pinned.rs new file mode 100644 index 0000000..be072b1 --- /dev/null +++ b/examples/next_pinned.rs @@ -0,0 +1,13 @@ +use std::pin::pin; + +use event_iterator::EventIterator; + +#[async_main::async_main] +async fn main(_spawner: async_main::LocalSpawner) { + let mut ei = pin!(event_iterator::from_iter_ref([3, 1, 2])); + + assert_eq!(Some(&3), ei.as_mut().next_pinned().await); + assert_eq!(Some(&1), ei.as_mut().next_pinned().await); + assert_eq!(Some(&2), ei.as_mut().next_pinned().await); + assert_eq!(None, ei.as_mut().next_pinned().await); +} diff --git a/examples/next_unpinned.rs b/examples/next_unpinned.rs deleted file mode 100644 index 4492f7f..0000000 --- a/examples/next_unpinned.rs +++ /dev/null @@ -1,11 +0,0 @@ -use event_iterator::EventIterator; - -#[async_main::async_main] -async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([3, 1, 2]); - - assert_eq!(Some(3), ei.next_unpinned().await); - assert_eq!(Some(1), ei.next_unpinned().await); - assert_eq!(Some(2), ei.next_unpinned().await); - assert_eq!(None, ei.next_unpinned().await); -} diff --git a/examples/pending.rs b/examples/pending.rs index 4caaf14..9bf81c2 100644 --- a/examples/pending.rs +++ b/examples/pending.rs @@ -1,11 +1,9 @@ -use std::task::Poll; - use event_iterator::{EventIterator, Pending}; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei: Pending = event_iterator::pending(); + let mut ei: Pending = event_iterator::pending(); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Pending); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Pending); + assert!(futures::poll!(ei.next()).is_pending()); + assert!(futures::poll!(ei.next()).is_pending()); } diff --git a/examples/size_hint.rs b/examples/size_hint.rs index 47821ca..e4bfb62 100644 --- a/examples/size_hint.rs +++ b/examples/size_hint.rs @@ -2,11 +2,11 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([1, 2, 3, 4, 5]); + let mut ei = event_iterator::from_iter_ref([1, 2, 3, 4, 5]); assert_eq!((5, Some(5)), ei.size_hint()); - let _ = ei.next_unpinned().await; + let _ = ei.next().await; assert_eq!((4, Some(4)), ei.size_hint()); @@ -15,15 +15,16 @@ async fn main(_spawner: async_main::LocalSpawner) { ///////////////////// // The even numbers in the range of zero to nine. - let iter = event_iterator::from_iter((0..10).filter(|x| x % 2 == 0)); + let iter = event_iterator::from_iter_ref((0..10).filter(|x| x % 2 == 0)); // We might iterate from zero to ten times. Knowing that it's five // exactly wouldn't be possible without executing filter(). assert_eq!((0, Some(10)), iter.size_hint()); // Let's add five more numbers with chain() - let iter = - event_iterator::from_iter((0..10).filter(|x| x % 2 == 0).chain(15..20)); + let iter = event_iterator::from_iter_ref( + (0..10).filter(|x| x % 2 == 0).chain(15..20), + ); // now both bounds are increased by five assert_eq!((5, Some(15)), iter.size_hint()); @@ -34,7 +35,7 @@ async fn main(_spawner: async_main::LocalSpawner) { // an infinite iterator has no upper bound // and the maximum possible lower bound - let iter = event_iterator::from_iter(0..); + let iter = event_iterator::from_iter_ref(0..); assert_eq!((usize::MAX, None), iter.size_hint()); } diff --git a/examples/stdin.rs b/examples/stdin.rs index 046bb66..9fa3b64 100644 --- a/examples/stdin.rs +++ b/examples/stdin.rs @@ -1,113 +1,112 @@ use std::{ - cell::Cell, future::Future, - io, mem, + io, pin::Pin, + sync::Arc, task::{Context, Poll}, - thread, + thread::{self, JoinHandle}, }; use event_iterator::EventIterator; use whisk::Channel; -/// An event iterator, for reading from stdin +/// An event iterator, for scanning from stdin #[derive(Default)] pub struct Stdin { - sender: Channel>, - recver: Cell>>>, - buffer: Cell>, - send: Cell + Send>>>>, + channel: Channel>>, + buffer: Option>, + join: Option>, } -impl EventIterator for Stdin { - type Event<'me> = Buffer<'me>; - - fn poll_next( - self: Pin<&Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); +impl Drop for Stdin { + fn drop(&mut self) { + self.join.take().unwrap().join().unwrap(); + } +} - if let Some(buffer) = this.buffer.take() { - let sender = this.sender.clone(); +impl Stdin { + pub fn new() -> Self { + let channel = Channel::new(); + let sender = channel.clone(); + let join = thread::spawn(move || { + pasts::Executor::default().block_on(async move { + let stdin = io::stdin(); + let mut buffer = String::new(); + let mut sending = Arc::new(String::new()); + + while stdin.read_line(&mut buffer).is_ok() { + let buf = if let Some(s) = Arc::get_mut(&mut sending) { + s + } else { + sending = Arc::new(String::new()); + Arc::get_mut(&mut sending).unwrap() + }; + + // Remove trailing newline + buffer.pop(); + + if buffer.is_empty() { + break; + } + + buf.replace_range(.., buffer.as_str()); + sender.send(Some(sending.clone())).await; + buffer.clear(); + } + + sender.send(None).await; + }) + }); - this.send.set(Some(Box::pin(async move { - sender.send(Some(buffer)).await - }))); + Self { + buffer: None, + join: Some(join), + channel, } + } +} - if let Some(mut future) = this.send.take() { - if future.as_mut().poll(cx).is_pending() { - this.send.set(Some(future)); - return Poll::Pending; - } - } +impl EventIterator for Stdin { + type Event<'me> = Buffer<'me>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let this = self.get_mut(); - let mut recver = this.recver.take().unwrap(); - let poll = match Pin::new(&mut recver).poll(cx) { - Poll::Ready(Some(buffer)) => { - this.buffer.set(Some(buffer)); - Poll::Ready(Some(Buffer(&this.buffer))) - } - Poll::Ready(None) => Poll::Ready(None), - Poll::Pending => Poll::Pending, + this.buffer = None; + + match Pin::new(&mut this.channel).poll(cx) { + Poll::Ready(Some(buffer)) => this.buffer = Some(buffer), + Poll::Ready(None) => {} + Poll::Pending => return Poll::Pending, }; - this.recver.set(Some(recver)); - poll + Poll::Ready(()) } -} -pub struct Buffer<'a>(&'a Cell>); + fn event(self: Pin<&mut Self>) -> Option> { + let this = self.get_mut(); -impl Buffer<'_> { - pub fn with(&self, f: impl FnOnce(&str)) { - self.0.set(self.0.take().map(|buf| { - f(&buf); - buf - })); + Some(Buffer(this.buffer.as_ref()?)) } } -async fn stdin_thread( - recver: Channel>, - sender: Channel>, -) { - let stdin = io::stdin(); - let mut buffer = String::new(); - - while stdin.read_line(&mut buffer).is_ok() { - // Remove trailing newline - buffer.pop(); +#[derive(Copy, Clone)] +pub struct Buffer<'a>(&'a String); - if buffer.is_empty() { - break; - } - - sender.send(Some(mem::take(&mut buffer))).await; - buffer = recver.recv().await.unwrap_or_default(); - buffer.clear(); +impl Buffer<'_> { + pub fn with(&self, f: impl FnOnce(&str)) { + f(self.0) } - - sender.send(None).await; } #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - // Init stdin - let stdin = Stdin::default(); - let recver = stdin.sender.clone(); - let sender = Channel::new(); + println!("Echo example - enter empty line to quit"); - stdin.recver.set(Some(sender.clone())); - thread::spawn(move || { - pasts::Executor::default().block_on(stdin_thread(recver, sender)) - }); + let mut stdin = Stdin::new(); // Check messages - while let Some(buffer) = stdin.next_unpinned().await { - buffer.with(|message| { - println!("Echo: {message}"); - }); + while let Some(buffer) = stdin.next().await { + buffer.with(|message| println!("Echo: {message}")); } } diff --git a/examples/stdout.rs b/examples/stdout.rs index 89973de..a0c7d2c 100644 --- a/examples/stdout.rs +++ b/examples/stdout.rs @@ -9,53 +9,54 @@ use event_iterator::EventIterator; /// An event iterator, for printing to stdout #[derive(Default)] pub struct Stdout { - buffer: Cell>, + buffer: Option, } impl EventIterator for Stdout { type Event<'me> = Buffer<'me>; - fn poll_next( - self: Pin<&Self>, - _cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> { + let this = self.get_mut(); - // Print last buffer contents if set, set if unset - this.buffer.set(if let Some(buffer) = this.buffer.take() { + if let Some(ref mut buffer) = this.buffer { // This could be an asynchronous operation // Left synchronous for example simplicity println!("{buffer}"); - // Reuse buffer - Some(buffer) + buffer.clear(); } else { - Some(String::new()) - }); - Poll::Ready(Some(Buffer(&this.buffer))) + this.buffer = Some(String::new()); + } + + Poll::Ready(()) + } + + fn event(self: Pin<&mut Self>) -> Option> { + let this = self.get_mut(); + + Some(Buffer(Cell::from_mut(this.buffer.as_mut().unwrap()))) } } -pub struct Buffer<'a>(&'a Cell>); +#[derive(Copy, Clone)] +pub struct Buffer<'a>(&'a Cell); impl Buffer<'_> { pub fn write(&self, text: &str) { - self.0.set(self.0.take().map(|mut buf| { - buf.replace_range(.., text); - buf - })); + let mut buffer = self.0.take(); + + buffer.replace_range(.., text); + self.0.set(buffer); } } #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let stdout = Stdout::default(); + let mut stdout = Stdout::default(); // Overwrite buffer with text to print - stdout.next_unpinned().await.unwrap().write("Hello, world!"); - stdout.next_unpinned().await.unwrap().write("Hello, again!"); - - // Once more, to use the previous buffer contents - let flush = pin!(stdout); + stdout.next().await.unwrap().write("Hello, world!"); + stdout.next().await.unwrap().write("Hello, again!"); - flush.as_ref().next().await.unwrap(); + // Once more, to flush the previous buffer contents + pin!(stdout).next_pinned().await.unwrap(); } diff --git a/examples/take.rs b/examples/take.rs index c05c587..9ed194f 100644 --- a/examples/take.rs +++ b/examples/take.rs @@ -2,30 +2,31 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([1, 2, 3]).take(2); + let mut ei = event_iterator::from_iter_ref([1, 2, 3]).take(2); - assert_eq!(ei.next_unpinned().await, Some(1)); - assert_eq!(ei.next_unpinned().await, Some(2)); - assert_eq!(ei.next_unpinned().await, None); - assert_eq!(ei.next_unpinned().await, None); + assert_eq!(ei.next().await, Some(&1)); + assert_eq!(ei.next().await, Some(&2)); + assert_eq!(ei.next().await, None); + assert_eq!(ei.next().await, None); - // `take()` is often used with an infinite iterator, to make it finite: + // `take()` is often used with an infinite event iterator, to make it + // finite: - let ei = event_iterator::from_iter(0..).take(3); + let mut ei = event_iterator::from_iter_ref(0..).take(3); - assert_eq!(ei.next_unpinned().await, Some(0)); - assert_eq!(ei.next_unpinned().await, Some(1)); - assert_eq!(ei.next_unpinned().await, Some(2)); - assert_eq!(ei.next_unpinned().await, None); - assert_eq!(ei.next_unpinned().await, None); + assert_eq!(ei.next().await, Some(&0)); + assert_eq!(ei.next().await, Some(&1)); + assert_eq!(ei.next().await, Some(&2)); + assert_eq!(ei.next().await, None); + assert_eq!(ei.next().await, None); // If less than `n` elements are available, `take()` will limit itself to - // the size of the underlying iterator: + // the size of the underlying event iterator: - let ei = event_iterator::from_iter([1, 2]).take(5); + let mut ei = event_iterator::from_iter_ref([1, 2]).take(5); - assert_eq!(ei.next_unpinned().await, Some(1)); - assert_eq!(ei.next_unpinned().await, Some(2)); - assert_eq!(ei.next_unpinned().await, None); - assert_eq!(ei.next_unpinned().await, None); + assert_eq!(ei.next().await, Some(&1)); + assert_eq!(ei.next().await, Some(&2)); + assert_eq!(ei.next().await, None); + assert_eq!(ei.next().await, None); } diff --git a/examples/take_while.rs b/examples/take_while.rs index 0fed9ad..887b363 100644 --- a/examples/take_while.rs +++ b/examples/take_while.rs @@ -2,11 +2,12 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([-2i32, -1, 0, 1, -2]) + let mut ei = event_iterator::from_iter_ref([-2i32, -1, 0, 1, -2]) .take_while(|x| x.is_negative()); - assert_eq!(ei.next_unpinned().await, Some(-2)); - assert_eq!(ei.next_unpinned().await, Some(-1)); - assert_eq!(ei.next_unpinned().await, None); - assert_eq!(ei.next_unpinned().await, None); + assert_eq!(ei.next().await, Some(&-2)); + assert_eq!(ei.next().await, Some(&-1)); + assert_eq!(ei.next().await, None); + assert_eq!(ei.next().await, None); + assert_eq!(ei.next().await, None); } diff --git a/examples/tear.rs b/examples/tear.rs index b68b11a..9fd7ca1 100644 --- a/examples/tear.rs +++ b/examples/tear.rs @@ -4,12 +4,12 @@ use event_iterator::EventIterator; #[async_main::async_main] async fn main(_spawner: async_main::LocalSpawner) { - let ei = event_iterator::from_iter([1, 2, 3]).tear(); + let mut ei = event_iterator::from_iter_ref([1, 2, 3]).tear(); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(Some(1))); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(Some(2))); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(Some(3))); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Ready(None)); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Pending); - assert_eq!(futures::poll!(ei.next_unpinned()), Poll::Pending); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(Some(&1))); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(Some(&2))); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(Some(&3))); + assert_eq!(futures::poll!(ei.next()), Poll::Ready(None)); + assert_eq!(futures::poll!(ei.next()), Poll::Pending); + assert_eq!(futures::poll!(ei.next()), Poll::Pending); } diff --git a/src/as_event_iter.rs b/src/as_event_iter.rs index 02e3907..8961722 100644 --- a/src/as_event_iter.rs +++ b/src/as_event_iter.rs @@ -14,7 +14,7 @@ pub struct AsEventIter<'b, E>(&'b (dyn DynEventIter<'b, Event = E> + Unpin)); impl<'b, E> AsEventIter<'b, E> { /// Create a new `AsEventIter` from something implementing /// [`EventIterator`]. - pub fn new(ei: &'b (impl EventIterator = E> + Unpin)) -> Self { + pub fn new(ei: &'b mut (impl EventIterator = E> + Unpin)) -> Self { Self(ei) } } @@ -31,10 +31,10 @@ impl EventIterator for AsEventIter<'_, E> { type Event<'me> = E where Self: 'me; fn poll_next( - self: Pin<&Self>, + mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>> { - Pin::new(&self.0).poll_next(cx) + Pin::new(&mut self.0).poll_next(cx) } } @@ -56,7 +56,7 @@ pub trait AsEventIterator<'b>: Unpin { /// ```rust #[doc = include_str!("../examples/tripple_buffer.rs")] /// ``` - fn as_event_iter(&'b self) -> AsEventIter<'b, Self::Event>; + fn as_event_iter(&'b mut self) -> AsEventIter<'b, Self::Event>; } impl<'b, T> AsEventIterator<'b> for T @@ -65,7 +65,7 @@ where { type Event = ::Event<'b>; - fn as_event_iter(&'b self) -> AsEventIter<'b, Self::Event> { + fn as_event_iter(&'b mut self) -> AsEventIter<'b, Self::Event> { AsEventIter::new(self) } } @@ -73,7 +73,7 @@ where trait DynEventIter<'b> { type Event; - fn poll_next(&'b self, cx: &mut Context<'_>) -> Poll>; + fn poll_next(&'b mut self, cx: &mut Context<'_>) -> Poll>; } impl<'b, T> DynEventIter<'b> for T @@ -82,7 +82,7 @@ where { type Event = ::Event<'b>; - fn poll_next(&'b self, cx: &mut Context<'_>) -> Poll> { + fn poll_next(&'b mut self, cx: &mut Context<'_>) -> Poll> { Pin::new(self).poll_next(cx) } } diff --git a/src/consts.rs b/src/consts.rs new file mode 100644 index 0000000..9f3a1c1 --- /dev/null +++ b/src/consts.rs @@ -0,0 +1,2 @@ +pub(crate) const EVENT_BEFORE_POLL: &str = + "tried to lend event before first poll"; diff --git a/src/empty.rs b/src/empty.rs index 2430fe4..2cb51a0 100644 --- a/src/empty.rs +++ b/src/empty.rs @@ -7,26 +7,38 @@ use core::{ use crate::EventIterator; -/// Event iterator that yields nothing +/// [Fused](crate::Fuse) event iterator that yields nothing /// /// This event iterator is created by the [`empty()`] function. See its /// documentation for more. -pub struct Empty(PhantomData); +pub struct Empty(PhantomData) +where + E: Copy; -impl fmt::Debug for Empty { +impl fmt::Debug for Empty +where + E: Copy, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Empty").field(&format_args!("_")).finish() } } -impl EventIterator for Empty { - type Event<'me> = E where Self: 'me; +impl EventIterator for Empty +where + E: Copy, +{ + type Event<'me> + = E + where + Self: 'me; - fn poll_next<'a>( - self: Pin<&'a Self>, - _cx: &mut Context<'_>, - ) -> Poll>> { - Poll::Ready(None) + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> { + Poll::Ready(()) + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + None } fn size_hint(&self) -> (usize, Option) { @@ -43,6 +55,9 @@ impl EventIterator for Empty { /// ```rust #[doc = include_str!("../examples/empty.rs")] /// ``` -pub fn empty() -> Empty { +pub fn empty() -> Empty +where + E: Copy, +{ Empty(PhantomData::) } diff --git a/src/enumerate.rs b/src/enumerate.rs index fcdfd29..d215196 100644 --- a/src/enumerate.rs +++ b/src/enumerate.rs @@ -1,24 +1,26 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, }; -use crate::EventIterator; +use crate::{consts::EVENT_BEFORE_POLL, EventIterator}; -/// Event iterator that yields the current count and event during iteration -/// -/// This `struct` is created by the [`EventIterator::enumerate()`] method. See -/// its documentation for more. -pub struct Enumerate { - ei: I, - count: Cell, +pin_project_lite::pin_project! { + /// Event iterator that yields the current count and event during iteration + /// + /// This `struct` is created by the [`EventIterator::enumerate()`] method. + /// See its documentation for more. + pub struct Enumerate { + #[pin] + ei: I, + count: Option, + } } impl Enumerate { pub(crate) fn new(ei: I) -> Self { - let count = Cell::new(0); + let count = None; Self { ei, count } } @@ -38,22 +40,29 @@ where impl EventIterator for Enumerate where - I: EventIterator + Unpin, + I: EventIterator, { - type Event<'me> = (usize, I::Event<'me>) where I: 'me; - - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); - let Poll::Ready(event) = Pin::new(&this.ei).poll_next(cx) else { - return Poll::Pending; - }; - let count = this.count.get(); - - this.count.set(count + 1); - Poll::Ready(event.map(|e| (count, e))) + type Event<'me> + = (usize, I::Event<'me>) + where + I: 'me; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let this = self.project(); + let poll = this.ei.poll(cx); + + if poll.is_ready() { + (*this.count) = Some((*this.count).map(|c| c + 1).unwrap_or(0)); + } + + poll + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); + let count = (*this.count).expect(EVENT_BEFORE_POLL); + + this.ei.event().map(|e| (count, e)) } fn size_hint(&self) -> (usize, Option) { diff --git a/src/event_iter.rs b/src/event_iter.rs index c7ac6cb..152c525 100644 --- a/src/event_iter.rs +++ b/src/event_iter.rs @@ -1,20 +1,23 @@ use core::{ - ops::Deref, + ops::{Deref, DerefMut}, pin::Pin, task::{Context, Poll}, }; use crate::{ - Enumerate, Filter, FilterMap, Fuse, Inspect, Map, Next, Take, TakeWhile, - Tear, + Enumerate, Filter, FilterMapRef, Fuse, Inspect, LendAs, Map, MapRef, Next, + Take, TakeWhile, Tear, }; /// Asynchronous lending iterator /// -/// Unlike iterators, the type must only be modified through interior mutability -/// during iteration. This is to get around the limitation of not being able to -/// use [`Pin::as_mut()`] in some situations, due to the fact that events take -/// the lifetime of `Self`, resulting in insufficient lifetimes. +/// Rather than have a single `poll_next()` method as in `Stream` / +/// `AsyncIterator`, event iterators have separate `poll()` and `event()` +/// methods for polling and lending. Why? A lot of asynchronous implementation +/// patterns require usage of [`Pin::as_mut()`]. When GATs are in the mix, this +/// usage is impossible since it reduces the lifetime on your pinned reference +/// to `Self`, which would be insufficient for a returned +/// `Poll>>` lifetime. /// /// # Example /// @@ -23,76 +26,46 @@ use crate::{ /// ``` pub trait EventIterator { /// The type of the events being iterated over - type Event<'me> + type Event<'me>: Copy where Self: 'me; - /// Attempt to pull out the next event of this event iterator, registering - /// the current task for wakeup if the value is not yet available, and - /// returning `None` if the event iterator is exhausted. + /// Attempt to poll the next event of this event iterator, registering the + /// current task for wakeup if the event is not yet available. /// /// # Return value /// - /// There are several possible return values, each indicating a distinct - /// event iterator state: - /// /// - `Poll::Pending` means that this event iterator’s next value is not /// ready yet. Implementations will ensure that the current task will be /// notified when the next value may be ready. - /// - `Poll::Ready(Some(val))` means that the event iterator has - /// successfully produced a value, `val`, and may produce further values - /// on subsequent poll_next calls. - /// - `Poll::Ready(None)` means that the event iterator has terminated, and - /// `poll_next()` should not be invoked again. + /// - `Poll::Ready(())` means that the event iterator is either ready to + /// lend an event or has terminated. `event()` should be called to check. /// /// # Panics /// - /// Once an event iterator has finished (returned `Ready(None)` from - /// `poll_next()`), calling its `poll_next()` method again may panic, block - /// forever, or cause other kinds of problems; the `EventIterator` trait - /// places no requirements on the effects of such a call. However, as the - /// `poll_next()` method is not marked unsafe, Rust’s usual rules apply: - /// calls must never cause undefined behavior (memory corruption, incorrect - /// use of unsafe functions, or the like), regardless of the event - /// iterator’s state. - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>>; - - /// Create a future that resolves to the next event in the event iterator. - /// - /// This is more flexible than [`next_unpinned()`](Self::next_unpinned), but - /// often more verbose than needed. - /// - /// # Example - /// - /// ```rust - #[doc = include_str!("../examples/next.rs")] - /// ``` - fn next<'a>(self: Pin<&'a Self>) -> Next<'a, Self> - where - Self: Sized, - { - Next::new(self) - } + /// Once an event iterator has finished (returned `Ready` from `poll()` with + /// `event()` returning `None`), calling its `poll()` method again may + /// panic, block forever, or cause other kinds of problems; the + /// `EventIterator` trait places no requirements on the effects of such a + /// call. However, as the `poll()` method is not marked unsafe, Rust’s + /// usual rules apply: calls must never cause undefined behavior (memory + /// corruption, incorrect use of unsafe functions, or the like), regardless + /// of the event iterator’s state. + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()>; - /// Create a future that resolves to the next event in the event iterator. + /// Attempt to borrow the current event, and return `None` if the event + /// iterator is exhausted. /// - /// This is less flexible than [`next()`](Self::next), but avoids the need - /// to handle pinning yourself. - /// - /// # Example + /// # Panics /// - /// ```rust - #[doc = include_str!("../examples/next_unpinned.rs")] - /// ``` - fn next_unpinned(&self) -> Next<'_, Self> - where - Self: Sized + Unpin, - { - Pin::new(self).next() - } + /// Calling `event()` before `poll()` may panic, block forever or cause + /// other kinds of problems; the `EventIterator` trait places no + /// requirements on the effects of such a call. However, as the + /// `poll()` method is not marked unsafe, Rust’s usual rules apply: calls + /// must never cause undefined behavior (memory corruption, incorrect use of + /// unsafe functions, or the like), regardless of the event iterator’s + /// state. + fn event<'a>(self: Pin<&'a mut Self>) -> Option>; /// Return the bounds on the remaining length of the event iterator. /// @@ -130,24 +103,58 @@ pub trait EventIterator { (0, None) } - /// Take a closure and create an event iterator which calls that closure on - /// each event. + /// Create a future that resolves to the next event in the event iterator. + /// + /// This is less flexible than [`next()`](Self::next), but avoids the need + /// to handle pinning yourself. + /// + /// # Example + /// + /// ```rust + #[doc = include_str!("../examples/next.rs")] + /// ``` + fn next(&mut self) -> Next<'_, Self> + where + Self: Sized + Unpin, + { + Pin::new(self).next_pinned() + } + + /// Create a future that resolves to the next event in the event iterator. + /// + /// This is more flexible than [`next()`](Self::next), but often more + /// verbose than needed. + /// + /// # Example + /// + /// ```rust + #[doc = include_str!("../examples/next_pinned.rs")] + /// ``` + fn next_pinned<'a>(self: Pin<&'a mut Self>) -> Next<'a, Self> + where + Self: Sized, + { + Next::new(self) + } + + /// Take a type implementing [`LendAs`] and create an event iterator which + /// lends as a new type on each event. /// - /// `map()` transforms one event iterator into another, by means of its + /// `map_ref()` transforms one event iterator into another, by means of its /// argument: something that implements [`FnMut`]. It produces a new event /// iterator which calls this closure on each event of the original event /// iterator. /// - /// If you are good at thinking in types, you can think of `map()` like + /// If you are good at thinking in types, you can think of `map_ref()` like /// this: If you have an iterator that gives you elements of some type `A`, - /// and you want an iterator of some other type `B`, you can use `map()`, - /// passing a closure that takes an `A` and returns a `B`. + /// and you want an iterator of some other type `B`, you can use + /// `map_ref()`, passing a closure that takes an `A` and returns a `B`. /// - /// `map()` is conceptually similar to a `while let Some(_) = _.await` loop. - /// However, as `map()` is lazy, it is best used when you’re already working - /// with other event iterators. If you’re doing some sort of looping for a - /// side effect, it’s considered more idiomatic to use - /// `while let Some(_) = _.await` than `map()`. + /// `map_ref()` is conceptually similar to a `while let Some(_) = _.await` + /// loop. However, as `map_ref()` is lazy, it is best used when you’re + /// already working with other event iterators. If you’re doing some sort + /// of looping for a side effect, it’s considered more idiomatic to use + /// `while let Some(_) = _.await` than `map_ref()`. /// /// # Example /// @@ -163,12 +170,53 @@ pub trait EventIterator { /// uwuuwuuwuuwu /// uwuuwuuwuuwuuwu /// ``` - fn map(self, f: F) -> Map + fn map(self, lend_as: L) -> Map + where + Self: Sized, + L: for<'me> LendAs = Self::Event<'me>> + Copy, + { + Map::new(self, lend_as) + } + + /// Take a closure and create an event iterator of references which calls + /// that closure on each event. + /// + /// `map_ref()` transforms one event iterator into another, by means of its + /// argument: something that implements [`FnMut`]. It produces a new event + /// iterator which calls this closure on each event of the original event + /// iterator. + /// + /// If you are good at thinking in types, you can think of `map_ref()` like + /// this: If you have an iterator that gives you elements of some type `A`, + /// and you want an iterator of some other type `B`, you can use + /// `map_ref()`, passing a closure that takes an `A` and returns a `B`. + /// + /// `map_ref()` is conceptually similar to a `while let Some(_) = _.await` + /// loop. However, as `map_ref()` is lazy, it is best used when you’re + /// already working with other event iterators. If you’re doing some sort + /// of looping for a side effect, it’s considered more idiomatic to use + /// `while let Some(_) = _.await` than `map_ref()`. + /// + /// # Example + /// + /// ```rust + #[doc = include_str!("../examples/map_ref.rs")] + /// ``` + /// + /// Output: + /// ```console + /// uwu + /// uwuuwu + /// uwuuwuuwu + /// uwuuwuuwuuwu + /// uwuuwuuwuuwuuwu + /// ``` + fn map_ref(self, f: F) -> MapRef where Self: Sized, - F: for<'me> FnMut(Self::Event<'me>) -> B, + F: for<'me> FnMut(Self::Event<'me>) -> E, { - Map::new(self, f) + MapRef::new(self, f) } /// Create an event iterator which uses a closure to determine if an event @@ -186,7 +234,7 @@ pub trait EventIterator { fn filter

(self, predicate: P) -> Filter where Self: Sized, - P: for<'me> FnMut(&Self::Event<'me>) -> bool, + P: for<'me> FnMut(Self::Event<'me>) -> bool, { Filter::new(self, predicate) } @@ -196,22 +244,22 @@ pub trait EventIterator { /// The returned event iterator yields only the events for which the /// supplied closure returns `Some(event)`. /// - /// `filter_map()` can be used to make chains of [`filter()`](Self::filter) - /// and [`map()`](Self::map) more concise. The example below shows how a - /// `map().filter().map()` can be shortened to a single call to - /// `filter_map()`. + /// `filter_map_ref()` can be used to make chains of + /// [`filter()`](Self::filter) and [`map_ref()`](Self::map_ref) more + /// concise. The example below shows how a `map_ref().filter().map_ref()` + /// can be shortened to a single call to `filter_map_ref()`. /// /// # Example /// /// ```rust - #[doc = include_str!("../examples/filter_map.rs")] + #[doc = include_str!("../examples/filter_map_ref.rs")] /// ``` - fn filter_map(self, f: F) -> FilterMap + fn filter_map_ref(self, f: F) -> FilterMapRef where Self: Sized, - F: for<'me> FnMut(Self::Event<'me>) -> Option, + F: for<'me> FnMut(Self::Event<'me>) -> Option, { - FilterMap::new(self, f) + FilterMapRef::new(self, f) } /// Do something with each event of an event iterator, passing the value on. @@ -237,7 +285,7 @@ pub trait EventIterator { fn inspect(self, f: F) -> Inspect where Self: Sized, - F: for<'me> FnMut(&Self::Event<'me>), + F: for<'me> FnMut(Self::Event<'me>), { Inspect::new(self, f) } @@ -262,6 +310,9 @@ pub trait EventIterator { /// The returned event iterator might panic if the to-be-returned index /// would overflow a [`usize`]. /// + /// The returned event iterator might panic if [`EventIterator::event()`] is + /// called before [`EventIterator::poll()`]. + /// /// # Example /// /// ```rust @@ -356,7 +407,7 @@ pub trait EventIterator { fn take_while

(self, predicate: P) -> TakeWhile where Self: Sized, - P: for<'me> FnMut(&Self::Event<'me>) -> bool, + P: for<'me> FnMut(Self::Event<'me>) -> bool, { TakeWhile::new(self, predicate) } @@ -364,17 +415,20 @@ pub trait EventIterator { impl EventIterator for T where - T: Deref + ?Sized, + T: Deref + DerefMut + ?Sized + Unpin, T::Target: EventIterator + Unpin, { - type Event<'me> = <::Target as EventIterator>::Event<'me> - where Self: 'me; + type Event<'me> + = <::Target as EventIterator>::Event<'me> + where + Self: 'me; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + Pin::new(&mut **self.get_mut()).poll(cx) + } - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - Pin::new(&**self.get_ref()).poll_next(cx) + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + Pin::new(&mut **self.get_mut()).event() } fn size_hint(&self) -> (usize, Option) { diff --git a/src/filter.rs b/src/filter.rs index 56ddd0e..684c3f9 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -1,5 +1,4 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, @@ -7,19 +6,21 @@ use core::{ use crate::EventIterator; -/// Event iterator that filters the events of an event iterator with a predicate -/// -/// This `struct` is created by the [`EventIterator::filter()`] method. See its -/// documentation for more. -pub struct Filter { - ei: I, - p: Cell>, +pin_project_lite::pin_project! { + /// Event iterator that filters the events of an event iterator with a + /// predicate + /// + /// This `struct` is created by the [`EventIterator::filter()`] method. See + /// its documentation for more. + pub struct Filter { + #[pin] + ei: I, + p: P, + } } impl Filter { pub(crate) fn new(ei: I, p: P) -> Self { - let p = Cell::new(Some(p)); - Self { ei, p } } } @@ -37,37 +38,38 @@ where impl EventIterator for Filter where - I: EventIterator + Unpin, - P: for<'me> FnMut(&I::Event<'me>) -> bool + 'static + Unpin, + I: EventIterator, + P: for<'me> FnMut(I::Event<'me>) -> bool, { - type Event<'me> = I::Event<'me> where I: 'me; + type Event<'me> + = I::Event<'me> + where + I: 'me, + P: 'me; - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mut this = self.project(); loop { - let Poll::Ready(event) = Pin::new(&this.ei).poll_next(cx) else { + let Poll::Ready(()) = this.ei.as_mut().poll(cx) else { break Poll::Pending; }; - let Some(event) = event else { - break Poll::Ready(None); + let Some(event) = this.ei.as_mut().event() else { + break Poll::Ready(()); }; - let Some(mut predicate) = this.p.take() else { - break Poll::Ready(None); - }; - let should_yield = predicate(&event); - - this.p.set(Some(predicate)); - if should_yield { - break Poll::Ready(Some(event)); + if (this.p)(event) { + break Poll::Ready(()); } } } + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); + + this.ei.event() + } + fn size_hint(&self) -> (usize, Option) { let (_, upper) = self.ei.size_hint(); diff --git a/src/filter_map.rs b/src/filter_map.rs deleted file mode 100644 index 548d232..0000000 --- a/src/filter_map.rs +++ /dev/null @@ -1,77 +0,0 @@ -use core::{ - cell::Cell, - fmt, - pin::Pin, - task::{Context, Poll}, -}; - -use crate::EventIterator; - -/// Event iterator that uses a closure to both filter and map events -/// -/// This `struct` is created by the [`EventIterator::filter_map()`] method. See -/// its documentation for more. -pub struct FilterMap { - ei: I, - f: Cell>, -} - -impl FilterMap { - pub(crate) fn new(ei: I, f: F) -> Self { - let f = Cell::new(Some(f)); - - Self { ei, f } - } -} - -impl fmt::Debug for FilterMap -where - I: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("FilterMap") - .field("ei", &self.ei) - .finish_non_exhaustive() - } -} - -impl EventIterator for FilterMap -where - I: EventIterator + Unpin, - F: for<'me> FnMut(I::Event<'me>) -> Option + 'static + Unpin, -{ - type Event<'me> = B where I: 'me; - - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); - - loop { - let Poll::Ready(event) = Pin::new(&this.ei).poll_next(cx) else { - break Poll::Pending; - }; - let Some(event) = event else { - break Poll::Ready(None); - }; - let Some(mut f) = this.f.take() else { - break Poll::Ready(None); - }; - let event = f(event); - - this.f.set(Some(f)); - - let Some(event) = event else { continue }; - - break Poll::Ready(Some(event)); - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.ei.size_hint(); - - // Can't know a lower bound, due to the predicate - (0, upper) - } -} diff --git a/src/filter_map_ref.rs b/src/filter_map_ref.rs new file mode 100644 index 0000000..d6b74c8 --- /dev/null +++ b/src/filter_map_ref.rs @@ -0,0 +1,86 @@ +use core::{ + fmt, + pin::Pin, + task::{Context, Poll}, +}; + +use crate::EventIterator; + +pin_project_lite::pin_project! { + /// Event iterator that uses a closure to both filter and map a reference to + /// events + /// + /// This `struct` is created by the [`EventIterator::filter_map_ref()`] + /// method. See its documentation for more. + pub struct FilterMapRef { + #[pin] + ei: I, + f: F, + event: Option, + } +} + +impl FilterMapRef { + pub(crate) fn new(ei: I, f: F) -> Self { + let event = None; + + Self { ei, f, event } + } +} + +impl fmt::Debug for FilterMapRef +where + I: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FilterMapRef") + .field("ei", &self.ei) + .finish_non_exhaustive() + } +} + +impl EventIterator for FilterMapRef +where + I: EventIterator, + F: for<'me> FnMut(I::Event<'me>) -> Option, +{ + type Event<'me> + = &'me E + where + I: 'me, + E: 'me, + F: 'me; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mut this = self.project(); + + loop { + let Poll::Ready(()) = this.ei.as_mut().poll(cx) else { + break Poll::Pending; + }; + let Some(event) = this.ei.as_mut().event() else { + (*this.event) = None; + break Poll::Ready(()); + }; + + (*this.event) = (this.f)(event); + + if this.event.is_some() { + break Poll::Ready(()); + } + } + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); + + this.event.as_ref() + } + + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.ei.size_hint(); + + // Can't know a lower bound, due to the predicate + (0, upper) + } +} diff --git a/src/from_fn.rs b/src/from_fn.rs index 9ceb05b..7bfabbf 100644 --- a/src/from_fn.rs +++ b/src/from_fn.rs @@ -1,5 +1,4 @@ use core::{ - cell::Cell, fmt, future::Future, pin::Pin, @@ -8,22 +7,30 @@ use core::{ use crate::EventIterator; -/// Event iterator where each iteration calls the provided closure -/// -/// This event iterator is created by the [`from_fn()`] function. See its -/// documentation for more. -pub struct FromFn { - generator: Cell>, - future: Cell>, +pin_project_lite::pin_project! { + /// Event iterator where each iteration calls the provided closure + /// + /// This event iterator is created by the [`from_fn()`] function. See its + /// documentation for more. + pub struct FromFn + where + F: Future, + G: FnMut() -> F, + { + generator: G, + #[pin] + future: Option, + event: Option, + } } -impl fmt::Debug for FromFn { +impl fmt::Debug for FromFn { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FromFn").finish_non_exhaustive() } } -impl EventIterator for FromFn +impl EventIterator for FromFn where F: Future> + Unpin, G: FnMut() -> F + Unpin, @@ -61,13 +68,14 @@ where /// ```rust #[doc = include_str!("../examples/from_fn.rs")] /// ``` -pub fn from_fn(gen: G) -> FromFn +pub fn from_fn(generator: G) -> FromFn where F: Future>, G: FnMut() -> F, { FromFn { - generator: Cell::new(Some(gen)), - future: Cell::new(None), + generator, + future: None, + event: None, } } diff --git a/src/from_iter.rs b/src/from_iter.rs deleted file mode 100644 index a7e2001..0000000 --- a/src/from_iter.rs +++ /dev/null @@ -1,83 +0,0 @@ -use core::{ - cell::Cell, - fmt, - pin::Pin, - task::{Context, Poll}, -}; - -use crate::EventIterator; - -/// Event iterator that was created from an iterator -/// -/// This event iterator is created by the [`from_iter()`] function. See its -/// documentation for more. -pub struct FromIter(Cell>); - -impl fmt::Debug for FromIter -where - I: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let iter = self.0.take(); - let result = f.debug_tuple("FromIter").field(&iter).finish(); - - self.0.set(iter); - result - } -} - -impl Unpin for FromIter {} - -impl EventIterator for FromIter -where - I: Iterator, -{ - type Event<'me> = ::Item where I: 'me; - - fn poll_next<'a>( - self: Pin<&'a Self>, - _cx: &mut Context<'_>, - ) -> Poll>> { - Poll::Ready(self.0.take().and_then(|mut iter| { - let item = iter.next()?; - - self.0.set(Some(iter)); - Some(item) - })) - } - - fn size_hint(&self) -> (usize, Option) { - self.0 - .take() - .map(|iter| { - let size = iter.size_hint(); - - self.0.set(Some(iter)); - size - }) - .unwrap_or((0, Some(0))) - } -} - -/// Convert an iterator into an event iterator. -/// -/// # Example -/// -/// ```rust -#[doc = include_str!("../examples/from_iter.rs")] -/// ``` -/// -/// Output: -/// ```console -/// 1 -/// 2 -/// 3 -/// 4 -/// 5 -/// ``` -pub fn from_iter(iter: I) -> FromIter<::IntoIter> -where - I: IntoIterator, -{ - FromIter(Cell::new(iter.into_iter().into())) -} diff --git a/src/from_iter_ref.rs b/src/from_iter_ref.rs new file mode 100644 index 0000000..ccabdc6 --- /dev/null +++ b/src/from_iter_ref.rs @@ -0,0 +1,104 @@ +use core::{ + fmt, + iter::Peekable, + pin::Pin, + task::{Context, Poll}, +}; + +use crate::{consts::EVENT_BEFORE_POLL, EventIterator}; + +/// Event iterator of references that was created from an iterator +/// +/// This event iterator is created by the [`from_iter_ref()`] function. See its +/// documentation for more. +pub struct FromIterRef +where + I: Iterator, +{ + iter: Peekable, + started: bool, +} + +impl fmt::Debug for FromIterRef +where + I: Iterator + fmt::Debug, + ::Item: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("FromIterRef").field(&self.iter).finish() + } +} + +impl EventIterator for FromIterRef +where + I: Iterator + Unpin, + ::Item: Unpin, +{ + type Event<'me> + = &'me ::Item + where + I: 'me; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> { + let this = self.get_mut(); + + if this.started { + _ = this.iter.next(); + } else { + this.started = true; + } + + Poll::Ready(()) + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.get_mut(); + + if !this.started { + panic!("{EVENT_BEFORE_POLL}"); + } + + this.iter.peek() + } + + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.iter.size_hint(); + + if self.started { + (lower.saturating_sub(1), upper.map(|n| n.saturating_sub(1))) + } else { + (lower, upper) + } + } +} + +/// Convert an iterator into an event iterator of references. +/// +/// # Example +/// +/// ```rust +#[doc = include_str!("../examples/from_iter_ref.rs")] +/// ``` +/// +/// Output: +/// ```console +/// 1 +/// 2 +/// 3 +/// 4 +/// 5 +/// ``` +/// +/// # Panics +/// +/// The returned event iterator might panic if [`EventIterator::event()`] is +/// called before [`EventIterator::poll()`]. +pub fn from_iter_ref(iter: I) -> FromIterRef<::IntoIter> +where + I: IntoIterator, +{ + FromIterRef { + iter: iter.into_iter().peekable(), + started: false, + } +} diff --git a/src/fuse.rs b/src/fuse.rs index e7cab31..78e53c1 100644 --- a/src/fuse.rs +++ b/src/fuse.rs @@ -1,5 +1,4 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, @@ -7,15 +6,18 @@ use core::{ use crate::EventIterator; -/// Event iterator that returns `Ready(None)` forever after it's finished -/// -/// An event iterator is finished after it first returns `Ready(None)`. -/// -/// This `struct` is created by the [`EventIterator::fuse()`] method. See its -/// documentation for more. -pub struct Fuse { - ei: I, - ended: Cell, +pin_project_lite::pin_project! { + /// Event iterator that returns `Ready(None)` forever after it's finished + /// + /// An event iterator is finished after it first returns `Ready(None)`. + /// + /// This `struct` is created by the [`EventIterator::fuse()`] method. See + /// its documentation for more. + #[repr(transparent)] + pub struct Fuse { + #[pin] + ei: Option, + } } impl fmt::Debug for Fuse @@ -23,47 +25,50 @@ where I: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Fuse") - .field("ei", &self.ei) - .field("ended", &self.ended) - .finish() + f.debug_struct("Fuse").field("ei", &self.ei).finish() } } impl Fuse { pub(crate) fn new(ei: I) -> Self { - let ended = Cell::new(false); - - Self { ei, ended } + Self { ei: Some(ei) } } } impl EventIterator for Fuse where - I: EventIterator + Unpin, + I: EventIterator, { - type Event<'me> = I::Event<'me> where I: 'me; + type Event<'me> + = I::Event<'me> + where + I: 'me; - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let this = self.project(); + let Some(ei) = this.ei.as_pin_mut() else { + return Poll::Ready(()); + }; - if this.ended.get() { - return Poll::Ready(None); - } + ei.poll(cx) + } - let poll = Pin::new(&this.ei).poll_next(cx); + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let mut this = self.project(); + let ei = this.ei.as_mut().as_pin_mut()?; - if let Poll::Ready(None) = poll { - this.ended.set(true); + if ei.event().is_none() { + this.ei.set(None); + return None; } - poll + this.ei.as_pin_mut().and_then(|ei| ei.event()) } fn size_hint(&self) -> (usize, Option) { - self.ei.size_hint() + self.ei + .as_ref() + .map(|ei| ei.size_hint()) + .unwrap_or((0, Some(0))) } } diff --git a/src/inspect.rs b/src/inspect.rs index d06b770..76787fd 100644 --- a/src/inspect.rs +++ b/src/inspect.rs @@ -1,5 +1,4 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, @@ -7,19 +6,20 @@ use core::{ use crate::EventIterator; -/// Event iterator that calls a closure with a reference to each event -/// -/// This `struct` is created by the [`EventIterator::map()`] method. See its -/// documentation for more. -pub struct Inspect { - ei: I, - f: Cell>, +pin_project_lite::pin_project! { + /// Event iterator that calls a closure with a reference to each event + /// + /// This `struct` is created by the [`EventIterator::inspect()`] method. + /// See its documentation for more. + pub struct Inspect { + #[pin] + ei: I, + f: F, + } } impl Inspect { pub(crate) fn new(ei: I, f: F) -> Self { - let f = Cell::new(Some(f)); - Self { ei, f } } } @@ -37,27 +37,32 @@ where impl EventIterator for Inspect where - I: EventIterator + Unpin, - F: for<'me> FnMut(&I::Event<'me>) + 'static + Unpin, + I: EventIterator, + F: for<'me> FnMut(I::Event<'me>), { - type Event<'me> = I::Event<'me> where I: 'me; + type Event<'me> + = I::Event<'me> + where + I: 'me, + F: 'me; - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); - let event = Pin::new(&this.ei).poll_next(cx); - let Poll::Ready(Some(event)) = event else { - return event; - }; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mut this = self.project(); + let poll = this.ei.as_mut().poll(cx); - if let Some(mut f) = this.f.take() { - f(&event); - this.f.set(Some(f)); + if poll.is_ready() { + if let Some(event) = this.ei.event() { + (*this.f)(event); + } } - Poll::Ready(Some(event)) + poll + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); + + this.ei.event() } fn size_hint(&self) -> (usize, Option) { diff --git a/src/lend_as.rs b/src/lend_as.rs new file mode 100644 index 0000000..d41e8c8 --- /dev/null +++ b/src/lend_as.rs @@ -0,0 +1,12 @@ +/// A lending conversion trait +/// +/// For lending a type as another. Should be a lightweight operation. +pub trait LendAs { + /// Type converting from + type From<'a>; + /// Type converting into + type Into<'a>; + + /// Lend a type to another type. + fn lend_as(self, from: Self::From<'_>) -> Self::Into<'_>; +} diff --git a/src/lib.rs b/src/lib.rs index f6116e4..b094cd2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,49 +42,54 @@ variant_size_differences )] -mod as_event_iter; +//mod as_event_iter; mod empty; mod enumerate; mod event_iter; mod filter; -mod filter_map; -mod from_fn; -mod from_iter; +mod filter_map_ref; +//mod from_fn; +mod consts; +mod from_iter_ref; mod fuse; mod inspect; mod map; +mod map_ref; mod next; -mod once; -mod once_with; +//mod once; +//mod once_with; mod pending; -mod poll_fn; -mod ready; -mod repeat; -mod repeat_with; +//mod poll_fn; +//mod ready; +//mod repeat; +//mod repeat_with; +mod lend_as; mod take; mod take_while; mod tear; pub use self::{ - as_event_iter::{AsEventIter, AsEventIterator}, + // as_event_iter::{AsEventIter, AsEventIterator}, empty::{empty, Empty}, enumerate::Enumerate, event_iter::EventIterator, filter::Filter, - filter_map::FilterMap, - from_fn::{from_fn, FromFn}, - from_iter::{from_iter, FromIter}, + filter_map_ref::FilterMapRef, + //from_fn::{from_fn, FromFn}, + from_iter_ref::{from_iter_ref, FromIterRef}, fuse::Fuse, inspect::Inspect, + lend_as::LendAs, map::Map, + map_ref::MapRef, next::Next, - once::{once, Once}, - once_with::{once_with, OnceWith}, + // once::{once, Once}, + // once_with::{once_with, OnceWith}, pending::{pending, Pending}, - poll_fn::{poll_fn, PollFn}, - ready::{ready, Ready}, - repeat::{repeat, Repeat}, - repeat_with::{repeat_with, RepeatWith}, + // poll_fn::{poll_fn, PollFn}, + // ready::{ready, Ready}, + // repeat::{repeat, Repeat}, + // repeat_with::{repeat_with, RepeatWith}, take::Take, take_while::TakeWhile, tear::Tear, diff --git a/src/map.rs b/src/map.rs index 4a45deb..6926700 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,30 +1,30 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, }; -use crate::EventIterator; +use crate::{EventIterator, LendAs}; -/// Event iterator that maps the events with a closure -/// -/// This `struct` is created by the [`EventIterator::map()`] method. See its -/// documentation for more. -pub struct Map { - ei: I, - f: Cell>, +pin_project_lite::pin_project! { + /// Event iterator that maps the events with a type implementing [`LendAs`] + /// + /// This `struct` is created by the [`EventIterator::map()`] method. + /// See its documentation for more. + pub struct Map { + #[pin] + ei: I, + lend_as : L, + } } -impl Map { - pub(crate) fn new(ei: I, f: F) -> Self { - let f = Cell::new(Some(f)); - - Self { ei, f } +impl Map { + pub(crate) fn new(ei: I, lend_as: L) -> Self { + Self { ei, lend_as } } } -impl fmt::Debug for Map +impl fmt::Debug for Map where I: fmt::Debug, { @@ -35,28 +35,27 @@ where } } -impl EventIterator for Map +impl EventIterator for Map where - I: EventIterator + Unpin, - F: for<'me> FnMut(I::Event<'me>) -> B + 'static + Unpin, + I: EventIterator, + L: for<'me> LendAs = I::Event<'me>> + Copy, + for<'a> L::Into<'a>: Copy, { - type Event<'me> = B where I: 'me; + type Event<'me> + = L::Into<'me> + where + Self: 'me; - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); - let Poll::Ready(event) = Pin::new(&this.ei).poll_next(cx) else { - return Poll::Pending; - }; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mut this = self.project(); + + this.ei.as_mut().poll(cx) + } - Poll::Ready(this.f.take().and_then(|mut f| { - let event = event.map(&mut f); + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); - this.f.set(Some(f)); - event - })) + Some(this.lend_as.lend_as(this.ei.event()?)) } fn size_hint(&self) -> (usize, Option) { diff --git a/src/map_ref.rs b/src/map_ref.rs new file mode 100644 index 0000000..6207be2 --- /dev/null +++ b/src/map_ref.rs @@ -0,0 +1,71 @@ +use core::{ + fmt, + pin::Pin, + task::{Context, Poll}, +}; + +use crate::EventIterator; + +pin_project_lite::pin_project! { + /// Event iterator that maps the events with a closure to a reference + /// + /// This `struct` is created by the [`EventIterator::map_ref()`] method. + /// See its documentation for more. + pub struct MapRef { + #[pin] + ei: I, + f: F, + event: Option, + } +} + +impl MapRef { + pub(crate) fn new(ei: I, f: F) -> Self { + let event = None; + + Self { ei, f, event } + } +} + +impl fmt::Debug for MapRef +where + I: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("MapRef") + .field("ei", &self.ei) + .finish_non_exhaustive() + } +} + +impl EventIterator for MapRef +where + I: EventIterator, + F: for<'me> FnMut(I::Event<'me>) -> E, +{ + type Event<'me> + = &'me E + where + Self: 'me; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mut this = self.project(); + let poll = this.ei.as_mut().poll(cx); + + if poll.is_ready() { + (*this.event) = this.ei.event().map(this.f); + } + + poll + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); + + this.event.as_ref() + } + + fn size_hint(&self) -> (usize, Option) { + self.ei.size_hint() + } +} diff --git a/src/next.rs b/src/next.rs index b47cac9..24ae443 100644 --- a/src/next.rs +++ b/src/next.rs @@ -9,13 +9,13 @@ use crate::EventIterator; /// Future to get the next event in an [`EventIterator`] /// /// This `struct` is created by the [`next()`](EventIterator::next) and -/// [`next_unpinned()`](EventIterator::next_unpinned) methods. See their +/// [`next_pinned()`](EventIterator::next_pinned) methods. See their /// documentation for more. #[derive(Debug)] -pub struct Next<'a, Ei>(Option>); +pub struct Next<'a, Ei>(Option>); impl<'a, Ei> Next<'a, Ei> { - pub(crate) fn new(ei: Pin<&'a Ei>) -> Self { + pub(crate) fn new(ei: Pin<&'a mut Ei>) -> Self { Self(Some(ei)) } } @@ -28,15 +28,14 @@ where fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let this = self.get_mut(); - let Some(ei) = this.0.as_ref() else { - return Poll::Ready(None); + let Some(mut ei) = this.0.take() else { + return Poll::Pending; + }; + let Poll::Ready(()) = ei.as_mut().poll(cx) else { + this.0 = Some(ei); + return Poll::Pending; }; - let output = ei.poll_next(cx); - - if output.is_ready() { - this.0 = None; - } - output + Poll::Ready(ei.event()) } } diff --git a/src/pending.rs b/src/pending.rs index 26e89e6..51671e2 100644 --- a/src/pending.rs +++ b/src/pending.rs @@ -5,29 +5,42 @@ use core::{ task::{Context, Poll}, }; -use crate::EventIterator; +use crate::{consts::EVENT_BEFORE_POLL, EventIterator}; -/// Event iterator that never produces an event and never finishes +/// [Torn](crate::Tear) event iterator that never produces an event and never +/// finishes /// /// This event iterator is created by the [`pending()`] function. See its /// documentation for more. -pub struct Pending(PhantomData); +pub struct Pending(PhantomData) +where + E: Copy; -impl fmt::Debug for Pending { +impl fmt::Debug for Pending +where + E: Copy, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Pending").field(&format_args!("_")).finish() } } -impl EventIterator for Pending { - type Event<'me> = E where Self: 'me; +impl EventIterator for Pending +where + E: Copy, +{ + type Event<'me> + = E + where + Self: 'me; - fn poll_next<'a>( - self: Pin<&'a Self>, - _cx: &mut Context<'_>, - ) -> Poll>> { + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<()> { Poll::Pending } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + panic!("{EVENT_BEFORE_POLL}"); + } } /// Create an event iterator that never produces an event and never finishes. @@ -39,6 +52,9 @@ impl EventIterator for Pending { /// ```rust #[doc = include_str!("../examples/pending.rs")] /// ``` -pub fn pending() -> Pending { +pub fn pending() -> Pending +where + E: Copy, +{ Pending(PhantomData::) } diff --git a/src/take.rs b/src/take.rs index 44550bb..f45c3cf 100644 --- a/src/take.rs +++ b/src/take.rs @@ -1,5 +1,4 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, @@ -7,18 +6,21 @@ use core::{ use crate::EventIterator; -/// Event iterator that only yields a specified number of events -/// -/// This `struct` is created by the [`EventIterator::take()`] method. See its -/// documentation for more. -pub struct Take { - ei: I, - count: Cell, +pin_project_lite::pin_project! { + /// Event iterator that only yields a specified number of events + /// + /// This `struct` is created by the [`EventIterator::take()`] method. See + /// its documentation for more. + pub struct Take { + #[pin] + ei: I, + count: usize, + } } impl Take { pub(crate) fn new(ei: I, count: usize) -> Self { - let count = Cell::new(count); + let count = count.checked_add(1).expect("overflow in take"); Self { ei, count } } @@ -38,31 +40,41 @@ where impl EventIterator for Take where - I: EventIterator + Unpin, + I: EventIterator, { - type Event<'me> = I::Event<'me> where I: 'me; + type Event<'me> + = I::Event<'me> + where + I: 'me; - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); - let count = this.count.get(); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let this = self.project(); - if count == 0 { - return Poll::Ready(None); + if *this.count == 0 { + return Poll::Ready(()); } - let Poll::Ready(event) = Pin::new(&this.ei).poll_next(cx) else { - return Poll::Pending; - }; + let poll = this.ei.poll(cx); + + if poll.is_ready() { + (*this.count) -= 1; + } + + poll + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); + + if *this.count == 0 { + return None; + } - this.count.set(count - 1); - Poll::Ready(event) + this.ei.event() } fn size_hint(&self) -> (usize, Option) { - let count = self.count.get(); + let count = self.count; if count == 0 { return (0, Some(0)); diff --git a/src/take_while.rs b/src/take_while.rs index f84bc00..43decef 100644 --- a/src/take_while.rs +++ b/src/take_while.rs @@ -1,5 +1,4 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, @@ -7,18 +6,22 @@ use core::{ use crate::EventIterator; -/// Event iterator that only yields elements while a predicate returns `true` -/// -/// This `struct` is created by the [`EventIterator::take_while()`] method. See -/// its documentation for more. -pub struct TakeWhile { - ei: I, - p: Cell>, +pin_project_lite::pin_project! { + /// Event iterator that only yields elements while a predicate returns + /// `true` + /// + /// This `struct` is created by the [`EventIterator::take_while()`] method. + /// See its documentation for more. + pub struct TakeWhile { + #[pin] + ei: Option, + p: P, + } } impl TakeWhile { pub(crate) fn new(ei: I, p: P) -> Self { - let p = Cell::new(Some(p)); + let ei = Some(ei); Self { ei, p } } @@ -37,38 +40,45 @@ where impl EventIterator for TakeWhile where - I: EventIterator + Unpin, - P: for<'me> FnMut(&I::Event<'me>) -> bool + 'static + Unpin, + I: EventIterator, + P: for<'me> FnMut(I::Event<'me>) -> bool, { - type Event<'me> = I::Event<'me> where I: 'me; - - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); + type Event<'me> + = I::Event<'me> + where + I: 'me, + P: 'me; - loop { - let Poll::Ready(event) = Pin::new(&this.ei).poll_next(cx) else { - break Poll::Pending; - }; - let Some(event) = event else { - break Poll::Ready(None); - }; - let Some(mut predicate) = this.p.take() else { - break Poll::Ready(None); - }; - let should_yield = predicate(&event); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let mut this = self.project(); + let Some(mut ei) = this.ei.as_mut().as_pin_mut() else { + return Poll::Ready(()); + }; + let Poll::Ready(()) = ei.as_mut().poll(cx) else { + return Poll::Pending; + }; + let Some(event) = ei.as_mut().event() else { + return Poll::Ready(()); + }; - if should_yield { - this.p.set(Some(predicate)); - break Poll::Ready(Some(event)); - } + if !(this.p)(event) { + this.ei.set(None); } + + Poll::Ready(()) + } + + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let this = self.project(); + + this.ei.as_pin_mut()?.event() } fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.ei.size_hint(); + let Some(ref ei) = self.ei else { + return (0, None); + }; + let (_, upper) = ei.size_hint(); // Can't know a lower bound, due to the predicate (0, upper) diff --git a/src/tear.rs b/src/tear.rs index a5b3e1c..940a39d 100644 --- a/src/tear.rs +++ b/src/tear.rs @@ -1,5 +1,4 @@ use core::{ - cell::Cell, fmt, pin::Pin, task::{Context, Poll}, @@ -7,15 +6,17 @@ use core::{ use crate::EventIterator; -/// Event iterator that returns `Pending` forever after it's finished -/// -/// An event iterator is finished after it first returns `Ready(None)`. -/// -/// This `struct` is created by the [`EventIterator::tear()`] method. See -/// its documentation for more. -pub struct Tear { - ei: I, - ended: Cell, +pin_project_lite::pin_project! { + /// Event iterator that returns `Pending` forever after it's finished + /// + /// An event iterator is finished after it first returns `Ready(None)`. + /// + /// This `struct` is created by the [`EventIterator::tear()`] method. See + /// its documentation for more. + pub struct Tear { + #[pin] + ei: Option, + } } impl fmt::Debug for Tear @@ -23,47 +24,50 @@ where I: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Tear") - .field("ei", &self.ei) - .field("ended", &self.ended) - .finish() + f.debug_struct("Tear").field("ei", &self.ei).finish() } } impl Tear { pub(crate) fn new(ei: I) -> Self { - let ended = Cell::new(false); - - Self { ei, ended } + Self { ei: Some(ei) } } } impl EventIterator for Tear where - I: EventIterator + Unpin, + I: EventIterator, { - type Event<'me> = I::Event<'me> where I: 'me; - - fn poll_next<'a>( - self: Pin<&'a Self>, - cx: &mut Context<'_>, - ) -> Poll>> { - let this = self.get_ref(); + type Event<'me> + = I::Event<'me> + where + I: 'me; - if this.ended.get() { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + let this = self.project(); + let Some(ei) = this.ei.as_pin_mut() else { return Poll::Pending; - } + }; + + ei.poll(cx) + } - let poll = Pin::new(&this.ei).poll_next(cx); + fn event<'a>(self: Pin<&'a mut Self>) -> Option> { + let mut this = self.project(); + let ei = this.ei.as_mut().as_pin_mut()?; - if let Poll::Ready(None) = poll { - this.ended.set(true); + if ei.event().is_none() { + this.ei.set(None); + return None; } - poll + this.ei.as_pin_mut().and_then(|ei| ei.event()) } fn size_hint(&self) -> (usize, Option) { - self.ei.size_hint() + self.ei + .as_ref() + .map(|ei| ei.size_hint()) + .unwrap_or((0, Some(0))) } }