Skip to main content

tokio_process_tools/output_stream/backend/discard/
mod.rs

1//! Discard backend: a zero-cost stream marker for stdio configured as `Stdio::null()`.
2//!
3//! A [`DiscardedOutputStream`] holds no buffers and spawns no reader task. The OS routes the
4//! child's stdout or stderr to `/dev/null` (or its platform equivalent), and the parent never
5//! sees the bytes. The type still implements [`Subscribable`] and [`Consumable`] for API
6//! uniformity (so generic helpers can target any backend), but its subscription emits a single
7//! [`StreamEvent::Eof`] and then `None`: any visitor consumed against a discarded stream
8//! observes zero chunks and terminates immediately.
9
10use crate::output_stream::num_bytes::NumBytes;
11use crate::output_stream::{Consumable, OutputStream};
12use crate::{StreamEvent, Subscribable, Subscription};
13use std::convert::Infallible;
14
15/// Marker stream for a stdio slot configured with [`std::process::Stdio::null()`].
16///
17/// The OS discards the child's writes; no pipe is allocated and no reader task runs. The
18/// `read_chunk_size` and `max_buffered_chunks` accessors are present because [`OutputStream`]
19/// requires them, but they have no operational meaning for this variant and return zero.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct DiscardedOutputStream {
22    name: &'static str,
23}
24
25impl DiscardedOutputStream {
26    pub(crate) fn new(name: &'static str) -> Self {
27        Self { name }
28    }
29}
30
31#[doc(hidden)]
32pub struct ImmediateEof {
33    eof_emitted: bool,
34}
35
36impl ImmediateEof {
37    fn new() -> Self {
38        Self { eof_emitted: false }
39    }
40}
41
42impl Subscription for ImmediateEof {
43    fn next_event(&mut self) -> impl Future<Output = Option<StreamEvent>> + Send + '_ {
44        let eof_emitted = self.eof_emitted;
45        self.eof_emitted = true;
46        async move {
47            if eof_emitted {
48                None
49            } else {
50                Some(StreamEvent::Eof)
51            }
52        }
53    }
54}
55
56impl Subscribable for DiscardedOutputStream {
57    type Subscription = ImmediateEof;
58    type SubscribeError = Infallible;
59
60    fn try_subscribe(&self) -> Result<Self::Subscription, Self::SubscribeError> {
61        Ok(Self::Subscription::new())
62    }
63}
64
65impl Consumable for DiscardedOutputStream {
66    type Error = Infallible;
67}
68
69impl OutputStream for DiscardedOutputStream {
70    fn read_chunk_size(&self) -> NumBytes {
71        NumBytes::zero()
72    }
73
74    fn max_buffered_chunks(&self) -> usize {
75        0
76    }
77
78    fn name(&self) -> &'static str {
79        self.name
80    }
81}