use optic_core::{OpticError, OpticErrorKind, OpticResult};
use std::fs;
use std::io::ErrorKind;
use std::path::PathBuf;
pub fn name(path: &str) -> Option<String> {
let path = PathBuf::from(path);
path.file_stem()
.map(|n| n.to_string_lossy().to_string())
}
pub fn extension(path: &str) -> Option<String> {
let path = PathBuf::from(path);
path.extension()
.map(|n| n.to_string_lossy().to_string())
}
pub fn exists(path: &str) -> bool {
PathBuf::from(path).exists()
}
pub fn read_bytes(path: &str) -> OpticResult<Vec<u8>> {
match fs::read(path) {
Ok(data) => Ok(data),
Err(e) => {
let kind = match e.kind() {
ErrorKind::NotFound | ErrorKind::InvalidInput => "file not found or invalid",
ErrorKind::PermissionDenied => "permission denied",
_ => "unknown file error",
};
Err(OpticError::new(
OpticErrorKind::File,
&format!("{kind}: {path}"),
))
}
}
}
pub fn read_string(path: &str) -> OpticResult<String> {
match fs::read_to_string(path) {
Ok(data) => Ok(data),
Err(e) => {
let kind = match e.kind() {
ErrorKind::NotFound | ErrorKind::InvalidInput => "file not found or invalid",
ErrorKind::PermissionDenied => "permission denied",
_ => "unknown file error",
};
Err(OpticError::new(
OpticErrorKind::File,
&format!("{kind}: {path}"),
))
}
}
}
pub fn write_bytes(path: &str, data: &[u8]) -> OpticResult<()> {
let pathbuf = PathBuf::from(path);
if let Some(parent) = pathbuf.parent() {
if !parent.exists() {
fs::create_dir_all(parent).map_err(|e| {
OpticError::new(
OpticErrorKind::File,
&format!("could not create directory {}: {e}", parent.display()),
)
})?;
}
}
fs::write(path, data).map_err(|e| {
OpticError::new(
OpticErrorKind::File,
&format!("could not write {path}: {e}"),
)
})
}
pub fn write_string(path: &str, data: &str) -> OpticResult<()> {
write_bytes(path, data.as_bytes())
}
pub fn cached_path(source: &str, ext: &str) -> String {
let pb = PathBuf::from(source);
let parent = pb.parent().and_then(|p| {
let s = p.to_string_lossy().to_string();
if s.is_empty() || s == "." { None } else { Some(s) }
});
let stem = pb.file_stem().map(|s| s.to_string_lossy().to_string()).unwrap_or_default();
match parent {
Some(dir) => format!("{dir}/optc/{stem}.{ext}"),
None => format!("optc/{stem}.{ext}"),
}
}
pub fn create_dir(path: &str) -> OpticResult<()> {
fs::create_dir_all(path).map_err(|e| {
OpticError::new(
OpticErrorKind::File,
&format!("could not create directory {path}: {e}"),
)
})
}