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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::fs::DirEntry;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use dirs::home_dir;
use c::C;
use result::{Result, Error};
const FILEDB_EXT: &str = "filedb";
#[derive(Debug)]
pub struct FileDB {
path: PathBuf,
cmap: HashMap<PathBuf, Mutex<C>>
}
impl FileDB {
pub fn connect<P: AsRef<OsStr>>(path: P) -> Result<Self> {
let p = Path::new(&path);
if !p.exists() {
fs::create_dir_all(p)?;
}
if !p.is_dir() {
return Err(
Error::DBFile {
path: PathBuf::from(&path).to_string_lossy().to_string()
}
);
}
Ok(FileDB {
path: PathBuf::from(&path),
cmap: HashMap::new()
})
}
pub fn col_names(&self) -> Result<Vec<String>> {
let dir: fs::ReadDir = self.path.read_dir()?;
let mut res: Vec<String> = Vec::new();
for ent in dir {
let ent: DirEntry = ent?;
let ext = PathBuf::from(&ent.file_name())
.extension()
.map(|s| s.to_os_string())
.unwrap_or_default();
if ext == OsStr::new(FILEDB_EXT) {
if let Some(file_name) = ent.file_name().to_str().map(|name| name.to_string()) {
res.push(file_name);
}
}
}
Ok(res)
}
pub fn c<'inc>(&'inc mut self, name: &'inc str) -> Result<&'inc Mutex<C>> {
let path = self.get_path(name);
if !self.cmap.contains_key(&path) {
let file = if path.exists() {
OpenOptions::new()
.append(true)
.read(true)
.open(&path)?
} else {
let parent = &path.parent().ok_or(Error::DBFile { path: name.to_string() })?;
fs::create_dir_all(parent)?;
OpenOptions::new()
.create(true)
.append(true)
.read(true)
.open(&path)?
};
self.cmap.insert(path.to_path_buf(), Mutex::new(C::new(&path, file)));
}
let path = self.get_path(name).to_str().unwrap_or_default().to_string();
self.cmap.get(&self.get_path(name)).ok_or(Error::DBFile { path })
}
fn get_path(&self, name: &str) -> PathBuf {
self.path.join(name).with_extension(FILEDB_EXT)
}
}
impl Default for FileDB {
fn default() -> Self {
let path = home_dir().unwrap_or_default().join(".filedb");
FileDB::connect(path).unwrap()
}
}