use std::borrow::Cow;
use std::fs::read;
use std::path::Path;
use crate::error::DatabaseError;
use crate::file::File;
use crate::file::FileType;
const MAXIMUM_FILE_SIZE: usize = 256 * 1024 * 1024;
pub(crate) fn read_file(workspace: &Path, path: &Path, file_type: FileType) -> Result<File, DatabaseError> {
let bytes = read(path)?;
if bytes.len() > MAXIMUM_FILE_SIZE {
return Err(DatabaseError::FileTooLarge(path.to_path_buf(), bytes.len(), MAXIMUM_FILE_SIZE));
}
#[cfg(windows)]
let logical_name = path.strip_prefix(workspace).unwrap_or(path).to_string_lossy().replace('\\', "/");
#[cfg(not(windows))]
let logical_name = path.strip_prefix(workspace).unwrap_or(path).to_string_lossy().into_owned();
let contents = if simdutf8::basic::from_utf8(&bytes).is_ok() {
unsafe {
String::from_utf8_unchecked(bytes)
}
} else {
let warning_message = format!(
"File `{logical_name}` contains invalid UTF-8. Lossy conversion applied, which may cause undefined behavior.",
);
match file_type {
FileType::Host => tracing::warn!("{}", warning_message),
FileType::Vendored | FileType::Builtin => tracing::info!("{}", warning_message),
}
String::from_utf8_lossy(&bytes).into_owned()
};
Ok(File::new(Cow::Owned(logical_name), file_type, Some(path.to_path_buf()), Cow::Owned(contents)))
}