use std::fmt;
use std::fs::File;
use std::io::SeekFrom::Start;
use std::io::{Read, Seek};
use std::path::Path;
const FAILED_READ_SENTINEL: usize = 1234567890;
const FAILED_READ_SENTINEL_2: usize = 12345678901;
pub struct TextFileReader<'a> {
filepath: &'a Path,
file: File,
size: u64,
}
impl<'a> TextFileReader<'a> {
pub fn new(filepath: &'a Path) -> Result<Self, Box<dyn std::error::Error>> {
let file = File::open(filepath)?;
let size = file.metadata()?.len();
Ok(Self {
filepath,
file,
size,
})
}
}
impl fmt::Debug for TextFileReader<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
writeln!(f, "{}", self.filepath.to_string_lossy()).unwrap();
let mut my_file = &self.file;
my_file.seek(Start(0)).unwrap();
let buffer: &mut [u8] = &mut [0; 1024];
loop {
match my_file.read(buffer) {
Ok(bytes_read) => {
if bytes_read > 0 {
write!(f, "{}", String::from_utf8_lossy(&buffer[0..bytes_read])).unwrap();
} else {
break;
}
}
Err(err) => {
write!(
f,
"Error: failed to read source file {}: {}",
self.filepath.to_string_lossy(),
err
)
.unwrap();
return Err(fmt::Error);
}
}
}
Ok(())
}
}
impl PartialEq for TextFileReader<'_> {
fn eq(&self, other: &Self) -> bool {
if self.size != other.size {
return false;
}
let mut my_file = &self.file;
let mut other_file = &other.file;
my_file.seek(Start(0)).unwrap();
other_file.seek(Start(0)).unwrap();
let my_buffer: &mut [u8] = &mut [0; 1024];
let other_buffer: &mut [u8] = &mut [0; 1024];
loop {
let my_bytes_read = my_file.read(my_buffer).unwrap_or(FAILED_READ_SENTINEL);
let other_bytes_read = other_file
.read(other_buffer)
.unwrap_or(FAILED_READ_SENTINEL_2);
if my_bytes_read == other_bytes_read {
if my_buffer != other_buffer {
return false;
}
} else {
return false;
}
if my_bytes_read == 0 {
break;
}
}
true
}
}