diff --git a/Cargo.toml b/Cargo.toml index 0deb7f7..51ab114 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "want" -version = "0.0.6" # remember to update html_root_url +version = "0.2.0" # remember to update html_root_url description = "Detect when another Future wants a result." keywords = ["futures", "channel"] authors = ["Sean McArthur "] diff --git a/LICENSE b/LICENSE index 2c77834..e0f0f8a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018 Sean McArthur +Copyright (c) 2018-2019 Sean McArthur Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index a8d169a..bd71b52 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,24 @@ # Want +- [Crates.io](https://crates.io/crates/want) +- [Docs](https://docs.rs/want) + A `Future`s channel-like utility to signal when a value is wanted. + +Futures are supposed to be lazy, and only starting work if `Future::poll` +is called. The same is true of `Stream`s, but when using a channel as +a `Stream`, it can be hard to know if the receiver is ready for the next +value. + +Put another way, given a `(tx, rx)` from `futures::sync::mpsc::channel()`, +how can the sender (`tx`) know when the receiver (`rx`) actually wants more +work to be produced? Just because there is room in the channel buffer +doesn't mean the work would be used by the receiver. + +This is where something like `want` comes in. Added to a channel, you can +make sure that the `tx` only creates the message and sends it when the `rx` +has `poll()` for it, and the buffer was empty. + +## License + +`want` is provided under the MIT license. See [LICENSE](LICENSE). diff --git a/src/lib.rs b/src/lib.rs index fb6fe48..657be07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://docs.rs/want/0.0.6")] +#![doc(html_root_url = "https://docs.rs/want/0.2.0")] #![deny(warnings)] #![deny(missing_docs)] #![deny(missing_debug_implementations)] @@ -18,6 +18,71 @@ //! This is where something like `want` comes in. Added to a channel, you can //! make sure that the `tx` only creates the message and sends it when the `rx` //! has `poll()` for it, and the buffer was empty. +//! +//! # Example +//! +//! ``` +//! extern crate futures; +//! extern crate want; +//! +//! use futures::{Async, Stream}; +//! +//! // Some message that is expensive to produce. +//! struct Expensive; +//! +//! let (mut tx, mut rx) = futures::sync::mpsc::channel(0); +//! let (mut gv, mut tk) = want::new(); +//! +//! # fn spawn(_t: T) {} +//! # fn can_we_print_msg() -> Result<(), ()> { Ok(()) } +//! +//! // Our receiving task... +//! spawn(futures::future::poll_fn(move || loop { +//! +//! match rx.poll() { +//! Ok(Async::Ready(Some(_msg))) => { +//! println!("got a message"); +//! }, +//! Ok(Async::Ready(None)) => { +//! println!("DONE"); +//! return Ok::<_, ()>(Async::Ready(())); +//! }, +//! Ok(Async::NotReady) => { +//! // Maybe something comes up that prevents us from ever +//! // using the expensive message. +//! // +//! // Without `want`, the "send" task may have started to +//! // produce the expensive message even though we wouldn't +//! // be able to use it. +//! can_we_print_msg()?; +//! +//! // But we can use it! So tell the `want` channel. +//! tk.want(); +//! }, +//! Err(()) => unreachable!("mpsc doesn't error"), +//! } +//! })); +//! +//! // Our sending task +//! spawn(futures::future::poll_fn(move || { +//! // It's expensive to create a new message, so we wait until the +//! // receiving end truly *wants* the message. +//! match gv.poll_want() { +//! Ok(Async::Ready(())) => { +//! // They want it, let's go! +//! tx.try_send(Expensive).unwrap(); +//! Ok(Async::Ready(())) +//! }, +//! Ok(Async::NotReady) => Ok(Async::NotReady), +//! Err(_) => { +//! // Looks like they will never want it... +//! Err(()) +//! } +//! } +//! })); +//! +//! # fn main() {} +//! ``` extern crate futures; #[macro_use]