1use std::fs::{File, Metadata};
2use std::io::{Seek, BufReader, SeekFrom, Read, BufWriter, Write};
3use std::collections::{VecDeque};
4
5const BUFFER_SIZE: u64 = 4096;
6
7pub enum ModificationType {
8 Added,
9 Removed,
10 NoChange,
11}
12
13#[allow(dead_code)]
14pub enum Input {
15 File(File),
16 Stdin(std::io::Stdin),
17}
18
19pub struct BackwardsReader<'a> {
30 pieces: VecDeque<VecDeque<Vec<u8>>>,
31 num_of_lines: usize,
32 fd: &'a mut BufReader<File>,
33 total_newlines: usize,
34 first_read: bool,
35 last_offset: u64
36}
37
38impl<'a> BackwardsReader<'a> {
39 pub fn new(num_of_lines: usize, fd: &'a mut BufReader<File>) -> Self {
40 let last_offset = fd.seek(SeekFrom::End(0))
41 .unwrap_or_else(|_| { panic!("Failed to seek to end of file") });
42 BackwardsReader {
43 pieces: VecDeque::with_capacity(num_of_lines),
44 num_of_lines: num_of_lines,
45 fd: fd,
46 total_newlines: 0,
47 first_read: true,
48 last_offset: last_offset
49 }
50 }
51
52 fn handle_partial_read(&mut self) {
53 if self.last_offset > 0 {
54 self.fd.seek(SeekFrom::Start(0)).unwrap();
55 let mut buff = vec![0; (self.last_offset) as usize];
56 self.fd.read_exact(buff.as_mut_slice())
57 .unwrap_or_else(|_| { panic!("Incorrectly handled unexpected EOF. Probably an off by one error") });
58 if self.first_read && buff[buff.len() - 1] != b'\n' {
59 self.total_newlines += 1;
60 self.first_read = false;
61 buff.push(b'\n');
62 }
63 let buff: VecDeque<Vec<u8>> = buff.split(|elm: &u8| {*elm == b'\n'}).map(|elm: &[u8]| elm.to_vec()).collect();
64 self.total_newlines += buff.len() - 1;
65 self.pieces.push_front(buff);
66 }
67 }
68
69 fn read(&mut self) -> bool {
70 let seek_offset = if (self.last_offset as i64) - (BUFFER_SIZE as i64) >= 0 {
71 self.last_offset - BUFFER_SIZE
72 } else {
73 self.handle_partial_read();
74 return false;
75 };
76 match self.fd.seek(SeekFrom::Start(seek_offset)) {
77 Ok(new_offset) => {
78 self.last_offset = new_offset;
79 },
80 Err(_) => {
81 self.handle_partial_read();
82 return false;
83 }
84 }
85
86 let mut buff = vec![0; BUFFER_SIZE as usize];
87 self.fd.read_exact(buff.as_mut_slice())
88 .unwrap_or_else(|_| { panic!("Failed to read from end of file in BackwardsReader") });
89 if self.first_read && buff[buff.len() - 1] != b'\n' {
90 self.total_newlines += 1;
91 self.first_read = false;
92 buff.push(b'\n');
93 }
94 let buff: VecDeque<Vec<u8>> = buff.split(|elm: &u8| {*elm == b'\n'}).map(|elm: &[u8]| elm.to_vec()).collect();
95 self.total_newlines += buff.len() - 1;
96 self.pieces.push_front(buff);
97
98 if self.first_read {
99 self.first_read = false;
100 }
101 self.total_newlines < self.num_of_lines
102 }
103
104 pub fn read_all<T: Write>(&mut self, writer: &mut BufWriter<T>) {
105 while self.read() {}
106
107 if self.total_newlines > self.num_of_lines {
111 let mut first_chunk = self.pieces.pop_front().unwrap();
112 let pieces_to_discard = self.total_newlines - self.num_of_lines as usize;
113 if pieces_to_discard > 0 {
114 for _ in 0..pieces_to_discard {
115 first_chunk.pop_front().unwrap();
116 }
117 self.total_newlines -= pieces_to_discard;
118 }
119 self.pieces.push_front(first_chunk);
120 }
121
122 if self.pieces.is_empty() { return; }
123
124 let mut line: Vec<u8> = Vec::new();
125 while let Some(mut piece) = self.pieces.pop_front() {
126 if piece.len() == 1 {
127 line.append(piece.pop_front().unwrap().as_mut());
128 } else if piece.len() > 1 {
129 let mut last_chunk = piece.pop_back().unwrap();
130 for mut chunk in piece {
131 line.append(&mut chunk);
132 line.push(b'\n');
133 writer.write(&line).unwrap();
134 line.clear();
135 }
136 line.append(&mut last_chunk);
137 }
138 }
139 if !line.is_empty() {
140 writer.write(&line).unwrap();
141 }
142 }
143}
144
145#[derive(Debug)]
146pub struct StatefulFile {
147 pub fd: BufReader<File>,
148 pub old_metadata: Metadata,
149 file_name: String,
150 cursor: SeekFrom,
151}
152
153impl StatefulFile {
154 pub fn new(fd: File, file_name: String) -> Self {
155 StatefulFile {
156 old_metadata: fd.metadata()
157 .unwrap_or_else(|_| { panic!("Could not retrieve metadata for file: {}", &file_name) }),
158 fd: BufReader::new(fd),
159 file_name: file_name,
160 cursor: SeekFrom::Start(0),
161 }
162 }
163
164 pub fn update_metadata(&mut self) {
165 self.old_metadata = self.fd.get_ref().metadata()
166 .unwrap_or_else(|_| { panic!("Could not retrieve metadata for file: {}", self.file_name) });
167 }
168
169 pub fn modification_type(&self) -> ModificationType {
170 let new_metadata = self.fd.get_ref().metadata()
171 .unwrap_or_else(|_| { panic!("Could not retrieve metadata for file: {}", self.file_name) });
172 if new_metadata.len() > self.old_metadata.len() {
173 ModificationType::Added
174 } else if new_metadata.len() < self.old_metadata.len() {
175 ModificationType::Removed
176 } else {
177 ModificationType::NoChange
178 }
179 }
180
181 pub fn seek_to_cursor(&mut self) {
182 self.fd.seek(self.cursor).unwrap();
183 }
184
185 pub fn update_cursor(&mut self) {
186 self.cursor = SeekFrom::Start(self.fd.seek(SeekFrom::Current(0)).unwrap());
187 }
188
189 pub fn reset_cursor(&mut self) {
190 self.cursor = SeekFrom::Start(0);
191 }
192}