1use super::{ConvertSlice, ErrHandler, Reader};
2
3#[allow(unused_imports)] use opts;
5use results::{Result, Success};
6use std::{
7 cmp::Ordering,
8 io::{BufRead, Read, Write},
9 time::SystemTime,
10};
11
12pub fn standard<R, W, C, E>(mut r: Reader<R>, w: &mut W, c: C, mut e: ErrHandler<E>) -> Result<Success>
15where
16 R: Read,
17 W: Write,
18 C: ConvertSlice<u8>,
19 E: Write,
20{
21 let start = SystemTime::now();
22 let mut bytes = 0;
23 loop {
24 let converted = match e.handle(r.fill_buf())? {
25 Some(ref buf) if buf.len() == 0 => return Ok(Success::Bytes { bytes, start }),
26 Some(buf) => c.convert_copy(buf),
27 None => continue,
28 };
29
30 e.handle(w.write_all(&converted))?;
31 r.consume(converted.len());
32 bytes += converted.len();
33 e.report_status_standard(bytes, &start)?
34 }
35}
36pub fn bytes<R, W, C, E>(mut r: R, w: &mut W, c: &C, mut e: ErrHandler<E>, max_bytes: usize) -> Result<Success>
37where
38 R: BufRead,
39 W: Write,
40 C: ConvertSlice<u8>,
41 E: Write,
42{
43 let start = SystemTime::now();
44 let mut bytes = 0;
45 loop {
46 let converted = match e.handle(r.fill_buf())? {
47 None => continue,
48 Some(buf) => match usize::min(max_bytes.saturating_sub(bytes), buf.len()) {
49 0 => return Ok(Success::Bytes { bytes, start }),
50 n => c.convert_copy(&buf[..n]),
51 },
52 };
53
54 e.handle(w.write_all(&converted))?;
55 r.consume(converted.len());
56 bytes += converted.len();
57 }
58}
59
60pub fn block<R, W, C, E>(r: R, w: &mut W, c: C, mut e: ErrHandler<E>, block_size: usize) -> Result<Success>
71where
72 R: BufRead,
73 W: Write,
74 C: ConvertSlice<u8>,
75 E: Write,
76{
77 let (mut lines, mut padded, mut truncated): (usize, usize, usize) = (0, 0, 0);
78 let (mut buf, mut bytes): (Vec<u8>, std::io::Bytes<_>) = (Vec::with_capacity(block_size), r.bytes());
79 let start = SystemTime::now();
80 while {
81 if let Some(b) = skip_trailing_while_match(&mut bytes, &b'\n')? {
82 buf.push(b)
83 };
84 e.handle(fill_buf_until_match(&mut bytes, &mut buf, b'\n'))?;
85 buf.len() != 0
86 } {
87 lines += 1;
88 match buf.len().cmp(&block_size) {
89 Ordering::Greater => truncated += 1,
90 Ordering::Less => padded += 1,
91 Ordering::Equal => {},
92 }
93
94 c.convert_slice(&mut buf);
95 buf.resize(block_size, b' ');
96 w.write_all(&buf)?;
97 e.report_status_block(lines, &start);
98 buf.clear();
99 }
100 Ok(Success::Block {
101 start,
102 lines,
103 truncated,
104 padded,
105 block_size,
106 })
107}
108
109pub fn unblock<R, W, C, E>(r: R, w: &mut W, c: C, mut e: ErrHandler<E>, block_size: usize) -> Result<Success>
116where
117 R: BufRead,
118 W: Write,
119 C: ConvertSlice<u8>,
120 E: Write,
121{
122 let start = SystemTime::now();
123 let mut buf: Vec<u8> = Vec::with_capacity(block_size + 1); let mut bytes = r.bytes();
125 let mut blocks = 0;
126 while {
127 if let Some(Some(b)) = e.handle(skip_trailing_while_match(&mut bytes, &b' '))? {
128 buf.push(b)
129 };
130 fill_buf_to(&mut bytes, &mut buf, block_size)?;
131 buf.len() != 0
132 } {
133 buf.push(b'\n');
134
135 c.convert_slice(&mut buf);
136 e.handle(w.write_all(&mut buf))?;
137
138 blocks += 1;
139 e.report_status_unblock(blocks, &start);
140 buf.clear();
141 }
142 Ok(Success::Unblock {
143 blocks,
144 block_size,
145 start,
146 })
147}
148
149fn skip_trailing_while_match<I, T>(it: &mut I, unwanted: &T) -> std::io::Result<Option<T>>
153where
154 I: Iterator<Item = ::std::io::Result<T>>,
155 T: PartialEq,
156{
157 loop {
158 match it.next() {
159 Some(Ok(ref t)) if t == unwanted => {},
160 Some(t) => return Ok(Some(t?)),
161 None => return Ok(None),
162 }
163 }
164}
165
166pub fn fill_buf_until_match<I, T>(it: &mut I, buf: &mut Vec<T>, want: T) -> std::io::Result<()>
176where
177 I: Iterator<Item = std::io::Result<T>>,
178 T: PartialEq,
179{
180 loop {
181 match it.next() {
182 Some(Ok(ref t)) if t == &want => return Ok(()),
183 Some(Ok(t)) => buf.push(t),
184 Some(Err(err)) => return Err(err),
185 None => return Ok(()),
186 }
187 }
188}
189
190pub fn fill_buf_to<I, T>(it: &mut I, buf: &mut Vec<T>, cap: usize) -> std::io::Result<()>
202where
203 I: Iterator<Item = std::io::Result<T>>,
204{
205 for _ in buf.len()..cap {
206 match it.next() {
207 Some(Ok(t)) => buf.push(t),
208 Some(Err(err)) => return Err(err),
209 None => break,
210 };
211 }
212 Ok(())
213}