Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi-common/src/pipe.rs
1691 views
1
//! Virtual pipes.
2
//!
3
//! These types provide easy implementations of `WasiFile` that mimic much of the behavior of Unix
4
//! pipes. These are particularly helpful for redirecting WASI stdio handles to destinations other
5
//! than OS files.
6
//!
7
//! Some convenience constructors are included for common backing types like `Vec<u8>` and `String`,
8
//! but the virtual pipes can be instantiated with any `Read` or `Write` type.
9
//!
10
use crate::Error;
11
use crate::file::{FdFlags, FileType, WasiFile};
12
use std::any::Any;
13
use std::io::{self, Read, Write};
14
use std::sync::{Arc, RwLock};
15
16
/// A virtual pipe read end.
17
///
18
/// A variety of `From` impls are provided so that common pipe types are easy to create. For example:
19
///
20
/// ```no_run
21
/// use wasi_common::{pipe::ReadPipe, WasiCtx, Table};
22
/// let stdin = ReadPipe::from("hello from stdin!");
23
/// // Brint these instances from elsewhere (e.g. wasi-cap-std-sync):
24
/// let random = todo!();
25
/// let clocks = todo!();
26
/// let sched = todo!();
27
/// let table = Table::new();
28
/// let mut ctx = WasiCtx::new(random, clocks, sched, table);
29
/// ctx.set_stdin(Box::new(stdin.clone()));
30
/// ```
31
#[derive(Debug)]
32
pub struct ReadPipe<R: Read> {
33
reader: Arc<RwLock<R>>,
34
}
35
36
impl<R: Read> Clone for ReadPipe<R> {
37
fn clone(&self) -> Self {
38
Self {
39
reader: self.reader.clone(),
40
}
41
}
42
}
43
44
impl<R: Read> ReadPipe<R> {
45
/// Create a new pipe from a `Read` type.
46
///
47
/// All `Handle` read operations delegate to reading from this underlying reader.
48
pub fn new(r: R) -> Self {
49
Self::from_shared(Arc::new(RwLock::new(r)))
50
}
51
52
/// Create a new pipe from a shareable `Read` type.
53
///
54
/// All `Handle` read operations delegate to reading from this underlying reader.
55
pub fn from_shared(reader: Arc<RwLock<R>>) -> Self {
56
Self { reader }
57
}
58
59
/// Try to convert this `ReadPipe<R>` back to the underlying `R` type.
60
///
61
/// This will fail with `Err(self)` if multiple references to the underlying `R` exist.
62
pub fn try_into_inner(mut self) -> Result<R, Self> {
63
match Arc::try_unwrap(self.reader) {
64
Ok(rc) => Ok(RwLock::into_inner(rc).unwrap()),
65
Err(reader) => {
66
self.reader = reader;
67
Err(self)
68
}
69
}
70
}
71
fn borrow(&self) -> std::sync::RwLockWriteGuard<'_, R> {
72
RwLock::write(&self.reader).unwrap()
73
}
74
}
75
76
impl From<Vec<u8>> for ReadPipe<io::Cursor<Vec<u8>>> {
77
fn from(r: Vec<u8>) -> Self {
78
Self::new(io::Cursor::new(r))
79
}
80
}
81
82
impl From<&[u8]> for ReadPipe<io::Cursor<Vec<u8>>> {
83
fn from(r: &[u8]) -> Self {
84
Self::from(r.to_vec())
85
}
86
}
87
88
impl From<String> for ReadPipe<io::Cursor<String>> {
89
fn from(r: String) -> Self {
90
Self::new(io::Cursor::new(r))
91
}
92
}
93
94
impl From<&str> for ReadPipe<io::Cursor<String>> {
95
fn from(r: &str) -> Self {
96
Self::from(r.to_string())
97
}
98
}
99
100
#[wiggle::async_trait]
101
impl<R: Read + Any + Send + Sync> WasiFile for ReadPipe<R> {
102
fn as_any(&self) -> &dyn Any {
103
self
104
}
105
async fn get_filetype(&self) -> Result<FileType, Error> {
106
Ok(FileType::Pipe)
107
}
108
async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
109
let n = self.borrow().read_vectored(bufs)?;
110
Ok(n.try_into()?)
111
}
112
}
113
114
/// A virtual pipe write end.
115
///
116
/// ```no_run
117
/// use wasi_common::{pipe::WritePipe, WasiCtx, Table};
118
/// let stdout = WritePipe::new_in_memory();
119
/// // Brint these instances from elsewhere (e.g. wasi-cap-std-sync):
120
/// let random = todo!();
121
/// let clocks = todo!();
122
/// let sched = todo!();
123
/// let table = Table::new();
124
/// let mut ctx = WasiCtx::new(random, clocks, sched, table);
125
/// ctx.set_stdout(Box::new(stdout.clone()));
126
/// // use ctx in an instance, then make sure it is dropped:
127
/// drop(ctx);
128
/// let contents: Vec<u8> = stdout.try_into_inner().expect("sole remaining reference to WritePipe").into_inner();
129
/// println!("contents of stdout: {:?}", contents);
130
/// ```
131
#[derive(Debug)]
132
pub struct WritePipe<W: Write> {
133
writer: Arc<RwLock<W>>,
134
}
135
136
impl<W: Write> Clone for WritePipe<W> {
137
fn clone(&self) -> Self {
138
Self {
139
writer: self.writer.clone(),
140
}
141
}
142
}
143
144
impl<W: Write> WritePipe<W> {
145
/// Create a new pipe from a `Write` type.
146
///
147
/// All `Handle` write operations delegate to writing to this underlying writer.
148
pub fn new(w: W) -> Self {
149
Self::from_shared(Arc::new(RwLock::new(w)))
150
}
151
152
/// Create a new pipe from a shareable `Write` type.
153
///
154
/// All `Handle` write operations delegate to writing to this underlying writer.
155
pub fn from_shared(writer: Arc<RwLock<W>>) -> Self {
156
Self { writer }
157
}
158
159
/// Try to convert this `WritePipe<W>` back to the underlying `W` type.
160
///
161
/// This will fail with `Err(self)` if multiple references to the underlying `W` exist.
162
pub fn try_into_inner(mut self) -> Result<W, Self> {
163
match Arc::try_unwrap(self.writer) {
164
Ok(rc) => Ok(RwLock::into_inner(rc).unwrap()),
165
Err(writer) => {
166
self.writer = writer;
167
Err(self)
168
}
169
}
170
}
171
172
fn borrow(&self) -> std::sync::RwLockWriteGuard<'_, W> {
173
RwLock::write(&self.writer).unwrap()
174
}
175
}
176
177
impl WritePipe<io::Cursor<Vec<u8>>> {
178
/// Create a new writable virtual pipe backed by a `Vec<u8>` buffer.
179
pub fn new_in_memory() -> Self {
180
Self::new(io::Cursor::new(vec![]))
181
}
182
}
183
184
#[wiggle::async_trait]
185
impl<W: Write + Any + Send + Sync> WasiFile for WritePipe<W> {
186
fn as_any(&self) -> &dyn Any {
187
self
188
}
189
async fn get_filetype(&self) -> Result<FileType, Error> {
190
Ok(FileType::Pipe)
191
}
192
async fn get_fdflags(&self) -> Result<FdFlags, Error> {
193
Ok(FdFlags::APPEND)
194
}
195
async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
196
let n = self.borrow().write_vectored(bufs)?;
197
Ok(n.try_into()?)
198
}
199
}
200
201