want/lib.rs
1#![doc(html_root_url = "https://docs.rs/want/0.3.1")]
2#![deny(warnings)]
3#![deny(missing_docs)]
4#![deny(missing_debug_implementations)]
5
6//! A Futures channel-like utility to signal when a value is wanted.
7//!
8//! Futures are supposed to be lazy, and only starting work if `Future::poll`
9//! is called. The same is true of `Stream`s, but when using a channel as
10//! a `Stream`, it can be hard to know if the receiver is ready for the next
11//! value.
12//!
13//! Put another way, given a `(tx, rx)` from `futures::sync::mpsc::channel()`,
14//! how can the sender (`tx`) know when the receiver (`rx`) actually wants more
15//! work to be produced? Just because there is room in the channel buffer
16//! doesn't mean the work would be used by the receiver.
17//!
18//! This is where something like `want` comes in. Added to a channel, you can
19//! make sure that the `tx` only creates the message and sends it when the `rx`
20//! has `poll()` for it, and the buffer was empty.
21//!
22//! # Example
23//!
24//! ```nightly
25//! # //#![feature(async_await)]
26//! extern crate want;
27//!
28//! # fn spawn<T>(_t: T) {}
29//! # fn we_still_want_message() -> bool { true }
30//! # fn mpsc_channel() -> (Tx, Rx) { (Tx, Rx) }
31//! # struct Tx;
32//! # impl Tx { fn send<T>(&mut self, _: T) {} }
33//! # struct Rx;
34//! # impl Rx { async fn recv(&mut self) -> Option<Expensive> { Some(Expensive) } }
35//!
36//! // Some message that is expensive to produce.
37//! struct Expensive;
38//!
39//! // Some futures-aware MPSC channel...
40//! let (mut tx, mut rx) = mpsc_channel();
41//!
42//! // And our `want` channel!
43//! let (mut gv, mut tk) = want::new();
44//!
45//!
46//! // Our receiving task...
47//! spawn(async move {
48//! // Maybe something comes up that prevents us from ever
49//! // using the expensive message.
50//! //
51//! // Without `want`, the "send" task may have started to
52//! // produce the expensive message even though we wouldn't
53//! // be able to use it.
54//! if !we_still_want_message() {
55//! return;
56//! }
57//!
58//! // But we can use it! So tell the `want` channel.
59//! tk.want();
60//!
61//! match rx.recv().await {
62//! Some(_msg) => println!("got a message"),
63//! None => println!("DONE"),
64//! }
65//! });
66//!
67//! // Our sending task
68//! spawn(async move {
69//! // It's expensive to create a new message, so we wait until the
70//! // receiving end truly *wants* the message.
71//! if let Err(_closed) = gv.want().await {
72//! // Looks like they will never want it...
73//! return;
74//! }
75//!
76//! // They want it, let's go!
77//! tx.send(Expensive);
78//! });
79//!
80//! # fn main() {}
81//! ```
82
83use std::fmt;
84use std::future::Future;
85use std::mem;
86use std::pin::Pin;
87use std::sync::Arc;
88use std::sync::atomic::AtomicUsize;
89// SeqCst is the only ordering used to ensure accessing the state and
90// TryLock are never re-ordered.
91use std::sync::atomic::Ordering::SeqCst;
92use std::task::{self, Poll, Waker};
93
94
95use try_lock::TryLock;
96
97/// Create a new `want` channel.
98pub fn new() -> (Giver, Taker) {
99 let inner = Arc::new(Inner {
100 state: AtomicUsize::new(State::Idle.into()),
101 task: TryLock::new(None),
102 });
103 let inner2 = inner.clone();
104 (
105 Giver {
106 inner,
107 },
108 Taker {
109 inner: inner2,
110 },
111 )
112}
113
114/// An entity that gives a value when wanted.
115pub struct Giver {
116 inner: Arc<Inner>,
117}
118
119/// An entity that wants a value.
120pub struct Taker {
121 inner: Arc<Inner>,
122}
123
124/// A cloneable `Giver`.
125///
126/// It differs from `Giver` in that you cannot poll for `want`. It's only
127/// usable as a cancellation watcher.
128#[derive(Clone)]
129pub struct SharedGiver {
130 inner: Arc<Inner>,
131}
132
133/// The `Taker` has canceled its interest in a value.
134pub struct Closed {
135 _inner: (),
136}
137
138#[derive(Clone, Copy, Debug)]
139enum State {
140 Idle,
141 Want,
142 Give,
143 Closed,
144}
145
146impl From<State> for usize {
147 fn from(s: State) -> usize {
148 match s {
149 State::Idle => 0,
150 State::Want => 1,
151 State::Give => 2,
152 State::Closed => 3,
153 }
154 }
155}
156
157impl From<usize> for State {
158 fn from(num: usize) -> State {
159 match num {
160 0 => State::Idle,
161 1 => State::Want,
162 2 => State::Give,
163 3 => State::Closed,
164 _ => unreachable!("unknown state: {}", num),
165 }
166 }
167}
168
169struct Inner {
170 state: AtomicUsize,
171 task: TryLock<Option<Waker>>,
172}
173
174// ===== impl Giver ======
175
176impl Giver {
177 /// Returns a `Future` that fulfills when the `Taker` has done some action.
178 pub fn want(&mut self) -> impl Future<Output = Result<(), Closed>> + '_ {
179 Want(self)
180 }
181
182 /// Poll whether the `Taker` has registered interest in another value.
183 ///
184 /// - If the `Taker` has called `want()`, this returns `Async::Ready(())`.
185 /// - If the `Taker` has not called `want()` since last poll, this
186 /// returns `Async::NotReady`, and parks the current task to be notified
187 /// when the `Taker` does call `want()`.
188 /// - If the `Taker` has canceled (or dropped), this returns `Closed`.
189 ///
190 /// After knowing that the Taker is wanting, the state can be reset by
191 /// calling [`give`](Giver::give).
192 pub fn poll_want(&mut self, cx: &mut task::Context<'_>) -> Poll<Result<(), Closed>> {
193 loop {
194 let state = self.inner.state.load(SeqCst).into();
195 match state {
196 State::Want => {
197 return Poll::Ready(Ok(()));
198 },
199 State::Closed => {
200 return Poll::Ready(Err(Closed { _inner: () }));
201 },
202 State::Idle | State::Give => {
203 // Taker doesn't want anything yet, so park.
204 if let Some(mut locked) = self.inner.task.try_lock_explicit(SeqCst, SeqCst) {
205
206 // While we have the lock, try to set to GIVE.
207 let old = self.inner.state.compare_exchange(
208 state.into(),
209 State::Give.into(),
210 SeqCst,
211 SeqCst,
212 );
213 // If it's still the first state (Idle or Give), park current task.
214 if old == Ok(state.into()) {
215 let park = locked.as_ref()
216 .map(|w| !w.will_wake(cx.waker()))
217 .unwrap_or(true);
218 if park {
219 let old = mem::replace(&mut *locked, Some(cx.waker().clone()));
220 drop(locked);
221 if let Some(prev_task) = old {
222 // there was an old task parked here.
223 // it might be waiting to be notified,
224 // so poke it before dropping.
225 prev_task.wake();
226 };
227 }
228 return Poll::Pending;
229 }
230 // Otherwise, something happened! Go around the loop again.
231 } else {
232 // if we couldn't take the lock, then a Taker has it.
233 // The *ONLY* reason is because it is in the process of notifying us
234 // of its want.
235 //
236 // We need to loop again to see what state it was changed to.
237 }
238 },
239 }
240 }
241 }
242
243 /// Mark the state as idle, if the Taker currently is wanting.
244 ///
245 /// Returns true if Taker was wanting, false otherwise.
246 #[inline]
247 pub fn give(&self) -> bool {
248 // only set to IDLE if it is still Want
249 let old = self.inner.state.compare_exchange(
250 State::Want.into(),
251 State::Idle.into(),
252 SeqCst,
253 SeqCst);
254 old == Ok(State::Want.into())
255 }
256
257 /// Check if the `Taker` has called `want()` without parking a task.
258 ///
259 /// This is safe to call outside of a futures task context, but other
260 /// means of being notified is left to the user.
261 #[inline]
262 pub fn is_wanting(&self) -> bool {
263 self.inner.state.load(SeqCst) == State::Want.into()
264 }
265
266
267 /// Check if the `Taker` has canceled interest without parking a task.
268 #[inline]
269 pub fn is_canceled(&self) -> bool {
270 self.inner.state.load(SeqCst) == State::Closed.into()
271 }
272
273 /// Converts this into a `SharedGiver`.
274 #[inline]
275 pub fn shared(self) -> SharedGiver {
276 SharedGiver {
277 inner: self.inner,
278 }
279 }
280}
281
282impl fmt::Debug for Giver {
283 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
284 f.debug_struct("Giver")
285 .field("state", &self.inner.state())
286 .finish()
287 }
288}
289
290// ===== impl SharedGiver ======
291
292impl SharedGiver {
293 /// Check if the `Taker` has called `want()` without parking a task.
294 ///
295 /// This is safe to call outside of a futures task context, but other
296 /// means of being notified is left to the user.
297 #[inline]
298 pub fn is_wanting(&self) -> bool {
299 self.inner.state.load(SeqCst) == State::Want.into()
300 }
301
302
303 /// Check if the `Taker` has canceled interest without parking a task.
304 #[inline]
305 pub fn is_canceled(&self) -> bool {
306 self.inner.state.load(SeqCst) == State::Closed.into()
307 }
308}
309
310impl fmt::Debug for SharedGiver {
311 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312 f.debug_struct("SharedGiver")
313 .field("state", &self.inner.state())
314 .finish()
315 }
316}
317
318// ===== impl Taker ======
319
320impl Taker {
321 /// Signal to the `Giver` that the want is canceled.
322 ///
323 /// This is useful to tell that the channel is closed if you cannot
324 /// drop the value yet.
325 #[inline]
326 pub fn cancel(&mut self) {
327 self.signal(State::Closed)
328 }
329
330 /// Signal to the `Giver` that a value is wanted.
331 #[inline]
332 pub fn want(&mut self) {
333 debug_assert!(
334 self.inner.state.load(SeqCst) != State::Closed.into(),
335 "want called after cancel"
336 );
337 self.signal(State::Want)
338 }
339
340 /// Mark the state as idle, if the `Taker` is currently wanting.
341 ///
342 /// This withdraws a `want()` that is no longer true, such as one signaled
343 /// just before a value arrived.
344 #[inline]
345 pub fn unwant(&mut self) {
346 let _ = self.inner.state.compare_exchange(
347 State::Want.into(),
348 State::Idle.into(),
349 SeqCst,
350 SeqCst);
351 }
352
353 #[inline]
354 fn signal(&mut self, state: State) {
355 let old_state = self.inner.state.swap(state.into(), SeqCst).into();
356 match old_state {
357 State::Idle | State::Want | State::Closed => (),
358 State::Give => {
359 loop {
360 if let Some(mut locked) = self.inner.task.try_lock_explicit(SeqCst, SeqCst) {
361 if let Some(task) = locked.take() {
362 drop(locked);
363 task.wake();
364 }
365 return;
366 } else {
367 // if we couldn't take the lock, then a Giver has it.
368 // The *ONLY* reason is because it is in the process of parking.
369 //
370 // We need to loop and take the lock so we can notify this task.
371 }
372 }
373 },
374 }
375 }
376}
377
378impl Drop for Taker {
379 #[inline]
380 fn drop(&mut self) {
381 self.signal(State::Closed);
382 }
383}
384
385impl fmt::Debug for Taker {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 f.debug_struct("Taker")
388 .field("state", &self.inner.state())
389 .finish()
390 }
391}
392
393// ===== impl Closed ======
394
395impl fmt::Debug for Closed {
396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397 f.debug_struct("Closed")
398 .finish()
399 }
400}
401
402// ===== impl Inner ======
403
404impl Inner {
405 #[inline]
406 fn state(&self) -> State {
407 self.state.load(SeqCst).into()
408 }
409}
410
411// ===== impl PollFn ======
412
413struct Want<'a>(&'a mut Giver);
414
415
416impl Future for Want<'_> {
417 type Output = Result<(), Closed>;
418
419 fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
420 self.0.poll_want(cx)
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 use std::thread;
427 use tokio_sync::oneshot;
428 use super::*;
429
430 fn block_on<F: Future>(f: F) -> F::Output {
431 tokio_executor::enter()
432 .expect("block_on enter")
433 .block_on(f)
434 }
435
436 #[test]
437 fn want_ready() {
438 let (mut gv, mut tk) = new();
439
440 tk.want();
441
442 block_on(gv.want()).unwrap();
443 }
444
445 #[test]
446 fn want_notify_0() {
447 let (mut gv, mut tk) = new();
448 let (tx, rx) = oneshot::channel();
449
450 thread::spawn(move || {
451 tk.want();
452 // use a oneshot to keep this thread alive
453 // until other thread was notified of want
454 block_on(rx).expect("rx");
455 });
456
457 block_on(gv.want()).expect("want");
458
459 assert!(gv.is_wanting(), "still wanting after poll_want success");
460 assert!(gv.give(), "give is true when wanting");
461
462 assert!(!gv.is_wanting(), "no longer wanting after give");
463 assert!(!gv.is_canceled(), "give doesn't cancel");
464
465 assert!(!gv.give(), "give is false if not wanting");
466
467 tx.send(()).expect("tx");
468 }
469
470 /*
471 /// This tests that if the Giver moves tasks after parking,
472 /// it will still wake up the correct task.
473 #[test]
474 fn want_notify_moving_tasks() {
475 use std::sync::Arc;
476 use futures::executor::{spawn, Notify, NotifyHandle};
477
478 struct WantNotify;
479
480 impl Notify for WantNotify {
481 fn notify(&self, _id: usize) {
482 }
483 }
484
485 fn n() -> NotifyHandle {
486 Arc::new(WantNotify).into()
487 }
488
489 let (mut gv, mut tk) = new();
490
491 let mut s = spawn(poll_fn(move || {
492 gv.poll_want()
493 }));
494
495 // Register with t1 as the task::current()
496 let t1 = n();
497 assert!(s.poll_future_notify(&t1, 1).unwrap().is_not_ready());
498
499 thread::spawn(move || {
500 thread::sleep(::std::time::Duration::from_millis(100));
501 tk.want();
502 });
503
504 // And now, move to a ThreadNotify task.
505 s.into_inner().wait().expect("poll_want");
506 }
507 */
508
509 #[test]
510 fn cancel() {
511 // explicit
512 let (mut gv, mut tk) = new();
513
514 assert!(!gv.is_canceled());
515
516 tk.cancel();
517
518 assert!(gv.is_canceled());
519 block_on(gv.want()).unwrap_err();
520
521 // implicit
522 let (mut gv, tk) = new();
523
524 assert!(!gv.is_canceled());
525
526 drop(tk);
527
528 assert!(gv.is_canceled());
529 block_on(gv.want()).unwrap_err();
530
531 // notifies
532 let (mut gv, tk) = new();
533
534 thread::spawn(move || {
535 let _tk = tk;
536 // and dropped
537 });
538
539 block_on(gv.want()).unwrap_err();
540 }
541
542 #[test]
543 fn unwant() {
544 let (gv, mut tk) = new();
545
546 tk.want();
547 assert!(gv.is_wanting());
548
549 tk.unwant();
550 assert!(!gv.is_wanting());
551 assert!(!gv.give());
552
553 // Only a want is withdrawn: a canceled Taker stays canceled.
554 tk.cancel();
555 tk.unwant();
556 assert!(gv.is_canceled());
557 }
558
559 /*
560 #[test]
561 fn stress() {
562 let nthreads = 5;
563 let nwants = 100;
564
565 for _ in 0..nthreads {
566 let (mut gv, mut tk) = new();
567 let (mut tx, mut rx) = mpsc::channel(0);
568
569 // rx thread
570 thread::spawn(move || {
571 let mut cnt = 0;
572 poll_fn(move || {
573 while cnt < nwants {
574 let n = match rx.poll().expect("rx poll") {
575 Async::Ready(n) => n.expect("rx opt"),
576 Async::NotReady => {
577 tk.want();
578 return Ok(Async::NotReady);
579 },
580 };
581 assert_eq!(cnt, n);
582 cnt += 1;
583 }
584 Ok::<_, ()>(Async::Ready(()))
585 }).wait().expect("rx wait");
586 });
587
588 // tx thread
589 thread::spawn(move || {
590 let mut cnt = 0;
591 let nsent = poll_fn(move || {
592 loop {
593 while let Ok(()) = tx.try_send(cnt) {
594 cnt += 1;
595 }
596 match gv.poll_want() {
597 Ok(Async::Ready(_)) => (),
598 Ok(Async::NotReady) => return Ok::<_, ()>(Async::NotReady),
599 Err(_) => return Ok(Async::Ready(cnt)),
600 }
601 }
602 }).wait().expect("tx wait");
603
604 assert_eq!(nsent, nwants);
605 }).join().expect("thread join");
606 }
607 }
608 */
609}