conch_runtime_pshaw/spawn/
builtin.rs1use crate::env::{AsyncIoEnvironment, FileDescEnvironment};
4use crate::{ExitStatus, Fd, EXIT_ERROR, EXIT_SUCCESS, STDERR_FILENO, STDOUT_FILENO};
5use futures_util::future::BoxFuture;
6use std::fmt;
7use void::Void;
8
9macro_rules! format_err {
10 ($builtin_name:expr, $e:expr) => {
11 format!("{}: {}\n", $builtin_name, $e).into_bytes()
12 };
13}
14
15macro_rules! try_and_report {
16 ($builtin_name:expr, $result:expr, $env:ident) => {
17 match $result {
18 Ok(val) => val,
19 Err(e) => {
20 return $crate::spawn::builtin::report_err($builtin_name, $env, e).await;
21 }
22 }
23 };
24}
25
26pub(crate) async fn report_err<E, ERR>(
27 builtin_name: &str,
28 env: &mut E,
29 err: ERR,
30) -> BoxFuture<'static, ExitStatus>
31where
32 E: ?Sized + AsyncIoEnvironment + FileDescEnvironment,
33 E::FileHandle: Clone,
34 E::IoHandle: From<E::FileHandle>,
35 ERR: fmt::Display,
36{
37 generate_and_write_bytes_to_fd_if_present(
38 builtin_name,
39 env,
40 STDERR_FILENO,
41 EXIT_ERROR,
42 |_| -> Result<_, Void> { Ok(format_err!(builtin_name, err)) },
43 )
44 .await
45}
46
47mod cd;
48mod echo;
49mod pwd;
50mod shift;
51mod trivial;
52
53pub use self::cd::cd;
54pub use self::echo::echo;
55pub use self::pwd::pwd;
56pub use self::shift::shift;
57pub use self::trivial::{colon, false_cmd, true_cmd};
58
59pub(crate) async fn generate_and_print_output<E, F, ERR>(
60 builtin_name: &str,
61 env: &mut E,
62 generate_bytes: F,
63) -> BoxFuture<'static, ExitStatus>
64where
65 E: ?Sized + AsyncIoEnvironment + FileDescEnvironment,
66 E::FileHandle: Clone,
67 E::IoHandle: From<E::FileHandle>,
68 for<'a> F: FnOnce(&'a E) -> Result<Vec<u8>, ERR>,
69 ERR: fmt::Display,
70{
71 generate_and_write_bytes_to_fd_if_present(
72 builtin_name,
73 env,
74 STDOUT_FILENO,
75 EXIT_SUCCESS,
76 generate_bytes,
77 )
78 .await
79}
80
81pub(crate) async fn generate_and_write_bytes_to_fd_if_present<E, F, ERR>(
82 builtin_name: &str,
83 env: &mut E,
84 fd: Fd,
85 exit_status_on_success: ExitStatus,
86 generate_bytes: F,
87) -> BoxFuture<'static, ExitStatus>
88where
89 E: ?Sized + AsyncIoEnvironment + FileDescEnvironment,
90 E::FileHandle: Clone,
91 E::IoHandle: From<E::FileHandle>,
92 for<'a> F: FnOnce(&'a E) -> Result<Vec<u8>, ERR>,
93 ERR: fmt::Display,
94{
95 macro_rules! get_fdes {
96 ($fd:expr, $fallback_status:expr) => {{
97 match get_fdes_or_status(env, fd, exit_status_on_success) {
98 Ok(fdes) => fdes,
99 Err(status) => return Box::pin(async move { status }),
100 }
101 }};
102 }
103
104 let fdes = get_fdes!(fd, exit_status_on_success);
106
107 let bytes_result = match generate_bytes(env) {
108 Ok(bytes) => Ok(bytes),
109 Err(e) if fd == STDERR_FILENO => Ok(format_err!(builtin_name, e)),
112 Err(e) => Err(e),
113 };
114
115 let err_bytes = match bytes_result {
116 Ok(bytes) => match env.write_all(fdes, bytes.into()).await {
117 Ok(()) => return Box::pin(async move { exit_status_on_success }),
118 Err(e) => format_err!(builtin_name, e),
119 },
120 Err(e) => format_err!(builtin_name, e),
121 };
122
123 let stderr_fdes = get_fdes!(fd, EXIT_ERROR);
125
126 let future = env.write_all(stderr_fdes, err_bytes.into());
127
128 Box::pin(async move {
129 let _ = future.await;
131 EXIT_ERROR
132 })
133}
134
135fn get_fdes_or_status<E>(
136 env: &E,
137 fd: Fd,
138 fallback_status: ExitStatus,
139) -> Result<E::IoHandle, ExitStatus>
140where
141 E: ?Sized + AsyncIoEnvironment + FileDescEnvironment,
142 E::FileHandle: Clone,
143 E::IoHandle: From<E::FileHandle>,
144{
145 env.file_desc(fd)
146 .map(|(fdes, _)| E::IoHandle::from(fdes.clone()))
147 .ok_or(fallback_status)
148}