nu_protocol/engine/
stack_out_dest.rs1use crate::{OutDest, engine::Stack};
2use std::{
3 fs::File,
4 mem,
5 ops::{Deref, DerefMut},
6 sync::Arc,
7};
8
9#[derive(Debug, Clone)]
10pub enum Redirection {
11 Pipe(OutDest),
17 File(Arc<File>),
22}
23
24impl Redirection {
25 pub fn file(file: File) -> Self {
26 Self::File(Arc::new(file))
27 }
28}
29
30#[derive(Debug, Clone)]
31pub(crate) struct StackOutDest {
32 pub pipe_stdout: Option<OutDest>,
34 pub pipe_stderr: Option<OutDest>,
36 pub stdout: OutDest,
40 pub stderr: OutDest,
44 pub parent_stdout: Option<OutDest>,
52 pub parent_stderr: Option<OutDest>,
60}
61
62impl StackOutDest {
63 pub(crate) fn new() -> Self {
64 Self {
65 pipe_stdout: Some(OutDest::Print),
66 pipe_stderr: Some(OutDest::Print),
67 stdout: OutDest::Inherit,
68 stderr: OutDest::Inherit,
69 parent_stdout: None,
70 parent_stderr: None,
71 }
72 }
73
74 pub(crate) fn stdout(&self) -> &OutDest {
80 self.pipe_stdout.as_ref().unwrap_or(&self.stdout)
81 }
82
83 pub(crate) fn stderr(&self) -> &OutDest {
89 self.pipe_stderr.as_ref().unwrap_or(&self.stderr)
90 }
91
92 fn push_stdout(&mut self, stdout: OutDest) -> Option<OutDest> {
93 let stdout = mem::replace(&mut self.stdout, stdout);
94 self.parent_stdout.replace(stdout)
95 }
96
97 fn push_stderr(&mut self, stderr: OutDest) -> Option<OutDest> {
98 let stderr = mem::replace(&mut self.stderr, stderr);
99 self.parent_stderr.replace(stderr)
100 }
101}
102
103pub struct StackIoGuard<'a> {
104 stack: &'a mut Stack,
105 old_pipe_stdout: Option<OutDest>,
106 old_pipe_stderr: Option<OutDest>,
107 old_parent_stdout: Option<OutDest>,
108 old_parent_stderr: Option<OutDest>,
109}
110
111impl<'a> StackIoGuard<'a> {
112 pub(crate) fn new(
113 stack: &'a mut Stack,
114 stdout: Option<Redirection>,
115 stderr: Option<Redirection>,
116 ) -> Self {
117 let out_dest = &mut stack.out_dest;
118
119 let (old_pipe_stdout, old_parent_stdout) = match stdout {
120 Some(Redirection::Pipe(stdout)) => {
121 let old = out_dest.pipe_stdout.replace(stdout);
122 (old, out_dest.parent_stdout.take())
123 }
124 Some(Redirection::File(file)) => {
125 let file = OutDest::from(file);
126 (
127 out_dest.pipe_stdout.replace(file.clone()),
128 out_dest.push_stdout(file),
129 )
130 }
131 None => (out_dest.pipe_stdout.take(), out_dest.parent_stdout.take()),
132 };
133
134 let (old_pipe_stderr, old_parent_stderr) = match stderr {
135 Some(Redirection::Pipe(stderr)) => {
136 let old = out_dest.pipe_stderr.replace(stderr);
137 (old, out_dest.parent_stderr.take())
138 }
139 Some(Redirection::File(file)) => (
140 out_dest.pipe_stderr.take(),
141 out_dest.push_stderr(file.into()),
142 ),
143 None => (out_dest.pipe_stderr.take(), out_dest.parent_stderr.take()),
144 };
145
146 StackIoGuard {
147 stack,
148 old_pipe_stdout,
149 old_parent_stdout,
150 old_pipe_stderr,
151 old_parent_stderr,
152 }
153 }
154}
155
156impl Deref for StackIoGuard<'_> {
157 type Target = Stack;
158
159 fn deref(&self) -> &Self::Target {
160 self.stack
161 }
162}
163
164impl DerefMut for StackIoGuard<'_> {
165 fn deref_mut(&mut self) -> &mut Self::Target {
166 self.stack
167 }
168}
169
170impl Drop for StackIoGuard<'_> {
171 fn drop(&mut self) {
172 self.out_dest.pipe_stdout = self.old_pipe_stdout.take();
173 self.out_dest.pipe_stderr = self.old_pipe_stderr.take();
174
175 let old_stdout = self.old_parent_stdout.take();
176 if let Some(stdout) = mem::replace(&mut self.out_dest.parent_stdout, old_stdout) {
177 self.out_dest.stdout = stdout;
178 }
179
180 let old_stderr = self.old_parent_stderr.take();
181 if let Some(stderr) = mem::replace(&mut self.out_dest.parent_stderr, old_stderr) {
182 self.out_dest.stderr = stderr;
183 }
184 }
185}
186
187pub struct StackCollectValueGuard<'a> {
188 stack: &'a mut Stack,
189 old_pipe_stdout: Option<OutDest>,
190 old_pipe_stderr: Option<OutDest>,
191}
192
193impl<'a> StackCollectValueGuard<'a> {
194 pub(crate) fn new(stack: &'a mut Stack) -> Self {
195 let old_pipe_stdout = stack.out_dest.pipe_stdout.replace(OutDest::Value);
196 let old_pipe_stderr = stack.out_dest.pipe_stderr.take();
197 Self {
198 stack,
199 old_pipe_stdout,
200 old_pipe_stderr,
201 }
202 }
203}
204
205impl Deref for StackCollectValueGuard<'_> {
206 type Target = Stack;
207
208 fn deref(&self) -> &Self::Target {
209 &*self.stack
210 }
211}
212
213impl DerefMut for StackCollectValueGuard<'_> {
214 fn deref_mut(&mut self) -> &mut Self::Target {
215 self.stack
216 }
217}
218
219impl Drop for StackCollectValueGuard<'_> {
220 fn drop(&mut self) {
221 self.out_dest.pipe_stdout = self.old_pipe_stdout.take();
222 self.out_dest.pipe_stderr = self.old_pipe_stderr.take();
223 }
224}
225
226pub struct StackCallArgGuard<'a> {
227 stack: &'a mut Stack,
228 old_pipe_stdout: Option<OutDest>,
229 old_pipe_stderr: Option<OutDest>,
230 old_stdout: Option<OutDest>,
231 old_stderr: Option<OutDest>,
232}
233
234impl<'a> StackCallArgGuard<'a> {
235 pub(crate) fn new(stack: &'a mut Stack) -> Self {
236 let old_pipe_stdout = stack.out_dest.pipe_stdout.replace(OutDest::Value);
237 let old_pipe_stderr = stack.out_dest.pipe_stderr.take();
238
239 let old_stdout = stack
240 .out_dest
241 .parent_stdout
242 .take()
243 .map(|stdout| mem::replace(&mut stack.out_dest.stdout, stdout));
244
245 let old_stderr = stack
246 .out_dest
247 .parent_stderr
248 .take()
249 .map(|stderr| mem::replace(&mut stack.out_dest.stderr, stderr));
250
251 Self {
252 stack,
253 old_pipe_stdout,
254 old_pipe_stderr,
255 old_stdout,
256 old_stderr,
257 }
258 }
259}
260
261impl Deref for StackCallArgGuard<'_> {
262 type Target = Stack;
263
264 fn deref(&self) -> &Self::Target {
265 &*self.stack
266 }
267}
268
269impl DerefMut for StackCallArgGuard<'_> {
270 fn deref_mut(&mut self) -> &mut Self::Target {
271 self.stack
272 }
273}
274
275impl Drop for StackCallArgGuard<'_> {
276 fn drop(&mut self) {
277 self.out_dest.pipe_stdout = self.old_pipe_stdout.take();
278 self.out_dest.pipe_stderr = self.old_pipe_stderr.take();
279 if let Some(stdout) = self.old_stdout.take() {
280 self.out_dest.push_stdout(stdout);
281 }
282 if let Some(stderr) = self.old_stderr.take() {
283 self.out_dest.push_stderr(stderr);
284 }
285 }
286}