Skip to main content

ntex_util/channel/
bstream.rs

1//! A buffered stream of byte chunks.
2use std::cell::{Cell, RefCell};
3use std::task::{Context, Poll};
4use std::{collections::VecDeque, fmt, future::poll_fn, pin::Pin, rc::Rc, rc::Weak};
5
6use ntex_bytes::Bytes;
7use ntex_service::ReadyNotifier;
8
9use crate::{Stream, future::OnDropFn, task::LocalWaker};
10
11/// Default high watermark, 32 KiB
12const HIGH_WATERMARK: u32 = 32_768;
13/// Default low watermark, 16 KiB
14const LOW_WATERMARK: u32 = HIGH_WATERMARK / 2;
15
16/// Indicates the current status of a byte stream.
17#[derive(Copy, Clone, Debug, PartialEq, Eq)]
18pub enum Status {
19    /// End of stream reached.
20    Eof,
21    /// Stream is ready to accept more bytes.
22    Ready,
23    /// The receiver side has been dropped.
24    Dropped,
25}
26
27/// Creates a byte stream and returns its sender and receiver.
28pub fn channel<E>() -> (Sender<E>, Receiver<E>) {
29    channel_inner(Inner::new(false))
30}
31
32/// Creates a byte stream that invalidates cached sender readiness.
33///
34/// Subscribe to `changed` in [`ntex_service::Service::bind`] before using the
35/// stream. The same notifier may be supplied to successive streams when a
36/// service's active stream changes at runtime. Installing or removing that
37/// active stream must also notify, since it changes the service's readiness.
38///
39/// Watermark and terminal-state transitions notify before waking waiters,
40/// including when the receiver is dropped after a successful readiness check.
41pub fn channel_with_notifier<E>(changed: ReadyNotifier) -> (Sender<E>, Receiver<E>) {
42    channel_inner(Inner {
43        changed: Some(changed),
44        ..Inner::new(false)
45    })
46}
47
48/// Creates a byte stream that starts at EOF.
49///
50/// Data may still be added through the returned sender. The receiver yields
51/// that buffered data first and then completes.
52pub fn eof<E>() -> (Sender<E>, Receiver<E>) {
53    channel_inner(Inner::new(true))
54}
55
56fn channel_inner<E>(inner: Inner<E>) -> (Sender<E>, Receiver<E>) {
57    let inner = Rc::new(inner);
58    (
59        Sender {
60            inner: Rc::downgrade(&inner),
61        },
62        Receiver { inner },
63    )
64}
65
66/// Creates a receiver that contains optional data and is already at EOF.
67pub fn empty<E>(data: Option<Bytes>) -> Receiver<E> {
68    let rx = Receiver {
69        inner: Rc::new(Inner::new(true)),
70    };
71    if let Some(data) = data {
72        rx.put(data);
73    }
74    rx
75}
76
77/// A buffered stream of byte chunks.
78///
79/// The receiver yields chunks in insertion order. Its configured buffer size
80/// is a cooperative backpressure threshold for the sender, not a hard memory
81/// limit.
82#[derive(Debug)]
83pub struct Receiver<E> {
84    inner: Rc<Inner<E>>,
85}
86
87impl<E> Receiver<E> {
88    /// Sets the sender backpressure watermarks.
89    ///
90    /// Once buffered data reaches `high` bytes, [`Sender::poll_ready`] stops
91    /// reporting [`Status::Ready`] until the receiver drains the buffer to
92    /// `low` bytes or less, so the sender is not woken for every consumed
93    /// chunk. `low` is capped below `high`.
94    ///
95    /// Sending does not enforce the watermarks, so producers must cooperate
96    /// by waiting for readiness. Changing the watermarks immediately updates
97    /// and, when needed, wakes sender readiness: the sender is ready if
98    /// buffered data is below `high`. The defaults are 32 KiB and 16 KiB.
99    #[inline]
100    pub fn set_watermarks(&self, high: u32, low: u32) {
101        self.inner.set_watermarks(high, low);
102    }
103
104    /// Sets the sender backpressure threshold.
105    ///
106    /// Sets the high watermark to `size` and the low watermark to half of it.
107    #[inline]
108    #[deprecated(since = "4.2.0", note = "Use `Receiver::set_watermarks()` instead")]
109    pub fn max_buffer_size(&self, size: usize) {
110        let size = u32::try_from(size).unwrap_or(u32::MAX);
111        self.inner.set_watermarks(size, size / 2);
112    }
113
114    /// Puts previously read data back at the front of the stream.
115    ///
116    /// This may grow the buffer past its readiness threshold.
117    #[inline]
118    pub fn put(&self, data: Bytes) {
119        self.inner.unread_data(data);
120    }
121
122    #[inline]
123    /// Returns `true` once EOF has been marked.
124    ///
125    /// Buffered chunks may still be available after this returns `true`.
126    pub fn is_eof(&self) -> bool {
127        self.inner.flags.get().contains(Flags::EOF)
128    }
129
130    #[inline]
131    /// Waits for and returns the next chunk, stream error, or EOF.
132    pub async fn read(&self) -> Option<Result<Bytes, E>> {
133        poll_fn(|cx| self.poll_read(cx)).await
134    }
135
136    #[inline]
137    /// Polls for the next chunk, stream error, or EOF.
138    pub fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, E>>> {
139        if let Some(data) = self.inner.get_data() {
140            Poll::Ready(Some(Ok(data)))
141        } else if let Some(err) = self.inner.err.take() {
142            self.inner.insert_flag(Flags::EOF);
143            Poll::Ready(Some(Err(err)))
144        } else if self.inner.flags.get().intersects(Flags::EOF | Flags::ERROR) {
145            Poll::Ready(None)
146        } else {
147            self.inner.recv_task.register(cx.waker());
148            Poll::Pending
149        }
150    }
151}
152
153impl<E> Stream for Receiver<E> {
154    type Item = Result<Bytes, E>;
155
156    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
157        self.poll_read(cx)
158    }
159}
160
161impl<E> Drop for Receiver<E> {
162    fn drop(&mut self) {
163        let flags = self.inner.flags.get();
164        self.inner.insert_flag(Flags::RECEIVER_GONE);
165        self.inner.notify(flags, false, true);
166    }
167}
168
169/// Sender side of the byte stream.
170///
171/// Clones share one readiness registration. If several clones poll readiness,
172/// the most recently registered task is the one that will be woken.
173#[derive(Debug)]
174pub struct Sender<E> {
175    inner: Weak<Inner<E>>,
176}
177
178impl<E> Clone for Sender<E> {
179    fn clone(&self) -> Self {
180        Self {
181            inner: self.inner.clone(),
182        }
183    }
184}
185
186impl<E> Drop for Sender<E> {
187    fn drop(&mut self) {
188        if self.inner.weak_count() == 1
189            && let Some(shared) = self.inner.upgrade()
190        {
191            let flags = shared.flags.get();
192            shared.insert_flag(Flags::EOF | Flags::SENDER_GONE);
193            // a pending read completes with EOF
194            shared.notify(flags, true, true);
195        }
196    }
197}
198
199impl<E> Sender<E> {
200    /// Returns `true` if the receiver has been dropped.
201    pub fn is_closed(&self) -> bool {
202        self.inner
203            .upgrade()
204            .is_none_or(|shared| shared.flags.get().contains(Flags::RECEIVER_GONE))
205    }
206
207    /// Stores a terminal stream error and wakes both sides.
208    ///
209    /// The error is ignored once EOF has been marked, including after an
210    /// earlier error was read.
211    pub fn set_error(&self, err: E) {
212        if let Some(shared) = self.inner.upgrade() {
213            shared.set_error(err);
214        }
215    }
216
217    /// Marks the stream as EOF and wakes both sides.
218    pub fn feed_eof(&self) {
219        if let Some(shared) = self.inner.upgrade() {
220            shared.feed_eof();
221        }
222    }
223
224    /// Adds a chunk to the stream.
225    ///
226    /// This method does not enforce the configured backpressure threshold.
227    /// The chunk is dropped once EOF has been marked or an error was set.
228    pub fn feed_data(&self, data: Bytes) {
229        if let Some(shared) = self.inner.upgrade() {
230            shared.feed_data(data);
231        }
232    }
233
234    /// Waits until the stream needs more data or reaches a terminal state.
235    pub async fn ready(&self) -> Status {
236        poll_fn(|cx| self.poll_ready(cx)).await
237    }
238
239    /// Polls until the stream needs more data or reaches a terminal state.
240    ///
241    /// Terminal states take precedence: [`Status::Dropped`] is returned once
242    /// the receiver is gone or an error was set, [`Status::Eof`] after EOF.
243    pub fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Status> {
244        if let Some(shared) = self.inner.upgrade() {
245            let status = shared.flags.get().status();
246            if status.is_pending() {
247                shared.send_task.register(cx.waker());
248            }
249            status
250        } else {
251            // receiver is gone
252            Poll::Ready(Status::Dropped)
253        }
254    }
255}
256
257bitflags::bitflags! {
258    #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
259    struct Flags: u8 {
260        const EOF         = 0b0000_0001;
261        const ERROR       = 0b0000_0010;
262        const NEED_READ   = 0b0000_0100;
263        const SENDER_GONE = 0b0000_1000;
264        const RECEIVER_GONE = 0b0001_0000;
265    }
266}
267
268impl Flags {
269    fn status(self) -> Poll<Status> {
270        if self.intersects(Self::SENDER_GONE | Self::RECEIVER_GONE | Self::ERROR) {
271            Poll::Ready(Status::Dropped)
272        } else if self.contains(Self::EOF) {
273            Poll::Ready(Status::Eof)
274        } else if self.contains(Self::NEED_READ) {
275            Poll::Ready(Status::Ready)
276        } else {
277            Poll::Pending
278        }
279    }
280}
281
282struct Inner<E> {
283    len: Cell<usize>,
284    flags: Cell<Flags>,
285    err: Cell<Option<E>>,
286    items: RefCell<VecDeque<Bytes>>,
287    recv_task: LocalWaker,
288    send_task: LocalWaker,
289    high_watermark: Cell<u32>,
290    low_watermark: Cell<u32>,
291    changed: Option<ReadyNotifier>,
292}
293
294impl<E> Inner<E> {
295    fn new(eof: bool) -> Self {
296        let flags = if eof { Flags::EOF } else { Flags::NEED_READ };
297        Inner {
298            flags: Cell::new(flags),
299            len: Cell::new(0),
300            err: Cell::new(None),
301            items: RefCell::new(VecDeque::new()),
302            recv_task: LocalWaker::new(),
303            send_task: LocalWaker::new(),
304            high_watermark: Cell::new(HIGH_WATERMARK),
305            low_watermark: Cell::new(LOW_WATERMARK),
306            changed: None,
307        }
308    }
309
310    fn insert_flag(&self, f: Flags) {
311        let mut flags = self.flags.get();
312        flags.insert(f);
313        self.flags.set(flags);
314    }
315
316    fn remove_flag(&self, f: Flags) {
317        let mut flags = self.flags.get();
318        flags.remove(f);
319        self.flags.set(flags);
320    }
321
322    fn notify(&self, previous: Flags, recv: bool, send: bool) {
323        let _wake = OnDropFn::new(|| {
324            if recv {
325                self.recv_task.wake();
326            }
327            if send {
328                self.send_task.wake();
329            }
330        });
331        if previous.status() != self.flags.get().status()
332            && let Some(changed) = &self.changed
333        {
334            changed.notify();
335        }
336    }
337
338    fn set_watermarks(&self, high: u32, low: u32) {
339        self.high_watermark.set(high);
340        self.low_watermark.set(low.min(high.saturating_sub(1)));
341
342        let flags = self.flags.get();
343        if flags.intersects(Flags::EOF | Flags::ERROR | Flags::SENDER_GONE) {
344            return;
345        }
346
347        if self.len.get() < high as usize {
348            if !flags.contains(Flags::NEED_READ) {
349                self.insert_flag(Flags::NEED_READ);
350                self.notify(flags, false, true);
351            }
352        } else {
353            self.remove_flag(Flags::NEED_READ);
354            self.notify(flags, false, false);
355        }
356    }
357
358    fn set_error(&self, err: E) {
359        let flags = self.flags.get();
360        if flags.contains(Flags::EOF) {
361            return;
362        }
363        self.err.set(Some(err));
364        self.insert_flag(Flags::ERROR);
365        self.notify(flags, true, true);
366    }
367
368    fn feed_eof(&self) {
369        let flags = self.flags.get();
370        self.insert_flag(Flags::EOF);
371        self.notify(flags, true, true);
372    }
373
374    fn feed_data(&self, data: Bytes) {
375        let flags = self.flags.get();
376        if flags.intersects(Flags::EOF | Flags::ERROR) {
377            return;
378        }
379        let len = self.len.get() + data.len();
380        self.len.set(len);
381        self.items.borrow_mut().push_back(data);
382        if len >= self.high_watermark.get() as usize {
383            self.remove_flag(Flags::NEED_READ);
384        }
385        self.notify(flags, true, false);
386    }
387
388    fn get_data(&self) -> Option<Bytes> {
389        let data = self.items.borrow_mut().pop_front();
390        data.inspect(|data| {
391            let flags = self.flags.get();
392            let len = self.len.get() - data.len();
393
394            // wake up sender once the buffer is drained to the low watermark
395            self.len.set(len);
396            if len <= self.low_watermark.get() as usize {
397                self.insert_flag(Flags::NEED_READ);
398                self.notify(flags, false, true);
399            }
400        })
401    }
402
403    fn unread_data(&self, data: Bytes) {
404        let flags = self.flags.get();
405        if !data.is_empty() {
406            self.len.set(self.len.get() + data.len());
407            self.items.borrow_mut().push_front(data);
408            if self.len.get() >= self.high_watermark.get() as usize {
409                self.remove_flag(Flags::NEED_READ);
410            }
411            self.notify(flags, false, false);
412        }
413    }
414}
415
416impl<E> fmt::Debug for Inner<E> {
417    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418        f.debug_struct("Inner")
419            .field("len", &self.len)
420            .field("flags", &self.flags)
421            .field("items", &self.items.borrow())
422            .field("high_watermark", &self.high_watermark)
423            .field("low_watermark", &self.low_watermark)
424            .field("recv_task", &self.recv_task)
425            .field("send_task", &self.send_task)
426            .finish()
427    }
428}
429
430#[cfg(test)]
431mod tests {
432    use ntex_service::{BindCtx, Ctx, Pipeline, ReadyCallback, Service};
433
434    use super::*;
435    use crate::future::lazy;
436
437    struct SenderService(Sender<()>, ReadyNotifier);
438
439    impl Service<(), Bytes> for SenderService {
440        type Res = ();
441        type Error = Status;
442
443        fn bind(&self, ctx: BindCtx<'_>) {
444            ctx.subscribe(&self.1);
445        }
446
447        async fn ready(&self, _: Ctx<'_, Self>) -> Result<(), Status> {
448            match self.0.ready().await {
449                Status::Ready => Ok(()),
450                status => Err(status),
451            }
452        }
453
454        async fn call(&self, data: Bytes, _: Ctx<'_, Self>) -> Result<(), Status> {
455            self.0.feed_data(data);
456            Ok(())
457        }
458    }
459
460    /// STATEMENT: Byte-stream watermarks invalidate cached sender readiness on capacity changes.
461    ///
462    /// HOW:
463    /// - Fill the stream through a pipeline, drain data, and put data back through the receiver.
464    /// - Check readiness across each transition and across raised and lowered watermarks.
465    #[ntex::test]
466    async fn cached_sender_readiness_tracks_watermarks() {
467        let changed = ReadyNotifier::new();
468        let (tx, rx) = channel_with_notifier(changed.clone());
469        rx.set_watermarks(4, 2);
470        let srv = Pipeline::new((), SenderService(tx, changed));
471
472        srv.call(Bytes::from_static(b"ab")).await.unwrap();
473        assert!(srv.is_ready());
474        srv.call(Bytes::from_static(b"cd")).await.unwrap();
475        assert!(!srv.is_ready());
476        assert!(lazy(|cx| srv.poll_ready(cx)).await.is_pending());
477        assert_eq!(rx.read().await, Some(Ok(Bytes::from_static(b"ab"))));
478        srv.ready().await.unwrap();
479
480        rx.put(Bytes::from_static(b"ef"));
481        assert!(!srv.is_ready());
482        assert!(lazy(|cx| srv.poll_ready(cx)).await.is_pending());
483        rx.set_watermarks(8, 4);
484        srv.ready().await.unwrap();
485        rx.set_watermarks(4, 2);
486        assert!(!srv.is_ready());
487        assert!(lazy(|cx| srv.poll_ready(cx)).await.is_pending());
488    }
489
490    /// STATEMENT: Terminal stream states invalidate cached readiness before callbacks inspect them.
491    ///
492    /// HOW:
493    /// - Prime sender readiness, then signal EOF or an error and verify the reported status.
494    /// - Drop a receiver and inspect closed state from a notification callback and subsequent readiness.
495    #[ntex::test]
496    async fn cached_sender_readiness_tracks_terminal_states() {
497        for status in [Status::Eof, Status::Dropped] {
498            let changed = ReadyNotifier::new();
499            let (tx, _rx) = channel_with_notifier(changed.clone());
500            let srv = Pipeline::new((), SenderService(tx.clone(), changed));
501            srv.ready().await.unwrap();
502            if status == Status::Eof {
503                tx.feed_eof();
504            } else {
505                tx.set_error(());
506            }
507            assert!(!srv.is_ready());
508            assert_eq!(srv.ready().await, Err(status));
509        }
510
511        let changed = ReadyNotifier::new();
512        let (tx, rx) = channel_with_notifier(changed.clone());
513        let srv = Pipeline::new((), SenderService(tx.clone(), changed));
514        let on_drop = ReadyCallback::new(move |_| {
515            assert!(tx.is_closed());
516            assert_eq!(
517                tx.poll_ready(&mut Context::from_waker(std::task::Waker::noop())),
518                Poll::Ready(Status::Dropped)
519            );
520        });
521        srv.on_notify(&on_drop);
522        srv.ready().await.unwrap();
523        drop(rx);
524        assert!(!srv.is_ready());
525        assert_eq!(srv.ready().await, Err(Status::Dropped));
526    }
527
528    /// STATEMENT: Readiness callback panics do not suppress byte-stream reader or sender wakeups.
529    ///
530    /// HOW:
531    /// - Register a counted reader waker and catch a callback panic while filling the stream.
532    /// - Register sender readiness, catch another panic while draining, and verify both wakeups.
533    #[ntex::test]
534    async fn callback_panic_does_not_skip_stream_wakes() {
535        use std::panic::{AssertUnwindSafe, catch_unwind};
536        use std::sync::{Arc, atomic::AtomicUsize, atomic::Ordering};
537        use std::task::{Wake, Waker};
538
539        #[derive(Default)]
540        struct WakeCount(AtomicUsize);
541        impl Wake for WakeCount {
542            fn wake(self: Arc<Self>) {
543                self.0.fetch_add(1, Ordering::Relaxed);
544            }
545        }
546
547        let changed = ReadyNotifier::new();
548        let (tx, rx) = channel_with_notifier(changed.clone());
549        rx.set_watermarks(1, 0);
550        let srv = Pipeline::new((), SenderService(tx.clone(), changed));
551        srv.ready().await.unwrap();
552        let armed = Rc::new(Cell::new(true));
553        let armed2 = armed.clone();
554        let callback = ReadyCallback::new(move |_| {
555            assert!(!armed2.replace(false), "callback panic");
556        });
557        srv.on_notify(&callback);
558        let wakes = Arc::new(WakeCount::default());
559        let waker = Waker::from(wakes.clone());
560        let mut cx = Context::from_waker(&waker);
561
562        assert!(rx.poll_read(&mut cx).is_pending());
563        assert!(catch_unwind(AssertUnwindSafe(|| tx.feed_data(b"x".into()))).is_err());
564        assert!(!srv.is_ready());
565        assert_eq!(wakes.0.load(Ordering::Relaxed), 1);
566        assert!(tx.poll_ready(&mut cx).is_pending());
567
568        armed.set(true);
569        assert!(catch_unwind(AssertUnwindSafe(|| rx.poll_read(&mut cx))).is_err());
570        assert_eq!(wakes.0.load(Ordering::Relaxed), 2);
571        srv.ready().await.unwrap();
572    }
573
574    /// STATEMENT: Dropping the sender wakes a blocked receiver with end-of-stream.
575    ///
576    /// HOW:
577    /// - Spawn a pending read, drop the sender, and await the task within a deadline.
578    /// - Verify the read returned no data.
579    #[ntex::test]
580    async fn test_sender_drop_wakes_receiver() {
581        let (tx, rx) = channel::<()>();
582        let handle = crate::spawn(async move { rx.read().await.is_none() });
583        crate::time::sleep(crate::time::Millis(10)).await;
584
585        drop(tx);
586        let res = crate::time::timeout(crate::time::Millis(1000), handle).await;
587        assert!(matches!(res, Ok(Ok(true))));
588    }
589
590    /// STATEMENT: An EOF channel remains terminal after setting watermarks.
591    ///
592    /// HOW:
593    /// - Construct an EOF channel, configure its watermarks, and check receiver and sender results.
594    #[ntex::test]
595    async fn test_eof() {
596        let (tx, rx) = eof::<()>();
597        rx.set_watermarks(100, 50);
598        assert!(rx.read().await.is_none());
599        assert_eq!(tx.ready().await, Status::Eof);
600    }
601
602    /// STATEMENT: Dropping either byte-stream endpoint closes its peer.
603    ///
604    /// HOW:
605    /// - Drop a receiver and check the sender's closed flag.
606    /// - Drop a sender in a fresh channel and verify the receiver returns no data.
607    #[ntex::test]
608    async fn test_closed() {
609        // drop receiver
610        let (tx, rx) = channel::<()>();
611        assert!(!tx.is_closed());
612        drop(rx);
613        assert!(tx.is_closed());
614
615        // drop sender
616        let (tx, rx) = channel::<()>();
617        drop(tx);
618        assert_eq!(rx.read().await, None);
619    }
620
621    /// STATEMENT: Data put back by the receiver is counted and can be read again.
622    ///
623    /// HOW:
624    /// - Put a byte chunk into the receiver, check buffered length, and poll back the same bytes.
625    #[ntex::test]
626    async fn test_unread_data() {
627        let (_, payload) = channel::<()>();
628
629        payload.put(Bytes::from("data"));
630        assert_eq!(payload.inner.len.get(), 4);
631        assert_eq!(
632            Bytes::from("data"),
633            poll_fn(|cx| payload.poll_read(cx)).await.unwrap().unwrap()
634        );
635    }
636
637    /// STATEMENT: Changing the high watermark immediately updates sender backpressure.
638    ///
639    /// HOW:
640    /// - Fill to the high watermark and register a pending sender waker.
641    /// - Raise the watermark to release readiness, then lower it to block again.
642    #[ntex::test]
643    async fn buffer_size_updates_sender_readiness() {
644        let (tx, rx) = channel::<()>();
645        rx.set_watermarks(4, 2);
646        tx.feed_data(Bytes::from_static(b"data"));
647
648        assert!(lazy(|cx| tx.poll_ready(cx)).await.is_pending());
649        assert!(rx.inner.send_task.is_set());
650
651        rx.set_watermarks(5, 2);
652        assert!(!rx.inner.send_task.is_set());
653        assert_eq!(
654            lazy(|cx| tx.poll_ready(cx)).await,
655            Poll::Ready(Status::Ready)
656        );
657
658        rx.set_watermarks(4, 2);
659        assert!(lazy(|cx| tx.poll_ready(cx)).await.is_pending());
660    }
661
662    /// STATEMENT: A blocked sender resumes at the low watermark, which is capped below the high one.
663    ///
664    /// HOW:
665    /// - Drain a full stream incrementally and check pending readiness above the low watermark.
666    /// - Verify readiness at the threshold and repeat with an oversized low-watermark setting.
667    #[ntex::test]
668    async fn sender_resumes_at_low_watermark() {
669        let (tx, rx) = channel::<()>();
670        rx.set_watermarks(8, 4);
671        for _ in 0..4 {
672            tx.feed_data(Bytes::from_static(b"da"));
673        }
674        assert!(lazy(|cx| tx.poll_ready(cx)).await.is_pending());
675
676        // above the low watermark
677        assert!(rx.read().await.is_some());
678        assert!(rx.inner.send_task.is_set());
679        assert!(lazy(|cx| tx.poll_ready(cx)).await.is_pending());
680
681        // at the low watermark
682        assert!(rx.read().await.is_some());
683        assert!(!rx.inner.send_task.is_set());
684        assert_eq!(
685            lazy(|cx| tx.poll_ready(cx)).await,
686            Poll::Ready(Status::Ready)
687        );
688
689        // low watermark is capped below the high watermark
690        let (tx, rx) = channel::<()>();
691        rx.set_watermarks(4, 10);
692        for _ in 0..3 {
693            tx.feed_data(Bytes::from_static(b"da"));
694        }
695        assert!(rx.read().await.is_some());
696        assert!(lazy(|cx| tx.poll_ready(cx)).await.is_pending());
697        assert!(rx.read().await.is_some());
698        assert_eq!(
699            lazy(|cx| tx.poll_ready(cx)).await,
700            Poll::Ready(Status::Ready)
701        );
702    }
703
704    /// STATEMENT: A custom low watermark controls how far a full stream must drain.
705    ///
706    /// HOW:
707    /// - Fill an eight-byte stream with a two-byte low watermark.
708    /// - Verify the sender stays pending at four bytes and becomes ready at two.
709    #[ntex::test]
710    async fn custom_low_watermark() {
711        let (tx, rx) = channel::<()>();
712        rx.set_watermarks(8, 2);
713        for _ in 0..4 {
714            tx.feed_data(Bytes::from_static(b"da"));
715        }
716        assert!(rx.read().await.is_some());
717        assert!(rx.read().await.is_some());
718        assert!(lazy(|cx| tx.poll_ready(cx)).await.is_pending());
719        assert!(rx.read().await.is_some());
720        assert_eq!(
721            lazy(|cx| tx.poll_ready(cx)).await,
722            Poll::Ready(Status::Ready)
723        );
724    }
725
726    /// STATEMENT: The deprecated buffer-size setter derives a half-size low watermark.
727    ///
728    /// HOW:
729    /// - Set the maximum buffer size to ten and inspect both resulting watermark values.
730    #[ntex::test]
731    #[allow(deprecated)]
732    async fn deprecated_max_buffer_size() {
733        let (_tx, rx) = channel::<()>();
734        rx.max_buffer_size(10);
735        assert_eq!(rx.inner.high_watermark.get(), 10);
736        assert_eq!(rx.inner.low_watermark.get(), 5);
737    }
738
739    /// STATEMENT: The receiver reaches EOF only when the last sender clone is dropped.
740    ///
741    /// HOW:
742    /// - Clone the sender and check EOF before and after dropping each sender handle.
743    #[ntex::test]
744    async fn test_sender_clone() {
745        let (sender, payload) = channel::<()>();
746        assert!(!payload.is_eof());
747        let sender2 = sender.clone();
748        assert!(!payload.is_eof());
749        drop(sender2);
750        assert!(!payload.is_eof());
751        drop(sender);
752        assert!(payload.is_eof());
753    }
754
755    /// STATEMENT: Sender readiness distinguishes normal operation, EOF, and dropped streams.
756    ///
757    /// HOW:
758    /// - Check readiness before and after setting an error, feeding EOF, and dropping the receiver.
759    #[ntex::test]
760    async fn test_ready_terminal_states() {
761        let (tx, _rx) = channel::<()>();
762        assert_eq!(tx.ready().await, Status::Ready);
763        tx.set_error(());
764        assert_eq!(tx.ready().await, Status::Dropped);
765
766        let (tx, _rx) = channel::<()>();
767        tx.feed_eof();
768        assert_eq!(tx.ready().await, Status::Eof);
769
770        let (tx, rx) = channel::<()>();
771        drop(rx);
772        assert_eq!(tx.ready().await, Status::Dropped);
773    }
774
775    /// STATEMENT: An empty receiver yields its optional initial chunk before terminating.
776    ///
777    /// HOW:
778    /// - Check immediate EOF without a chunk.
779    /// - Receive the supplied chunk through the stream adapter and verify the next read ends.
780    #[ntex::test]
781    async fn test_empty() {
782        let rx = empty::<()>(None);
783        assert!(rx.is_eof());
784        assert!(rx.read().await.is_none());
785
786        let mut rx = empty::<()>(Some(Bytes::from_static(b"data")));
787        assert!(format!("{rx:?}").contains("high_watermark"));
788        assert_eq!(
789            crate::future::stream_recv(&mut rx).await.unwrap().unwrap(),
790            Bytes::from_static(b"data")
791        );
792        assert!(crate::future::stream_recv(&mut rx).await.is_none());
793    }
794
795    /// STATEMENT: A stream returns buffered data before its error, then ends.
796    ///
797    /// HOW:
798    /// - Feed a chunk and set an error.
799    /// - Read the original bytes, the error, and finally EOF in that order.
800    #[ntex::test]
801    async fn test_error() {
802        let (tx, rx) = channel::<&'static str>();
803        tx.feed_data(Bytes::from_static(b"data"));
804        tx.set_error("err");
805
806        // buffered data is returned before the error, then eof
807        assert_eq!(
808            rx.read().await.unwrap().unwrap(),
809            Bytes::from_static(b"data")
810        );
811        assert_eq!(rx.read().await.unwrap().unwrap_err(), "err");
812        assert!(rx.is_eof());
813        assert!(rx.read().await.is_none());
814    }
815
816    /// STATEMENT: EOF and errors are terminal, later data and errors are ignored.
817    ///
818    /// HOW:
819    /// - Feed a chunk and EOF, then feed more data and set an error.
820    /// - Read the first chunk followed by repeated `None`, and check `ready()` still reports `Eof`.
821    /// - Set an error, then feed data and set another error; read the first error, then `None`.
822    #[ntex::test]
823    async fn eof_and_error_are_terminal() {
824        let (tx, rx) = channel::<&'static str>();
825        tx.feed_data(Bytes::from_static(b"data"));
826        tx.feed_eof();
827        tx.feed_data(Bytes::from_static(b"late"));
828        tx.set_error("late");
829        assert_eq!(tx.ready().await, Status::Eof);
830        assert_eq!(
831            rx.read().await.unwrap().unwrap(),
832            Bytes::from_static(b"data")
833        );
834        assert!(rx.read().await.is_none());
835        tx.feed_data(Bytes::from_static(b"later"));
836        assert!(rx.read().await.is_none());
837
838        let (tx, rx) = channel::<&'static str>();
839        tx.set_error("err");
840        tx.feed_data(Bytes::from_static(b"late"));
841        assert_eq!(rx.read().await.unwrap().unwrap_err(), "err");
842        tx.set_error("late");
843        assert!(rx.read().await.is_none());
844    }
845}