pub mod oversize;
pub mod tree;
use std::io;
use std::path::Path;
pub use oversize::{
check_size, format_oversize_warning, is_autogen_file, max_size_for, SizeCheck,
MAX_AUTOGEN_FILE_SIZE_BYTES, MAX_FILE_SIZE_BYTES,
};
pub use tree::get_file_tree;
#[derive(Debug)]
pub enum ReadOutcome {
Ok(String),
NonUtf8 {
byte_offset: usize,
},
}
pub fn read_to_string_tolerant(path: &Path) -> io::Result<ReadOutcome> {
let bytes = std::fs::read(path)?;
match String::from_utf8(bytes) {
Ok(source) => Ok(ReadOutcome::Ok(source)),
Err(err) => {
let byte_offset = err.utf8_error().valid_up_to();
Ok(ReadOutcome::NonUtf8 { byte_offset })
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use tempfile::NamedTempFile;
#[test]
fn read_to_string_tolerant_returns_ok_for_valid_utf8() {
let mut f = NamedTempFile::new().unwrap();
f.write_all(b"hello world\n").unwrap();
let outcome = read_to_string_tolerant(f.path()).unwrap();
match outcome {
ReadOutcome::Ok(s) => assert_eq!(s, "hello world\n"),
other => panic!("expected Ok, got {:?}", other),
}
}
#[test]
fn read_to_string_tolerant_returns_nonutf8_for_invalid_bytes() {
let mut f = NamedTempFile::new().unwrap();
f.write_all(b"valid prefix \xFF\xFE invalid").unwrap();
let outcome = read_to_string_tolerant(f.path()).unwrap();
match outcome {
ReadOutcome::NonUtf8 { byte_offset } => {
assert_eq!(byte_offset, "valid prefix ".len());
}
other => panic!("expected NonUtf8, got {:?}", other),
}
}
#[test]
fn read_to_string_tolerant_returns_err_for_missing_file() {
let outcome = read_to_string_tolerant(Path::new("/nonexistent/path/xyz.txt"));
assert!(outcome.is_err());
}
}