1use std::{
2 fs::File,
3 io::{self, BufRead, BufReader, Read},
4 path::{Path, PathBuf},
5 str::FromStr,
6 sync::{Arc, Mutex, MutexGuard},
7};
8
9#[track_caller]
10fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<T> {
11 mutex.lock().unwrap_or_else(|e| e.into_inner())
12}
13
14#[derive(Debug, Clone)]
47pub struct Input(InputInner);
48
49#[derive(Debug, Clone)]
50enum InputInner {
51 Stdin,
52 File {
53 path: Arc<PathBuf>,
54 reader: Arc<Mutex<BufReader<File>>>,
55 },
56}
57
58impl Input {
59 pub fn stdin() -> Self {
61 Self(InputInner::Stdin)
62 }
63
64 pub fn open(path: PathBuf) -> io::Result<Self> {
66 let path = Arc::new(path);
67 let file = File::open(&*path)?;
68 let reader = Arc::new(Mutex::new(BufReader::new(file)));
69 Ok(Self(InputInner::File { path, reader }))
70 }
71
72 pub fn is_stdin(&self) -> bool {
74 matches!(self.0, InputInner::Stdin)
75 }
76
77 pub fn is_file(&self) -> bool {
80 matches!(self.0, InputInner::File { .. })
81 }
82
83 pub fn path(&self) -> Option<&Path> {
87 match &self.0 {
88 InputInner::Stdin => None,
89 InputInner::File { path, .. } => Some(path),
90 }
91 }
92
93 pub fn lock(&self) -> LockedInput<'_> {
99 let inner = match &self.0 {
100 InputInner::Stdin => {
101 let reader = io::stdin().lock();
102 LockedInputInner::Stdin { reader }
103 }
104 InputInner::File { path, reader: file } => {
105 let reader = lock(file);
106 LockedInputInner::File {
107 path: Arc::clone(path),
108 reader,
109 }
110 }
111 };
112 LockedInput(inner)
113 }
114}
115
116impl FromStr for Input {
117 type Err = io::Error;
118
119 fn from_str(s: &str) -> Result<Self, Self::Err> {
120 if s == "-" {
121 return Ok(Self::stdin());
122 }
123 Self::open(PathBuf::from(s))
124 }
125}
126
127macro_rules! with_reader {
128 ($inner:expr, $var:ident => $e:expr) => {
129 match $inner {
130 InputInner::Stdin => {
131 let mut $var = io::stdin();
132 $e
133 }
134 InputInner::File { reader, .. } => {
135 let mut $var = lock(reader);
136 $e
137 }
138 }
139 };
140}
141
142impl Read for Input {
143 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
144 with_reader!(&self.0, r => r.read(buf))
145 }
146
147 fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
148 with_reader!(&self.0, r => r.read_vectored(bufs))
149 }
150
151 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
157 with_reader!(&self.0, r => r.read_to_end(buf))
158 }
159
160 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
161 with_reader!(&self.0, r => r.read_to_string(buf))
162 }
163
164 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
165 with_reader!(&self.0, r => r.read_exact(buf))
166 }
167
168 }
178
179#[derive(Debug)]
181pub struct LockedInput<'a>(LockedInputInner<'a>);
182
183impl LockedInput<'_> {
184 pub fn is_stdin(&self) -> bool {
186 matches!(self.0, LockedInputInner::Stdin { .. })
187 }
188
189 pub fn is_file(&self) -> bool {
191 matches!(self.0, LockedInputInner::File { .. })
192 }
193
194 pub fn path(&self) -> Option<&Path> {
198 match &self.0 {
199 LockedInputInner::Stdin { .. } => None,
200 LockedInputInner::File { path, .. } => Some(path),
201 }
202 }
203}
204
205#[derive(Debug)]
206enum LockedInputInner<'a> {
207 Stdin {
208 reader: io::StdinLock<'a>,
209 },
210 File {
211 path: Arc<PathBuf>,
212 reader: MutexGuard<'a, BufReader<File>>,
213 },
214}
215
216macro_rules! with_locked_reader {
217 ($inner:expr, $var:ident => $e:expr) => {
218 match $inner {
219 LockedInputInner::Stdin { reader } => {
220 let $var = reader;
221 $e
222 }
223 LockedInputInner::File { reader, .. } => {
224 let $var = reader;
225 $e
226 }
227 }
228 };
229}
230
231impl Read for LockedInput<'_> {
232 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
233 with_locked_reader!(&mut self.0, r => r.read(buf))
234 }
235
236 fn read_vectored(&mut self, bufs: &mut [io::IoSliceMut<'_>]) -> io::Result<usize> {
237 with_locked_reader!(&mut self.0, r => r.read_vectored(bufs))
238 }
239
240 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
246 with_locked_reader!(&mut self.0, r => r.read_to_end(buf))
247 }
248
249 fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
250 with_locked_reader!(&mut self.0, r => r.read_to_string(buf))
251 }
252
253 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
254 with_locked_reader!(&mut self.0, r => r.read_exact(buf))
255 }
256
257 }
267
268impl BufRead for LockedInput<'_> {
269 fn fill_buf(&mut self) -> io::Result<&[u8]> {
270 with_locked_reader!(&mut self.0, r => r.fill_buf())
271 }
272
273 fn consume(&mut self, amt: usize) {
274 with_locked_reader!(&mut self.0, r => r.consume(amt))
275 }
276}