conch_runtime_pshaw/
io.rs

1//! Defines interfaces and methods for doing OS agnostic file IO operations.
2
3mod file_desc_wrapper;
4mod permissions;
5mod pipe;
6
7use crate::sys;
8use crate::IntoInner;
9use std::io::{Read, Result, Seek, SeekFrom, Write};
10use std::process::Stdio;
11
12pub use self::file_desc_wrapper::FileDescWrapper;
13pub use self::permissions::Permissions;
14pub use self::pipe::Pipe;
15pub use crate::sys::io::getpid;
16
17/// A wrapper around an owned OS file primitive. The wrapper
18/// allows reading from or writing to the OS file primitive, and
19/// will close it once it goes out of scope.
20#[derive(Debug, PartialEq, Eq)]
21pub struct FileDesc(sys::io::RawIo);
22
23impl FileDesc {
24    /// Constructs an `FileDesc` from the specified raw file descriptor.
25    ///
26    /// # Safety
27    ///
28    /// This function **consumes ownership** of the specified file
29    /// descriptor. The returned object will take responsibility for closing
30    /// it when the object goes out of scope.
31    ///
32    /// This function is also unsafe as the primitives currently returned
33    /// have the contract that they are the sole owner of the file
34    /// descriptor they are wrapping. Usage of this function could
35    /// accidentally allow violating this contract which can cause memory
36    /// unsafety in code that relies on it being true.
37    #[cfg(unix)]
38    pub unsafe fn new(fd: ::std::os::unix::io::RawFd) -> Self {
39        Self::from_inner(sys::io::RawIo::new(fd))
40    }
41
42    /// Constructs an `FileDesc` from the specified raw handle.
43    ///
44    /// # Safety
45    ///
46    /// This function will **consume ownership** of the handle given,
47    /// passing responsibility for closing the handle to the returned
48    /// object.
49    ///
50    /// This function is also unsafe as the primitives currently returned
51    /// have the contract that they are the sole owner of the file
52    /// descriptor they are wrapping. Usage of this function could
53    /// accidentally allow violating this contract which can cause memory
54    /// unsafety in code that relies on it being true.
55    #[cfg(windows)]
56    pub unsafe fn new(handle: ::std::os::windows::io::RawHandle) -> Self {
57        Self::from_inner(sys::io::RawIo::new(handle))
58    }
59
60    /// Duplicates the underlying OS file primitive.
61    pub fn duplicate(&self) -> Result<Self> {
62        Ok(Self::from_inner(self.inner().duplicate()?))
63    }
64
65    /// Sets the `O_NONBLOCK` flag on the descriptor to the desired state.
66    ///
67    /// Specifiying `true` will set the file descriptor in non-blocking mode,
68    /// while specifying `false` will set it to blocking mode.
69    #[cfg(unix)]
70    pub fn set_nonblock(&mut self, set: bool) -> Result<()> {
71        self.inner_mut().set_nonblock(set)
72    }
73
74    fn read(&self, buf: &mut [u8]) -> Result<usize> {
75        self.inner().read_inner(buf)
76    }
77
78    fn write(&self, buf: &[u8]) -> Result<usize> {
79        self.inner().write_inner(buf)
80    }
81
82    fn flush(&self) -> Result<()> {
83        self.inner().flush_inner()
84    }
85
86    fn seek(&self, pos: SeekFrom) -> Result<u64> {
87        self.inner().seek(pos)
88    }
89}
90
91impl IntoInner for FileDesc {
92    type Inner = sys::io::RawIo;
93
94    fn inner(&self) -> &Self::Inner {
95        &self.0
96    }
97
98    fn inner_mut(&mut self) -> &mut Self::Inner {
99        &mut self.0
100    }
101
102    fn into_inner(self) -> Self::Inner {
103        self.0
104    }
105
106    fn from_inner(inner: Self::Inner) -> Self {
107        FileDesc(inner)
108    }
109}
110
111impl Into<Stdio> for FileDesc {
112    fn into(self) -> Stdio {
113        self.into_inner().into()
114    }
115}
116
117impl Read for FileDesc {
118    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
119        FileDesc::read(self, buf)
120    }
121}
122
123impl<'a> Read for &'a FileDesc {
124    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
125        FileDesc::read(self, buf)
126    }
127}
128
129impl Write for FileDesc {
130    fn write(&mut self, buf: &[u8]) -> Result<usize> {
131        FileDesc::write(self, buf)
132    }
133
134    fn flush(&mut self) -> Result<()> {
135        FileDesc::flush(self)
136    }
137}
138
139impl<'a> Write for &'a FileDesc {
140    fn write(&mut self, buf: &[u8]) -> Result<usize> {
141        FileDesc::write(self, buf)
142    }
143
144    fn flush(&mut self) -> Result<()> {
145        FileDesc::flush(self)
146    }
147}
148
149impl Seek for FileDesc {
150    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
151        FileDesc::seek(self, pos)
152    }
153}
154
155impl<'a> Seek for &'a FileDesc {
156    fn seek(&mut self, pos: SeekFrom) -> Result<u64> {
157        FileDesc::seek(self, pos)
158    }
159}
160
161/// Duplicates handles for (stdin, stdout, stderr) and returns them in that order.
162pub(crate) fn dup_stdio() -> Result<(FileDesc, FileDesc, FileDesc)> {
163    let (stdin, stdout, stderr) = sys::io::dup_stdio()?;
164    Ok((
165        FileDesc::from_inner(stdin),
166        FileDesc::from_inner(stdout),
167        FileDesc::from_inner(stderr),
168    ))
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn ensure_file_desc_is_send_and_sync() {
177        fn send_and_sync<T: Send + Sync>() {}
178
179        send_and_sync::<FileDesc>();
180    }
181}