|
|
|
//! Database manipulation stuffs
|
|
|
|
use super::*;
|
|
|
|
use std::{
|
|
|
|
path::{
|
|
|
|
PathBuf,
|
|
|
|
},
|
|
|
|
error,
|
|
|
|
fmt,
|
|
|
|
io,
|
|
|
|
marker::Unpin,
|
|
|
|
};
|
|
|
|
/// An error in database operations
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum Error {
|
|
|
|
ExpectedLine(Option<String>),
|
|
|
|
IO(io::Error),
|
|
|
|
Unknown,
|
|
|
|
}
|
|
|
|
impl error::Error for Error
|
|
|
|
{
|
|
|
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
|
|
|
match &self {
|
|
|
|
Self::IO(io) => Some(io),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl fmt::Display for Error
|
|
|
|
{
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
{
|
|
|
|
match self {
|
|
|
|
Self::IO(_)=> write!(f, "i/o"),
|
|
|
|
Self::ExpectedLine(None) => write!(f, "expected a line that was not present in the file"),
|
|
|
|
Self::ExpectedLine(Some(msg)) => write!(f, "{}", msg),
|
|
|
|
_ => write!(f, "unknown"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Contains Videl information for a database directory
|
|
|
|
#[derive(Debug, Clone, PartialEq, Ord, Eq, PartialOrd, Hash)]
|
|
|
|
pub struct Database
|
|
|
|
{
|
|
|
|
pub path: PathBuf,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Database
|
|
|
|
{
|
|
|
|
/// Create a new database for this path
|
|
|
|
pub fn new(path: PathBuf) -> Self
|
|
|
|
{
|
|
|
|
Self {
|
|
|
|
path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Save this database to a stream
|
|
|
|
pub async fn save<T: AsyncWrite + Unpin + ?Sized>(&self, stream: &mut T) -> Result<usize, Error>
|
|
|
|
{
|
|
|
|
let bytes = resolve::path_bytes(&self.path);
|
|
|
|
stream.write_all(&bytes[..]).await?;
|
|
|
|
stream.write_u8(b'\n').await?;
|
|
|
|
Ok(bytes.len() + 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Load database info from this file
|
|
|
|
pub async fn load<T: AsyncBufRead + Unpin + ?Sized>(stream: &mut T) -> Result<Database, Error>
|
|
|
|
{
|
|
|
|
let mut buffer = String::new();
|
|
|
|
macro_rules! line {
|
|
|
|
($message:literal $($tt:tt)*) => {
|
|
|
|
{
|
|
|
|
buffer.clear();
|
|
|
|
let read = stream.read_line(&mut buffer).await?;
|
|
|
|
if read == 0 {
|
|
|
|
return Err(Error::ExpectedLine(Some(format!($message $($tt)*))));
|
|
|
|
}
|
|
|
|
&buffer[..]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let location_encoded = line!("expected the location line");
|
|
|
|
|
|
|
|
Ok(Database{
|
|
|
|
path: PathBuf::from(location_encoded),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<io::Error> for Error
|
|
|
|
{
|
|
|
|
#[inline] fn from(from: io::Error) -> Self
|
|
|
|
{
|
|
|
|
Self::IO(from)
|
|
|
|
}
|
|
|
|
}
|