io_fs/runtimes/
std.rs

1//! The standard, blocking filesystem runtime.
2
3use std::{
4    collections::{HashMap, HashSet},
5    fs, io,
6    path::PathBuf,
7};
8
9use log::debug;
10
11use crate::io::FsIo;
12
13/// The standard, blocking filesystem runtime handler.
14///
15/// This handler makes use of standard modules [`std::fs`] and
16/// [`std::io`] to process [`FsIo`].
17pub fn handle(input: FsIo) -> io::Result<FsIo> {
18    match input {
19        FsIo::CreateDir(input) => create_dir(input),
20        FsIo::CreateDirs(input) => create_dirs(input),
21        FsIo::CreateFile(input) => create_file(input),
22        FsIo::CreateFiles(input) => create_files(input),
23        FsIo::ReadDir(input) => read_dir(input),
24        FsIo::ReadFile(input) => read_file(input),
25        FsIo::ReadFiles(input) => read_files(input),
26        FsIo::RemoveDir(input) => remove_dir(input),
27        FsIo::RemoveDirs(input) => remove_dirs(input),
28        FsIo::RemoveFile(input) => remove_file(input),
29        FsIo::RemoveFiles(input) => remove_files(input),
30        FsIo::Rename(input) => rename(input),
31    }
32}
33
34pub fn create_dir(input: Result<(), PathBuf>) -> io::Result<FsIo> {
35    let Err(path) = input else {
36        let kind = io::ErrorKind::InvalidInput;
37        return Err(io::Error::new(kind, "missing directory path"));
38    };
39
40    fs::create_dir(path)?;
41
42    Ok(FsIo::CreateDir(Ok(())))
43}
44
45pub fn create_dirs(input: Result<(), HashSet<PathBuf>>) -> io::Result<FsIo> {
46    let Err(paths) = input else {
47        let kind = io::ErrorKind::InvalidInput;
48        return Err(io::Error::new(kind, "missing directory paths"));
49    };
50
51    for path in paths {
52        fs::create_dir(path)?;
53    }
54
55    Ok(FsIo::CreateDirs(Ok(())))
56}
57
58pub fn create_file(input: Result<(), (PathBuf, Vec<u8>)>) -> io::Result<FsIo> {
59    let Err((path, contents)) = input else {
60        let kind = io::ErrorKind::InvalidInput;
61        return Err(io::Error::new(kind, "missing file contents"));
62    };
63
64    fs::write(path, contents)?;
65
66    Ok(FsIo::CreateFile(Ok(())))
67}
68
69pub fn create_files(input: Result<(), HashMap<PathBuf, Vec<u8>>>) -> io::Result<FsIo> {
70    let Err(contents) = input else {
71        let kind = io::ErrorKind::InvalidInput;
72        return Err(io::Error::new(kind, "missing file contents"));
73    };
74
75    for (path, contents) in contents {
76        fs::write(path, contents)?;
77    }
78
79    Ok(FsIo::CreateFiles(Ok(())))
80}
81
82pub fn read_dir(input: Result<HashSet<PathBuf>, PathBuf>) -> io::Result<FsIo> {
83    let Err(path) = input else {
84        let kind = io::ErrorKind::InvalidInput;
85        return Err(io::Error::new(kind, "missing directory path"));
86    };
87
88    let mut paths = HashSet::new();
89    let dir = fs::read_dir(path)?;
90
91    for entry in dir {
92        match entry {
93            Ok(entry) => {
94                paths.insert(entry.path());
95            }
96            Err(err) => {
97                debug!("ignore invalid directory entry: {err}");
98                continue;
99            }
100        };
101    }
102
103    Ok(FsIo::ReadDir(Ok(paths)))
104}
105
106pub fn read_file(input: Result<Vec<u8>, PathBuf>) -> io::Result<FsIo> {
107    let Err(path) = input else {
108        let kind = io::ErrorKind::InvalidInput;
109        return Err(io::Error::new(kind, "missing file path"));
110    };
111
112    let contents = fs::read(path)?;
113
114    Ok(FsIo::ReadFile(Ok(contents)))
115}
116
117pub fn read_files(input: Result<HashMap<PathBuf, Vec<u8>>, HashSet<PathBuf>>) -> io::Result<FsIo> {
118    let Err(paths) = input else {
119        let kind = io::ErrorKind::InvalidInput;
120        return Err(io::Error::new(kind, "missing file paths"));
121    };
122
123    let mut contents = HashMap::new();
124
125    for path in paths {
126        let content = fs::read(&path)?;
127        contents.insert(path, content);
128    }
129
130    Ok(FsIo::ReadFiles(Ok(contents)))
131}
132
133pub fn remove_dir(input: Result<(), PathBuf>) -> io::Result<FsIo> {
134    let Err(path) = input else {
135        let kind = io::ErrorKind::InvalidInput;
136        return Err(io::Error::new(kind, "missing directory path"));
137    };
138
139    fs::remove_dir_all(path)?;
140
141    Ok(FsIo::RemoveDir(Ok(())))
142}
143
144pub fn remove_dirs(input: Result<(), HashSet<PathBuf>>) -> io::Result<FsIo> {
145    let Err(paths) = input else {
146        let kind = io::ErrorKind::InvalidInput;
147        return Err(io::Error::new(kind, "missing directory paths"));
148    };
149
150    for path in paths {
151        fs::remove_dir_all(path)?;
152    }
153
154    Ok(FsIo::RemoveDirs(Ok(())))
155}
156
157pub fn remove_file(input: Result<(), PathBuf>) -> io::Result<FsIo> {
158    let Err(path) = input else {
159        let kind = io::ErrorKind::InvalidInput;
160        return Err(io::Error::new(kind, "missing file path"));
161    };
162
163    fs::remove_file(path)?;
164
165    Ok(FsIo::RemoveFile(Ok(())))
166}
167
168pub fn remove_files(input: Result<(), HashSet<PathBuf>>) -> io::Result<FsIo> {
169    let Err(paths) = input else {
170        let kind = io::ErrorKind::InvalidInput;
171        return Err(io::Error::new(kind, "missing file paths"));
172    };
173
174    for path in paths {
175        fs::remove_file(path)?;
176    }
177
178    Ok(FsIo::RemoveFiles(Ok(())))
179}
180
181pub fn rename(input: Result<(), Vec<(PathBuf, PathBuf)>>) -> io::Result<FsIo> {
182    let Err(paths) = input else {
183        let kind = io::ErrorKind::InvalidInput;
184        return Err(io::Error::new(kind, "missing file paths"));
185    };
186
187    for (from, to) in paths {
188        fs::rename(from, to)?;
189    }
190
191    Ok(FsIo::Rename(Ok(())))
192}