]> git.lizzy.rs Git - rust.git/blob - src/libstd/io/pipe.rs
Deprecate the bytes!() macro.
[rust.git] / src / libstd / io / pipe.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Synchronous, in-memory pipes.
12 //!
13 //! Currently these aren't particularly useful, there only exists bindings
14 //! enough so that pipes can be created to child processes.
15
16 #![allow(missing_doc)]
17
18 use prelude::*;
19
20 use io::{IoResult, IoError};
21 use libc;
22 use os;
23 use owned::Box;
24 use rt::rtio::{RtioPipe, LocalIo};
25
26 /// A synchronous, in-memory pipe.
27 pub struct PipeStream {
28     /// The internal, opaque runtime pipe object.
29     obj: Box<RtioPipe + Send>,
30 }
31
32 pub struct PipePair {
33     pub reader: PipeStream,
34     pub writer: PipeStream,
35 }
36
37 impl PipeStream {
38     /// Consumes a file descriptor to return a pipe stream that will have
39     /// synchronous, but non-blocking reads/writes. This is useful if the file
40     /// descriptor is acquired via means other than the standard methods.
41     ///
42     /// This operation consumes ownership of the file descriptor and it will be
43     /// closed once the object is deallocated.
44     ///
45     /// # Example
46     ///
47     /// ```rust
48     /// # #![allow(unused_must_use)]
49     /// extern crate libc;
50     ///
51     /// use std::io::pipe::PipeStream;
52     ///
53     /// fn main() {
54     ///     let mut pipe = PipeStream::open(libc::STDERR_FILENO);
55     ///     pipe.write(b"Hello, stderr!");
56     /// }
57     /// ```
58     pub fn open(fd: libc::c_int) -> IoResult<PipeStream> {
59         LocalIo::maybe_raise(|io| {
60             io.pipe_open(fd).map(|obj| PipeStream { obj: obj })
61         }).map_err(IoError::from_rtio_error)
62     }
63
64     #[doc(hidden)]
65     pub fn new(inner: Box<RtioPipe + Send>) -> PipeStream {
66         PipeStream { obj: inner }
67     }
68
69     /// Creates a pair of in-memory OS pipes for a unidirectional communication
70     /// stream.
71     ///
72     /// The structure returned contains a reader and writer I/O object. Data
73     /// written to the writer can be read from the reader.
74     ///
75     /// # Errors
76     ///
77     /// This function can fail to succeed if the underlying OS has run out of
78     /// available resources to allocate a new pipe.
79     pub fn pair() -> IoResult<PipePair> {
80         struct Closer { fd: libc::c_int }
81
82         let os::Pipe { reader, writer } = try!(unsafe { os::pipe() });
83         let mut reader = Closer { fd: reader };
84         let mut writer = Closer { fd: writer };
85
86         let io_reader = try!(PipeStream::open(reader.fd));
87         reader.fd = -1;
88         let io_writer = try!(PipeStream::open(writer.fd));
89         writer.fd = -1;
90         return Ok(PipePair { reader: io_reader, writer: io_writer });
91
92         impl Drop for Closer {
93             fn drop(&mut self) {
94                 if self.fd != -1 {
95                     let _ = unsafe { libc::close(self.fd) };
96                 }
97             }
98         }
99     }
100 }
101
102 impl Clone for PipeStream {
103     fn clone(&self) -> PipeStream {
104         PipeStream { obj: self.obj.clone() }
105     }
106 }
107
108 impl Reader for PipeStream {
109     fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
110         self.obj.read(buf).map_err(IoError::from_rtio_error)
111     }
112 }
113
114 impl Writer for PipeStream {
115     fn write(&mut self, buf: &[u8]) -> IoResult<()> {
116         self.obj.write(buf).map_err(IoError::from_rtio_error)
117     }
118 }
119
120 #[cfg(test)]
121 mod test {
122     iotest!(fn partial_read() {
123         use os;
124         use io::pipe::PipeStream;
125
126         let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() };
127         let out = PipeStream::open(writer);
128         let mut input = PipeStream::open(reader);
129         let (tx, rx) = channel();
130         spawn(proc() {
131             let mut out = out;
132             out.write([10]).unwrap();
133             rx.recv(); // don't close the pipe until the other read has finished
134         });
135
136         let mut buf = [0, ..10];
137         input.read(buf).unwrap();
138         tx.send(());
139     })
140 }