Struct duct::ReaderHandle [−][src]
An incremental reader created with the
Expression::reader
method.
When this reader reaches EOF, it automatically calls
wait
on the inner handle. If the child
returns a non-zero exit status, the read at EOF will return an error,
unless you use unchecked
.
If the reader is dropped before reaching EOF, it calls
kill
in its destructor.
Both ReaderHandle
and &ReaderHandle
implement
std::io::Read
. That
makes it possible for one thread to
kill
the ReaderHandle
while
another thread is reading it. That can be useful for effectively canceling
the read and unblocking the reader thread. However, note that killed child
processes return a non-zero exit status, which is an error for the reader
by default, unless you use
unchecked
.
Example
use duct::cmd; use duct::ReaderHandle; use std::sync::Arc; use std::io::prelude::*; // This child process prints a single byte and then sleeps. // // CAUTION: Using Bash for this example would probably hang, because Bash // would spawn a `sleep` grandchild processes, and that grandchild wouldn't // receive the kill signal. let python_child = "\ import sys import time print() sys.stdout.flush() time.sleep(24 * 60 * 60) "; let reader: ReaderHandle = cmd!("python3", "-c", python_child) .unchecked() .reader()?; // Spawn two threads that both try to read the single byte. Whichever one // succeeds then calls kill() to unblock the other. let arc_reader: Arc<ReaderHandle> = Arc::new(reader); let mut threads = Vec::new(); for _ in 0..2 { let arc_reader = arc_reader.clone(); threads.push(std::thread::spawn(move || -> std::io::Result<()> { let mut single_byte = [0u8]; (&*arc_reader).read(&mut single_byte)?; arc_reader.kill()?; Ok(()) })); } // Join both threads. Because of the kill() above, both threads will exit // quickly. for thread in threads { thread.join().unwrap()?; }
Implementations
impl ReaderHandle
[src]
pub fn try_wait(&self) -> Result<Option<&Output>>
[src]
Check whether the underlying expression is finished. This is equivalent
to Handle::try_wait
. If the
ReaderHandle
has indicated EOF successfully, then it's guaranteed
that this method will return Ok(Some(_))
.
Note that the
stdout
field of the returned
Output
will always be empty, because the ReaderHandle
itself owns the
child's stdout pipe.
pub fn kill(&self) -> Result<()>
[src]
Kill the underlying expression and await all the child processes.
Any errors that would normally result from a non-zero exit status are
ignored during this wait, as with
Handle::kill
.
Note that as with
std::process::Child::kill
,
this does not kill any grandchild processes that the children have
spawned on their own. It only kills the child processes that Duct
spawned itself. This is especially relevant for ReaderHandle
,
because if you're using kill
to unblock another thread that's
reading, an unkilled grandchild process might keep the child's stdout
pipe open and keep your reader thread blocked. For that use case, you
need to ensure that any grandchild processes your child might spawn are
going to be short-lived. See
gotchas.md
for an extensive discussion of these issues.
pub fn pids(&self) -> Vec<u32>
[src]
Return a Vec<u32>
containing the PIDs of all of the child processes.
The PIDs are given in pipeline order, from left to right.
Trait Implementations
impl Debug for ReaderHandle
[src]
impl Drop for ReaderHandle
[src]
impl<'a> Read for &'a ReaderHandle
[src]
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
[src]
Note that if you don't use
unchecked
, and the child
returns a non-zero exit status, the final call to read
will return an
error, just as run
would.
pub fn read_vectored(
&mut self,
bufs: &mut [IoSliceMut<'_>]
) -> Result<usize, Error>
1.36.0[src]
&mut self,
bufs: &mut [IoSliceMut<'_>]
) -> Result<usize, Error>
pub fn is_read_vectored(&self) -> bool
[src]
pub unsafe fn initializer(&self) -> Initializer
[src]
pub fn read_to_end(&mut self, buf: &mut Vec<u8, Global>) -> Result<usize, Error>
1.0.0[src]
pub fn read_to_string(&mut self, buf: &mut String) -> Result<usize, Error>
1.0.0[src]
pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error>
1.6.0[src]
pub fn by_ref(&mut self) -> &mut Self
1.0.0[src]
pub fn bytes(self) -> Bytes<Self>
1.0.0[src]
pub fn chain<R>(self, next: R) -> Chain<Self, R> where
R: Read,
1.0.0[src]
R: Read,
pub fn take(self, limit: u64) -> Take<Self>
1.0.0[src]
impl Read for ReaderHandle
[src]
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
[src]
Note that if you don't use
unchecked
, and the child
returns a non-zero exit status, the final call to read
will return an
error, just as run
would.
pub fn read_vectored(
&mut self,
bufs: &mut [IoSliceMut<'_>]
) -> Result<usize, Error>
1.36.0[src]
&mut self,
bufs: &mut [IoSliceMut<'_>]
) -> Result<usize, Error>
pub fn is_read_vectored(&self) -> bool
[src]
pub unsafe fn initializer(&self) -> Initializer
[src]
pub fn read_to_end(&mut self, buf: &mut Vec<u8, Global>) -> Result<usize, Error>
1.0.0[src]
pub fn read_to_string(&mut self, buf: &mut String) -> Result<usize, Error>
1.0.0[src]
pub fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Error>
1.6.0[src]
pub fn by_ref(&mut self) -> &mut Self
1.0.0[src]
pub fn bytes(self) -> Bytes<Self>
1.0.0[src]
pub fn chain<R>(self, next: R) -> Chain<Self, R> where
R: Read,
1.0.0[src]
R: Read,
pub fn take(self, limit: u64) -> Take<Self>
1.0.0[src]
Auto Trait Implementations
impl !RefUnwindSafe for ReaderHandle
[src]
impl Send for ReaderHandle
[src]
impl Sync for ReaderHandle
[src]
impl Unpin for ReaderHandle
[src]
impl !UnwindSafe for ReaderHandle
[src]
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,