#[cfg(test)] mod test;
use std::{
fs::{self, File},
io::{Read, Write},
net::TcpListener,
path::{Path, PathBuf},
};
use serde::de::DeserializeOwned;
use tokio::{fs::File as FileAsync, io::AsyncReadExt};
use crate::prelude::*;
pub type Port = u16;
pub fn read_file_to_string<P>(path: P) -> Result<String>
where
P: AsRef<Path>,
{
let mut file = File::open(path).map_err(error::Generic::Io)?;
let mut content = String::new();
file.read_to_string(&mut content).map_err(error::Generic::Io)?;
Ok(content)
}
pub async fn read_file_to_string_async<P>(path: P) -> Result<String>
where
P: AsRef<Path>,
{
let mut file = FileAsync::open(path).await.map_err(error::Generic::Io)?;
let mut content = String::new();
file.read_to_string(&mut content).await.map_err(error::Generic::Io)?;
Ok(content)
}
pub fn read_file_to_vec<P>(path: P) -> Result<Vec<u8>>
where
P: AsRef<Path>,
{
let mut file = File::open(path).map_err(error::Generic::Io)?;
let mut content = Vec::new();
file.read_to_end(&mut content).map_err(error::Generic::Io)?;
Ok(content)
}
pub async fn read_file_to_vec_async<P>(path: P) -> Result<Vec<u8>>
where
P: AsRef<Path>,
{
let mut file = FileAsync::open(path).await.map_err(error::Generic::Io)?;
let mut content = Vec::new();
file.read_to_end(&mut content).await.map_err(error::Generic::Io)?;
Ok(content)
}
pub fn read_file_to_struct<P, T>(path: P) -> Result<T>
where
P: AsRef<Path>,
T: DeserializeOwned,
{
subalfred_util::execution_timer!("system::read_file_to_struct");
let content = {
subalfred_util::execution_timer!("system::read_json");
read_file_to_vec(path)?
};
let result = {
subalfred_util::execution_timer!("system::parse_json");
serde_json::from_slice(&content).map_err(error::Generic::Serde)?
};
Ok(result)
}
pub async fn read_file_to_struct_async<P, T>(path: P) -> Result<T>
where
P: AsRef<Path>,
T: DeserializeOwned,
{
subalfred_util::execution_timer!("system::read_file_to_struct_async");
let content = {
subalfred_util::execution_timer!("system::read_json_async");
read_file_to_vec(path)?
};
let result = {
subalfred_util::execution_timer!("system::parse_json_async");
serde_json::from_slice(&content).map_err(error::Generic::Serde)?
};
Ok(result)
}
pub fn write_data_to_file<P>(path: P, data: &[u8]) -> Result<()>
where
P: AsRef<Path>,
{
let mut file = File::create(path).map_err(error::Generic::Io)?;
Ok(file.write_all(data).map_err(error::Generic::Io)?)
}
pub fn swap_file_data<P>(path: P, data: &[u8]) -> Result<()>
where
P: AsRef<Path>,
{
let path = path.as_ref();
let swapped_path = swapped_file_path(path)
.ok_or_else(|| error::System::NoFileNameInPath(path.to_path_buf()))?;
write_data_to_file(&swapped_path, data)?;
fs::rename(swapped_path, path).map_err(error::Generic::Io)?;
Ok(())
}
fn swapped_file_path<P>(path: P) -> Option<PathBuf>
where
P: AsRef<Path>,
{
let path = path.as_ref();
let file_name = path.file_name()?.to_string_lossy();
Some(path.with_file_name(format!(".{file_name}.swp")))
}
pub fn random_available_port() -> Result<Port> {
for port in 1025..Port::MAX {
if TcpListener::bind(("127.0.0.1", port)).is_ok() {
return Ok(port);
}
}
Err(error::System::NoAvailablePortFound)?
}