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