distant_protocol/common/
filesystem.rs

1use std::fs::FileType as StdFileType;
2use std::path::PathBuf;
3
4use derive_more::IsVariant;
5use serde::{Deserialize, Serialize};
6use strum::AsRefStr;
7
8/// Represents information about a single entry within a directory
9#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case", deny_unknown_fields)]
11pub struct DirEntry {
12    /// Represents the full path to the entry
13    pub path: PathBuf,
14
15    /// Represents the type of the entry as a file/dir/symlink
16    pub file_type: FileType,
17
18    /// Depth at which this entry was created relative to the root (0 being immediately within
19    /// root)
20    pub depth: usize,
21}
22
23/// Represents the type associated with a dir entry
24#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, AsRefStr, IsVariant, Serialize, Deserialize)]
25#[serde(rename_all = "snake_case", deny_unknown_fields)]
26#[strum(serialize_all = "snake_case")]
27pub enum FileType {
28    Dir,
29    File,
30    Symlink,
31}
32
33impl From<StdFileType> for FileType {
34    fn from(ft: StdFileType) -> Self {
35        if ft.is_dir() {
36            Self::Dir
37        } else if ft.is_symlink() {
38            Self::Symlink
39        } else {
40            Self::File
41        }
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    mod dir_entry {
50        use super::*;
51
52        #[test]
53        fn should_be_able_to_serialize_to_json() {
54            let entry = DirEntry {
55                path: PathBuf::from("dir").join("file"),
56                file_type: FileType::File,
57                depth: 1,
58            };
59
60            let path = entry.path.to_str().unwrap().to_string();
61            let value = serde_json::to_value(entry).unwrap();
62            assert_eq!(
63                value,
64                serde_json::json!({
65                    "path": path,
66                    "file_type": "file",
67                    "depth": 1,
68                })
69            );
70        }
71
72        #[test]
73        fn should_be_able_to_deserialize_from_json() {
74            let value = serde_json::json!({
75                "path": "test-file",
76                "file_type": "file",
77                "depth": 0,
78            });
79
80            let entry: DirEntry = serde_json::from_value(value).unwrap();
81            assert_eq!(
82                entry,
83                DirEntry {
84                    path: PathBuf::from("test-file"),
85                    file_type: FileType::File,
86                    depth: 0,
87                }
88            );
89        }
90
91        #[test]
92        fn should_be_able_to_serialize_to_msgpack() {
93            let entry = DirEntry {
94                path: PathBuf::from("dir").join("file"),
95                file_type: FileType::File,
96                depth: 1,
97            };
98
99            // NOTE: We don't actually check the output here because it's an implementation detail
100            // and could change as we change how serialization is done. This is merely to verify
101            // that we can serialize since there are times when serde fails to serialize at
102            // runtime.
103            let _ = rmp_serde::encode::to_vec_named(&entry).unwrap();
104        }
105
106        #[test]
107        fn should_be_able_to_deserialize_from_msgpack() {
108            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
109            // verify that we are not corrupting or causing issues when serializing on a
110            // client/server and then trying to deserialize on the other side. This has happened
111            // enough times with minor changes that we need tests to verify.
112            let buf = rmp_serde::encode::to_vec_named(&DirEntry {
113                path: PathBuf::from("test-file"),
114                file_type: FileType::File,
115                depth: 0,
116            })
117            .unwrap();
118
119            let entry: DirEntry = rmp_serde::decode::from_slice(&buf).unwrap();
120            assert_eq!(
121                entry,
122                DirEntry {
123                    path: PathBuf::from("test-file"),
124                    file_type: FileType::File,
125                    depth: 0,
126                }
127            );
128        }
129    }
130
131    mod file_type {
132        use super::*;
133
134        #[test]
135        fn should_be_able_to_serialize_to_json() {
136            let ty = FileType::File;
137
138            let value = serde_json::to_value(ty).unwrap();
139            assert_eq!(value, serde_json::json!("file"));
140        }
141
142        #[test]
143        fn should_be_able_to_deserialize_from_json() {
144            let value = serde_json::json!("file");
145
146            let ty: FileType = serde_json::from_value(value).unwrap();
147            assert_eq!(ty, FileType::File);
148        }
149
150        #[test]
151        fn should_be_able_to_serialize_to_msgpack() {
152            let ty = FileType::File;
153
154            // NOTE: We don't actually check the output here because it's an implementation detail
155            // and could change as we change how serialization is done. This is merely to verify
156            // that we can serialize since there are times when serde fails to serialize at
157            // runtime.
158            let _ = rmp_serde::encode::to_vec_named(&ty).unwrap();
159        }
160
161        #[test]
162        fn should_be_able_to_deserialize_from_msgpack() {
163            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
164            // verify that we are not corrupting or causing issues when serializing on a
165            // client/server and then trying to deserialize on the other side. This has happened
166            // enough times with minor changes that we need tests to verify.
167            let buf = rmp_serde::encode::to_vec_named(&FileType::File).unwrap();
168
169            let ty: FileType = rmp_serde::decode::from_slice(&buf).unwrap();
170            assert_eq!(ty, FileType::File);
171        }
172    }
173}