1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
use async_std::{io::{Read,Write,Seek},fs,path::PathBuf};

pub trait RW: Read+Write+Seek+Truncate+Send+Sync+Unpin {}
impl RW for fs::File {}

#[async_trait::async_trait]
pub trait Truncate {
  async fn set_len(&mut self, len: u64) -> Result<(),Error>;
}

type Error = Box<dyn std::error::Error+Send+Sync>;

#[async_trait::async_trait]
pub trait Storage<S>: Send+Sync+Unpin where S: RW {
  async fn open_rw(&mut self, name: &str) -> Result<S,Error>;
  async fn open_r(&mut self, name: &str) -> Result<Option<S>,Error>;
  async fn remove(&mut self, name: &str) -> Result<(),Error>;
  async fn exists(&mut self, name: &str) -> bool;
}

pub struct FileStorage {
  path: PathBuf,
}

impl FileStorage {
  pub async fn open_from_path<P>(path: P) -> Result<Self,Error>
  where PathBuf: From<P> {
    Ok(Self { path: path.into() })
  }
}

#[async_trait::async_trait]
impl Storage<fs::File> for FileStorage {
  async fn open_rw(&mut self, name: &str) -> Result<fs::File,Error> {
    let p = self.path.join(name);
    fs::create_dir_all(p.parent().unwrap()).await?;
    Ok(fs::OpenOptions::new().read(true).write(true).create(true).open(p).await?)
  }
  async fn open_r(&mut self, name: &str) -> Result<Option<fs::File>,Error> {
    let p = self.path.join(name);
    if p.exists().await {
      Ok(Some(fs::OpenOptions::new().read(true).open(p).await?))
    } else {
      Ok(None)
    }
  }
  async fn remove(&mut self, name: &str) -> Result<(),Error> {
    let p = self.path.join(name);
    fs::remove_file(p).await.map_err(|e| e.into())
  }
  async fn exists(&mut self, name: &str) -> bool {
    self.path.join(name).exists().await
  }
}

#[async_trait::async_trait]
impl Truncate for fs::File {
  async fn set_len(&mut self, len: u64) -> Result<(),Error> {
    fs::File::set_len(self, len).await.map_err(|e| e.into())
  }
}