rust_process_interface_library/
lib.rs1use std::collections::HashMap;
18use std::env;
19use std::ffi::CString;
20
21pub struct Output {
25 pub status: i32,
27 pub stdout: Vec<u8>,
29 pub stderr: Vec<u8>,
31}
32
33pub mod ssvm_process {
34 use std::os::raw::c_char;
35 #[link(wasm_import_module = "ssvm_process")]
36 extern "C" {
37 pub fn ssvm_process_set_prog_name(name: *const c_char, len: u32);
38 pub fn ssvm_process_add_arg(arg: *const c_char, len: u32);
39 pub fn ssvm_process_add_env(
40 env: *const c_char,
41 env_len: u32,
42 val: *const c_char,
43 val_len: u32,
44 );
45 pub fn ssvm_process_add_stdin(buf: *const c_char, len: u32);
46 pub fn ssvm_process_set_timeout(time_ms: u32);
47 pub fn ssvm_process_run() -> i32;
48 pub fn ssvm_process_get_exit_code() -> i32;
49 pub fn ssvm_process_get_stdout_len() -> u32;
50 pub fn ssvm_process_get_stdout(buf: *mut u8);
51 pub fn ssvm_process_get_stderr_len() -> u32;
52 pub fn ssvm_process_get_stderr(buf: *mut u8);
53 }
54}
55
56pub struct Command {
57 pub name: String,
59 pub args_list: Vec<String>,
61 pub envp_map: HashMap<String, String>,
63 pub timeout_val: u32,
65 pub stdin_str: Vec<u8>,
67}
68
69impl Command {
70 pub fn new<S: AsRef<str>>(prog: S) -> Command {
71 let mut envp: HashMap<String, String> = HashMap::new();
72 for (key, value) in env::vars() {
73 envp.insert(key, value);
74 }
75 Command {
76 name: String::from(prog.as_ref()),
77 args_list: vec![],
78 envp_map: envp,
79 timeout_val: 10000,
80 stdin_str: vec![],
81 }
82 }
83
84 pub fn arg<S: AsRef<str>>(&mut self, arg: S) -> &mut Command {
85 self.args_list.push(String::from(arg.as_ref()));
86 self
87 }
88
89 pub fn args<I, S>(&mut self, args: I) -> &mut Command
90 where
91 I: IntoIterator<Item = S>,
92 S: AsRef<str>,
93 {
94 for arg in args {
95 self.arg(arg.as_ref());
96 }
97 self
98 }
99
100 pub fn args_clear(&mut self) -> &mut Command {
101 self.args_list.clear();
102 self
103 }
104
105 pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
106 where
107 K: AsRef<str>,
108 V: AsRef<str>,
109 {
110 self.envp_map
111 .insert(String::from(key.as_ref()), String::from(val.as_ref()));
112 self
113 }
114
115 pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Command
116 where
117 I: IntoIterator<Item = (K, V)>,
118 K: AsRef<str>,
119 V: AsRef<str>,
120 {
121 for (ref key, ref val) in vars {
122 self.env(key.as_ref(), val.as_ref());
123 }
124 self
125 }
126
127 pub fn stdin<S: AsRef<str>>(&mut self, buf: S) -> &mut Command {
128 self.stdin_str
129 .extend(CString::new(buf.as_ref()).expect("").as_bytes());
130 self
131 }
132
133 pub fn stdin_u8(&mut self, buf: u8) -> &mut Command {
134 self.stdin_str.push(buf);
135 self
136 }
137
138 pub fn stdin_u8vec<S: AsRef<[u8]>>(&mut self, buf: S) -> &mut Command {
139 self.stdin_str.extend(buf.as_ref());
140 self
141 }
142
143 pub fn timeout(&mut self, time: u32) -> &mut Command {
144 self.timeout_val = time;
145 self
146 }
147
148 pub fn output(&mut self) -> Output {
149 unsafe {
150 let cprog = CString::new((&self.name).as_bytes()).expect("");
152 ssvm_process::ssvm_process_set_prog_name(cprog.as_ptr(), cprog.as_bytes().len() as u32);
153
154 for arg in &self.args_list {
156 let carg = CString::new(arg.as_bytes()).expect("");
157 ssvm_process::ssvm_process_add_arg(carg.as_ptr(), carg.as_bytes().len() as u32);
158 }
159
160 for (key, val) in &self.envp_map {
162 let ckey = CString::new(key.as_bytes()).expect("");
163 let cval = CString::new(val.as_bytes()).expect("");
164 ssvm_process::ssvm_process_add_env(
165 ckey.as_ptr(),
166 ckey.as_bytes().len() as u32,
167 cval.as_ptr(),
168 cval.as_bytes().len() as u32,
169 );
170 }
171
172 ssvm_process::ssvm_process_set_timeout(self.timeout_val);
174
175 ssvm_process::ssvm_process_add_stdin(
177 self.stdin_str.as_ptr() as *const i8,
178 self.stdin_str.len() as u32,
179 );
180
181 let exit_code = ssvm_process::ssvm_process_run();
183
184 let stdout_len = ssvm_process::ssvm_process_get_stdout_len();
186 let stderr_len = ssvm_process::ssvm_process_get_stderr_len();
187 let mut stdout_vec: Vec<u8> = vec![0; stdout_len as usize];
188 let mut stderr_vec: Vec<u8> = vec![0; stderr_len as usize];
189 let stdout_ptr = stdout_vec.as_mut_ptr();
190 let stderr_ptr = stderr_vec.as_mut_ptr();
191 ssvm_process::ssvm_process_get_stdout(stdout_ptr);
192 ssvm_process::ssvm_process_get_stderr(stderr_ptr);
193
194 Output {
195 status: exit_code,
196 stdout: stdout_vec,
197 stderr: stderr_vec,
198 }
199 }
200 }
201}
202
203#[cfg(test)]
209mod tests {
210 use super::Command;
211 #[test]
212 fn test_arg() {
213 let mut cmd = Command::new("rusttest");
214 cmd.arg("val1").arg("val2");
215 assert_eq!(cmd.args_list[0], "val1");
216 assert_eq!(cmd.args_list[1], "val2");
217 }
218 #[test]
219 fn test_args() {
220 let mut cmd = Command::new("rusttest");
221 cmd.args(&["val1", "val2"]);
222 assert_eq!(cmd.args_list[0], "val1");
223 assert_eq!(cmd.args_list[1], "val2");
224 }
225 #[test]
226 fn test_arg_args() {
227 let mut cmd = Command::new("rusttest");
228 cmd.arg("val1").arg("val2").args(&["val3", "val4"]);
229 assert_eq!(cmd.args_list[0], "val1");
230 assert_eq!(cmd.args_list[1], "val2");
231 assert_eq!(cmd.args_list[2], "val3");
232 assert_eq!(cmd.args_list[3], "val4");
233 }
234 #[test]
235 fn test_args_clear() {
236 let mut cmd = Command::new("rusttest");
237 cmd.arg("val1").arg("val2").args(&["val3", "val4"]);
238 cmd.args_clear();
239 assert_eq!(cmd.args_list.len(), 0);
240 }
241 #[test]
242 fn test_env() {
243 let mut cmd = Command::new("rusttest");
244 cmd.env("ENV1", "VALUE1").env("ENV2", "VALUE2");
245 assert_eq!(cmd.envp_map["ENV1"], "VALUE1");
246 assert_eq!(cmd.envp_map["ENV2"], "VALUE2");
247 }
248 #[test]
249 fn test_envs() {
250 use std::collections::HashMap;
251 let mut cmd = Command::new("rusttest");
252 let mut hash: HashMap<String, String> = HashMap::new();
253 hash.insert(String::from("ENV1"), String::from("VALUE1"));
254 hash.insert(String::from("ENV2"), String::from("VALUE2"));
255 cmd.envs(hash);
256 assert_eq!(cmd.envp_map["ENV1"], "VALUE1");
257 assert_eq!(cmd.envp_map["ENV2"], "VALUE2");
258 }
259 #[test]
260 fn test_env_envs() {
261 use std::collections::HashMap;
262 let mut cmd = Command::new("rusttest");
263 let mut hash: HashMap<String, String> = HashMap::new();
264 hash.insert(String::from("ENV1"), String::from("VALUE1"));
265 hash.insert(String::from("ENV2"), String::from("VALUE2"));
266 cmd.env("ENV3", "VALUE3").env("ENV4", "VALUE4").envs(hash);
267 assert_eq!(cmd.envp_map["ENV1"], "VALUE1");
268 assert_eq!(cmd.envp_map["ENV2"], "VALUE2");
269 assert_eq!(cmd.envp_map["ENV3"], "VALUE3");
270 assert_eq!(cmd.envp_map["ENV4"], "VALUE4");
271 }
272 #[test]
273 fn test_stdin() {
274 use std::str;
275 let mut cmd = Command::new("rusttest");
276 cmd.stdin("hello").stdin(" ").stdin("world");
277 assert_eq!(
278 str::from_utf8(&cmd.stdin_str).expect("ERROR"),
279 "hello world"
280 );
281 }
282 #[test]
283 fn test_stdin_u8() {
284 let mut cmd = Command::new("rusttest");
285 cmd.stdin("Test").stdin_u8(0).stdin_u8(100).stdin_u8(255);
286 assert_eq!(cmd.stdin_str, vec![84, 101, 115, 116, 0, 100, 255]);
287 }
288 #[test]
289 fn test_stdin_u8vec() {
290 let mut cmd = Command::new("rusttest");
291 let v = vec![5, 6, 7];
292 cmd.stdin("Test")
293 .stdin_u8vec(&v)
294 .stdin_u8(100)
295 .stdin_u8(255);
296 assert_eq!(cmd.stdin_str, vec![84, 101, 115, 116, 5, 6, 7, 100, 255]);
297 assert_eq!(v, vec![5, 6, 7]);
298 }
299 #[test]
300 fn test_timeout() {
301 let mut cmd = Command::new("rusttest");
302 cmd.timeout(666666);
303 assert_eq!(cmd.timeout_val, 666666);
304 }
305}