1use crate::Close;
2use libc::c_int;
3use std::fmt::Display;
4
5pub enum PipeSide {
6 Read,
7 Write,
8}
9
10#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
12pub struct Pipe {
13 fd: (c_int, c_int),
14}
15
16impl Pipe {
17 pub fn new(&fds: &[libc::c_int; 2]) -> Pipe {
18 Pipe {
19 fd: (fds[0], fds[1]),
20 }
21 }
22 pub fn pipe() -> Option<Pipe> {
23 let mut end = [0; 2];
24 match unsafe { libc::pipe(end.as_mut_ptr()) } {
25 libc::INT_MIN..=-1 => None,
26 _ => Some(Pipe::new(&end)),
27 }
28 }
29
30 pub fn pipe2(flag: i32) -> Option<Pipe> {
31 let mut end = [0; 2];
32 match unsafe { libc::pipe2(end.as_mut_ptr(), flag) } {
33 libc::INT_MIN..=-1 => None,
34 _ => Some(Pipe::new(&end)),
35 }
36 }
37
38 pub fn get(&self, side: PipeSide) -> c_int {
39 match side {
40 PipeSide::Read => self.fd.1,
41 PipeSide::Write => self.fd.0,
42 }
43 }
44}
45
46impl Drop for Pipe {
47 fn drop(&mut self) {
48 match Close::close(&[self.fd.0, self.fd.1]) {
49 Ok(_) => (),
50 Err(v) => eprintln!("{}", v),
51 }
52 }
53}
54
55impl Display for Pipe {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.write_str(
58 std::format!(
59 "pipe: | for_read(fd[0]) {} <<= for_write(fd[1]) {} |",
60 self.fd.0,
61 self.fd.1,
62 )
63 .as_str(),
64 )
65 }
66}
67#[macro_export]
68macro_rules! create_pipe {
69 (1) => {{
70 let mut pipe = [libc::c_int; 2];
71 match unsafe {
72 pipe(pipe.as_mut_ptr())
73 } {
74 -1 => None,
75 _ => Some(pipe)
76 }
77 }};
78 ($n: expr) => {{
79 if $n <= 0 {
80 None
81 } else {
82 let mut pipes: [[libc::c_int; 2]; $n] = [[0; 2]; $n];
83 let mut success = true;
84 for i in 0..$n as usize {
85 unsafe {
86 match libc::pipe(pipes[i].as_mut_ptr()) {
87 0 => {}
88 _ => {
89 success = false;
90 break;
91 }
92 }
93 };
94 }
95 if success {
96 Some(pipes)
97 } else {
98 None
99 }
100 }
101 }};
102}
103
104#[macro_export]
105macro_rules! create_pipe2 {
106 ($n: expr, $modes: expr) => {{
107 if $n != $modes.len() || $n == 0 {
108 None
109 } else {
110 let mut pipes: [[libc::c_int; 2]; $n] = [[0; 2]; $n];
111 let mut success = true;
112 for i in 0..$n as usize {
113 unsafe {
114 match libc::pipe2(pipes[i].as_mut_ptr(), $modes[i]) {
115 0 => {}
116 _ => {
117 success = false;
118 break;
119 }
120 }
121 };
122 }
123 if success {
124 Some(pipes)
125 } else {
126 None
127 }
128 }
129 }};
130}
131
132#[cfg(test)]
133mod pipe {
134 use std::{error::Error, ffi::CString};
135
136 use libc::execl;
137
138 use crate::Close;
139
140 #[test]
141 fn test_execl() -> Result<(), Box<dyn Error>> {
142 let path = CString::new("/bin/sh")?;
143 let sh = CString::new("sh")?;
144 let exec = CString::new("-c")?;
145 let arg = CString::new("ls")?;
146 Ok(())
148 }
149
150 #[test]
151 fn test_create_pipe_macro() {
152 let pipes1 = create_pipe!(1 + 1).unwrap();
153 let pipes2 = create_pipe!(1 & 1).unwrap();
154 assert!(pipes1.len() == 2);
155 assert!(pipes2.len() == 1);
156 let s = &pipes1.iter().flatten().map(|x| *x).collect::<Vec<i32>>()[..];
157 Close::close(s).unwrap();
158 let s1 = &pipes2.iter().flatten().map(|x| *x).collect::<Vec<i32>>()[..];
159 Close::close(s1).unwrap();
160 }
161}