conch_runtime_pshaw/env/
fd_opener.rs

1use crate::env::SubEnvironment;
2use crate::io::{FileDesc, Pipe as OsPipe};
3use std::fs::OpenOptions;
4use std::io;
5use std::path::Path;
6use std::sync::Arc;
7
8/// A pipe reader/writer pair created by a `FileDescOpener`.
9#[derive(Debug, PartialEq, Eq, Clone)]
10pub struct Pipe<T> {
11    /// The reader end of the pipe. Anything written to the writer end can be read here.
12    pub reader: T,
13    /// The writer end of the pipe. Anything written here can be read from the reader end.
14    pub writer: T,
15}
16
17/// An interface for opening file descriptors as some handle representation.
18pub trait FileDescOpener {
19    /// A type which represents an opened file descriptor.
20    type OpenedFileHandle;
21
22    /// Open a provided `path` with the specified `OpenOptions`.
23    fn open_path(&mut self, path: &Path, opts: &OpenOptions) -> io::Result<Self::OpenedFileHandle>;
24    /// Create a new `Pipe` pair.
25    fn open_pipe(&mut self) -> io::Result<Pipe<Self::OpenedFileHandle>>;
26}
27
28impl<'a, T: ?Sized + FileDescOpener> FileDescOpener for &'a mut T {
29    type OpenedFileHandle = T::OpenedFileHandle;
30
31    fn open_path(&mut self, path: &Path, opts: &OpenOptions) -> io::Result<Self::OpenedFileHandle> {
32        (**self).open_path(path, opts)
33    }
34
35    fn open_pipe(&mut self) -> io::Result<Pipe<Self::OpenedFileHandle>> {
36        (**self).open_pipe()
37    }
38}
39
40/// A `FileDescOpener` implementation which creates `FileDesc` handles.
41#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
42pub struct FileDescOpenerEnv;
43
44impl FileDescOpenerEnv {
45    /// Create a new `FileDescOpenerEnv` instance.
46    pub fn new() -> Self {
47        Self {}
48    }
49}
50
51impl SubEnvironment for FileDescOpenerEnv {
52    fn sub_env(&self) -> Self {
53        *self
54    }
55}
56
57impl FileDescOpener for FileDescOpenerEnv {
58    type OpenedFileHandle = FileDesc;
59
60    fn open_path(&mut self, path: &Path, opts: &OpenOptions) -> io::Result<Self::OpenedFileHandle> {
61        opts.open(path).map(FileDesc::from)
62    }
63
64    fn open_pipe(&mut self) -> io::Result<Pipe<Self::OpenedFileHandle>> {
65        OsPipe::new().map(|pipe| Pipe {
66            reader: pipe.reader,
67            writer: pipe.writer,
68        })
69    }
70}
71
72/// A `FileDescOpener` implementation which delegates to another implementation,
73/// but wraps any returned handles with in an `Arc`.
74#[derive(Default, Debug, Clone, PartialEq, Eq)]
75pub struct ArcFileDescOpenerEnv<O> {
76    opener: O,
77}
78
79impl<O> ArcFileDescOpenerEnv<O> {
80    /// Create a new wrapper instance around some other `FileDescOpener` implementation.
81    pub fn new(opener: O) -> Self {
82        Self { opener }
83    }
84}
85
86impl<O: SubEnvironment> SubEnvironment for ArcFileDescOpenerEnv<O> {
87    fn sub_env(&self) -> Self {
88        Self {
89            opener: self.opener.sub_env(),
90        }
91    }
92}
93
94impl<O: FileDescOpener> FileDescOpener for ArcFileDescOpenerEnv<O> {
95    type OpenedFileHandle = Arc<O::OpenedFileHandle>;
96
97    fn open_path(&mut self, path: &Path, opts: &OpenOptions) -> io::Result<Self::OpenedFileHandle> {
98        self.opener.open_path(path, opts).map(Arc::new)
99    }
100
101    fn open_pipe(&mut self) -> io::Result<Pipe<Self::OpenedFileHandle>> {
102        self.opener.open_pipe().map(|pipe| Pipe {
103            reader: Arc::new(pipe.reader),
104            writer: Arc::new(pipe.writer),
105        })
106    }
107}