yash_env/input/
fd_reader_2.rs1use super::{Context, Input, Result};
20use crate::io::Fd;
21use crate::system::{Concurrent, Fcntl, Read};
22use std::rc::Rc;
23use std::slice::from_mut;
24
25#[derive(Debug)]
38#[must_use = "FdReader2 does nothing unless used by a parser"]
39pub struct FdReader2<S> {
40 fd: Fd,
42 system: Rc<Concurrent<S>>,
44}
45
46impl<S> FdReader2<S> {
47 pub fn new(fd: Fd, system: Rc<Concurrent<S>>) -> Self {
53 FdReader2 { fd, system }
54 }
55}
56
57impl<S> Clone for FdReader2<S> {
59 fn clone(&self) -> Self {
60 Self {
61 fd: self.fd,
62 system: self.system.clone(),
63 }
64 }
65}
66
67impl<S: Fcntl + Read> Input for FdReader2<S> {
68 async fn next_line(&mut self, _context: &Context) -> Result {
69 let mut bytes = Vec::new();
72 loop {
73 let mut byte = 0;
74 match self.system.read(self.fd, from_mut(&mut byte)).await {
75 Ok(0) => break,
77
78 Ok(count) => {
79 assert_eq!(count, 1);
80 bytes.push(byte);
81 if byte == b'\n' {
82 break;
83 }
84 }
85
86 Err(errno) => return Err(errno.into()),
87 }
88 }
89
90 let line = String::from_utf8(bytes)
92 .unwrap_or_else(|e| String::from_utf8_lossy(&e.into_bytes()).into());
93
94 Ok(line)
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::system::Errno;
102 use crate::system::Mode;
103 use crate::system::OfdAccess;
104 use crate::system::Open as _;
105 use crate::system::OpenFlag;
106 use crate::system::r#virtual::FileBody;
107 use crate::system::r#virtual::Inode;
108 use crate::system::r#virtual::VirtualSystem;
109 use futures_util::FutureExt as _;
110
111 #[test]
112 fn empty_reader() {
113 let system = VirtualSystem::new();
114 let system = Rc::new(Concurrent::new(system));
115 let mut reader = FdReader2::new(Fd::STDIN, system);
116
117 let line = reader
118 .next_line(&Context::default())
119 .now_or_never()
120 .unwrap()
121 .unwrap();
122 assert_eq!(line, "");
123 }
124
125 #[test]
126 fn one_line_reader() {
127 let system = VirtualSystem::new();
128 {
129 let state = system.state.borrow_mut();
130 let file = state.file_system.get("/dev/stdin").unwrap();
131 file.borrow_mut().body = FileBody::new(*b"echo ok\n");
132 }
133 let system = Rc::new(Concurrent::new(system));
134 let mut reader = FdReader2::new(Fd::STDIN, system);
135
136 let line = reader
137 .next_line(&Context::default())
138 .now_or_never()
139 .unwrap()
140 .unwrap();
141 assert_eq!(line, "echo ok\n");
142 let line = reader
143 .next_line(&Context::default())
144 .now_or_never()
145 .unwrap()
146 .unwrap();
147 assert_eq!(line, "");
148 }
149
150 #[test]
151 fn reader_with_many_lines() {
152 let system = VirtualSystem::new();
153 {
154 let state = system.state.borrow_mut();
155 let file = state.file_system.get("/dev/stdin").unwrap();
156 file.borrow_mut().body = FileBody::new(*b"#!/bin/sh\necho ok\nexit");
157 }
158 let system = Rc::new(Concurrent::new(system));
159 let mut reader = FdReader2::new(Fd::STDIN, system);
160
161 let line = reader
162 .next_line(&Context::default())
163 .now_or_never()
164 .unwrap()
165 .unwrap();
166 assert_eq!(line, "#!/bin/sh\n");
167 let line = reader
168 .next_line(&Context::default())
169 .now_or_never()
170 .unwrap()
171 .unwrap();
172 assert_eq!(line, "echo ok\n");
173 let line = reader
174 .next_line(&Context::default())
175 .now_or_never()
176 .unwrap()
177 .unwrap();
178 assert_eq!(line, "exit");
179 let line = reader
180 .next_line(&Context::default())
181 .now_or_never()
182 .unwrap()
183 .unwrap();
184 assert_eq!(line, "");
185 }
186
187 #[test]
188 fn reading_from_file() {
189 let system = VirtualSystem::new();
190 {
191 let mut state = system.state.borrow_mut();
192 let file = Rc::new(Inode::new("echo file\n").into());
193 state.file_system.save("/foo", file).unwrap();
194 }
195 let system = Rc::new(Concurrent::new(system));
196 let path = c"/foo";
197 let fd = system
198 .open(
199 path,
200 OfdAccess::ReadOnly,
201 OpenFlag::CloseOnExec.into(),
202 Mode::empty(),
203 )
204 .now_or_never()
205 .unwrap()
206 .unwrap();
207 let mut reader = FdReader2::new(fd, system);
208
209 let line = reader
210 .next_line(&Context::default())
211 .now_or_never()
212 .unwrap()
213 .unwrap();
214 assert_eq!(line, "echo file\n");
215 let line = reader
216 .next_line(&Context::default())
217 .now_or_never()
218 .unwrap()
219 .unwrap();
220 assert_eq!(line, "");
221 }
222
223 #[test]
224 fn reader_error() {
225 let system = VirtualSystem::new();
226 system.current_process_mut().close_fd(Fd::STDIN);
227 let system = Rc::new(Concurrent::new(system));
228 let mut reader = FdReader2::new(Fd::STDIN, system);
229
230 let error = reader
231 .next_line(&Context::default())
232 .now_or_never()
233 .unwrap()
234 .unwrap_err();
235 assert_eq!(error.raw_os_error(), Some(Errno::EBADF.0));
236 }
237}