bitcasky_common/fs/
file_type.rs1use core::panic;
2use std::path::{Path, PathBuf};
3
4use crate::storage_id::StorageId;
5
6const LOCK_FILE_EXTENSION: &str = "lock";
7const MERGE_META_FILE_EXTENSION: &str = "meta";
8const DATA_FILE_EXTENSION: &str = "data";
9const HINT_FILE_EXTENSION: &str = "hint";
10
11#[derive(PartialEq, Eq, Debug, Copy, Clone)]
12pub enum FileType {
13 Unknown,
14 LockFile,
15 MergeMeta,
16 DataFile,
17 HintFile,
18}
19
20impl FileType {
21 pub fn get_path<P: AsRef<Path>>(&self, base_dir: P, storage_id: Option<StorageId>) -> PathBuf {
22 base_dir.as_ref().join(match self {
23 Self::LockFile => format!("bitcask.{}", LOCK_FILE_EXTENSION),
24 Self::MergeMeta => format!("merge.{}", MERGE_META_FILE_EXTENSION),
25 Self::DataFile => format!("{}.{}", storage_id.unwrap(), DATA_FILE_EXTENSION),
26 Self::HintFile => format!("{}.{}", storage_id.unwrap(), HINT_FILE_EXTENSION),
27 Self::Unknown => panic!("get path for unknown data type"),
28 })
29 }
30
31 pub fn check_file_belongs_to_type(&self, file_path: &Path) -> bool {
32 let ft = match file_path.extension() {
33 None => FileType::Unknown,
34 Some(os_str) => match os_str.to_str() {
35 Some(LOCK_FILE_EXTENSION) => FileType::LockFile,
36 Some(MERGE_META_FILE_EXTENSION) => FileType::MergeMeta,
37 Some(DATA_FILE_EXTENSION) => FileType::DataFile,
38 Some(HINT_FILE_EXTENSION) => FileType::HintFile,
39 _ => FileType::Unknown,
40 },
41 };
42 *self == ft
43 }
44
45 pub fn parse_storage_id_from_file_name(&self, file_path: &Path) -> Option<StorageId> {
46 let binding = file_path.file_name().unwrap().to_string_lossy();
47 let (storage_id_str, _) = binding.split_at(binding.len() - self.extension().len() - 1);
48 match self {
49 Self::LockFile => None,
50 Self::MergeMeta => None,
51 Self::DataFile => Some(storage_id_str),
52 Self::HintFile => Some(storage_id_str),
53 Self::Unknown => panic!("get path for unknown data type"),
54 }
55 .map(|storage_id_str| storage_id_str.parse::<StorageId>())
56 .transpose()
57 .unwrap_or(None)
58 }
59
60 fn extension(&self) -> &str {
61 match self {
62 Self::LockFile => LOCK_FILE_EXTENSION,
63 Self::MergeMeta => MERGE_META_FILE_EXTENSION,
64 Self::DataFile => DATA_FILE_EXTENSION,
65 Self::HintFile => HINT_FILE_EXTENSION,
66 Self::Unknown => panic!("get path for unknown data type"),
67 }
68 }
69}
70
71impl std::fmt::Display for FileType {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 match self {
74 FileType::Unknown => f.write_str("Unknown"),
75 FileType::LockFile => f.write_str("LockFile"),
76 FileType::MergeMeta => f.write_str("MergeMetaFile"),
77 FileType::DataFile => f.write_str("DataFile"),
78 FileType::HintFile => f.write_str("HintFile"),
79 }
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use utilities::common::get_temporary_directory_path;
87
88 #[test]
89 fn test_file_type() {
90 let dir = get_temporary_directory_path();
91
92 let p = FileType::LockFile.get_path(&dir, None);
93 assert!(FileType::LockFile.check_file_belongs_to_type(&p));
94 let p = FileType::HintFile.get_path(&dir, Some(123));
95 assert!(FileType::HintFile.check_file_belongs_to_type(&p));
96 let p = FileType::DataFile.get_path(&dir, Some(100));
97 assert!(FileType::DataFile.check_file_belongs_to_type(&p));
98 let p = FileType::MergeMeta.get_path(&dir, Some(100));
99 assert!(FileType::MergeMeta.check_file_belongs_to_type(&p));
100
101 assert!(!FileType::LockFile.check_file_belongs_to_type(&dir.join("")));
102 assert!(!FileType::DataFile.check_file_belongs_to_type(&dir.join("")));
103 assert!(!FileType::HintFile.check_file_belongs_to_type(&dir.join("")));
104 assert!(!FileType::MergeMeta.check_file_belongs_to_type(&dir.join("")));
105
106 assert!(!FileType::LockFile.check_file_belongs_to_type(&dir.join(".abc")));
107 assert!(!FileType::DataFile.check_file_belongs_to_type(&dir.join(".abc")));
108 assert!(!FileType::HintFile.check_file_belongs_to_type(&dir.join(".abc")));
109 assert!(!FileType::MergeMeta.check_file_belongs_to_type(&dir.join(".abc")));
110 }
111}