1use std::io::{Read, Seek, Write};
6use std::path::Path;
7use std::sync::Arc;
8
9use crate::storage::Storage;
10
11#[derive(Debug)]
12pub enum Error {
13 OpenFile,
14 Overwrite(crate::overwrite::Error),
15 RemoveFile,
16}
17
18impl std::fmt::Display for Error {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 Error::OpenFile => f.write_str("Unable to open file"),
22 Error::Overwrite(inner) => write!(f, "Unable to overwrite file: {inner}"),
23 Error::RemoveFile => f.write_str("Unable to remove file"),
24 }
25 }
26}
27
28impl std::error::Error for Error {}
29
30pub struct Request<P: AsRef<Path>> {
31 pub path: P,
32 pub passes: i32,
33}
34
35pub fn execute<RW, P>(stor: Arc<impl Storage<RW> + 'static>, req: Request<P>) -> Result<(), Error>
36where
37 RW: Read + Write + Seek,
38 P: AsRef<Path>,
39{
40 let file = stor.write_file(req.path).map_err(|_| Error::OpenFile)?;
41 let buf_capacity = stor.file_len(&file).map_err(|_| Error::OpenFile)?;
42
43 crate::overwrite::execute(crate::overwrite::Request {
44 writer: file
45 .try_writer()
46 .expect("We're confident that we're in writing mode"),
47 buf_capacity,
48 passes: req.passes,
49 })
50 .map_err(Error::Overwrite)?;
51
52 stor.remove_file(file).map_err(|_| Error::RemoveFile)?;
53
54 Ok(())
55}
56
57#[cfg(test)]
58mod tests {
59 use std::path::PathBuf;
60
61 use crate::storage::InMemoryStorage;
62
63 use super::*;
64
65 #[test]
66 fn should_erase_file() {
67 let stor = Arc::new(InMemoryStorage::default());
68 stor.add_hello_txt();
69
70 let req = Request {
71 path: "hello.txt",
72 passes: 2,
73 };
74 match execute(stor.clone(), req) {
75 Ok(_) => assert_eq!(stor.files().get(&PathBuf::from("hello.txt")), None),
76 _ => unreachable!(),
77 }
78 }
79
80 #[test]
81 fn should_not_open_file() {
82 let stor = Arc::new(InMemoryStorage::default());
83
84 let req = Request {
85 path: "hello.txt",
86 passes: 2,
87 };
88 match execute(stor, req) {
89 Err(Error::OpenFile) => {}
90 _ => unreachable!(),
91 }
92 }
93}