use std::path::PathBuf;
use io_fs::{
coroutines::{create_file::CreateFile, rename::Rename},
error::{FsError, FsResult},
io::FsIo,
};
use thiserror::Error;
use crate::{constants::TMP, item::Item};
#[derive(Clone, Debug, Error)]
pub enum UpdateItemError {
#[error("Create temporary Vdir item file error")]
CreateTempFile(#[source] FsError),
#[error("Save Vdir item file error")]
SaveFile(#[source] FsError),
}
#[derive(Clone, Debug)]
pub enum UpdateItemResult {
Ok,
Err(UpdateItemError),
Io(FsIo),
}
#[derive(Debug)]
enum State {
CreateTempItem(CreateFile),
MoveItem(Rename),
}
#[derive(Debug)]
pub struct UpdateItem {
path: PathBuf,
path_tmp: PathBuf,
state: State,
}
impl UpdateItem {
pub fn new(item: Item) -> Self {
let path_tmp = item.path.with_extension(TMP);
let fs = CreateFile::new(&path_tmp, item.to_string().into_bytes());
let state = State::CreateTempItem(fs);
Self {
path: item.path,
path_tmp,
state,
}
}
pub fn resume(&mut self, mut arg: Option<FsIo>) -> UpdateItemResult {
loop {
match &mut self.state {
State::CreateTempItem(fs) => {
match fs.resume(arg.take()) {
FsResult::Ok(()) => (),
FsResult::Io(io) => break UpdateItemResult::Io(io),
FsResult::Err(err) => {
let err = UpdateItemError::CreateTempFile(err);
break UpdateItemResult::Err(err);
}
};
let fs = Rename::new(Some((&self.path_tmp, &self.path)));
self.state = State::MoveItem(fs);
}
State::MoveItem(fs) => {
match fs.resume(arg.take()) {
FsResult::Ok(()) => (),
FsResult::Io(io) => break UpdateItemResult::Io(io),
FsResult::Err(err) => {
let err = UpdateItemError::SaveFile(err);
break UpdateItemResult::Err(err);
}
};
break UpdateItemResult::Ok;
}
}
}
}
}