rs_fsring/
lib.rs

1pub mod compose;
2pub mod del;
3pub mod empty;
4pub mod evt;
5pub mod full;
6pub mod integer;
7pub mod item;
8pub mod list;
9pub mod next;
10pub mod push;
11pub mod read;
12pub mod request;
13pub mod u;
14pub mod write;
15
16use crate::evt::Event;
17use crate::request::Request;
18
19use crate::item::{Item, Name};
20
21fn remove_item<R>(buf: &mut R, n: Name) -> Result<u64, Event>
22where
23    R: RingBuffer,
24{
25    let q: Request = Request::Del(n);
26    match buf.handle(q) {
27        Event::Success => Ok(1),
28        e => Err(e),
29    }
30}
31
32fn remove_broken_item<R>(buf: &mut R, n: Name) -> Result<u64, Event>
33where
34    R: RingBuffer,
35{
36    let q: Request = Request::Get(n);
37    match buf.handle(q) {
38        Event::Broken(broken_name) => remove_item(buf, broken_name),
39        _ => Ok(0),
40    }
41}
42
43fn remove_broken_items<R>(buf: &mut R, names: Vec<Name>) -> Result<u64, Event>
44where
45    R: RingBuffer,
46{
47    names.into_iter().try_fold(0, |tot, name| {
48        remove_broken_item(buf, name).map(|cnt: u64| cnt + tot)
49    })
50}
51
52fn remove_broken_items_from_list<R>(buf: &mut R) -> Result<u64, Event>
53where
54    R: RingBuffer,
55{
56    let q: Request = Request::List;
57    match buf.handle(q) {
58        Event::NamesGot(names) => remove_broken_items(buf, names),
59        e => Err(e),
60    }
61}
62
63/// Removes broken buffer items.
64///
65/// The buffer with checksum function required.
66pub fn remove_broken_buffers<R>(buf: &mut R) -> Event
67where
68    R: RingBuffer,
69{
70    remove_broken_items_from_list(buf)
71        .map(Event::BrokenItemsRemoved)
72        .unwrap_or_else(|e| {
73            Event::UnexpectedError(format!("Unable to remove broken items: {:#?}", e))
74        })
75}
76
77/// An interface for creating request handler.
78pub trait RingBuffer {
79    fn handle(&mut self, req: Request) -> Event;
80}
81
82/// Creates new request handler.
83pub fn ring_buffer_new<R>(mut r: R) -> impl FnMut(Request) -> Event
84where
85    R: RingBuffer,
86{
87    move |req: Request| r.handle(req)
88}
89
90/// Helper struct for creating request handler.
91pub struct FsRingBuffer<G, D, P, L> {
92    pub get: G,
93    pub del: D,
94    pub push: P,
95    pub list: L,
96}
97
98impl<G, D, P, L> FsRingBuffer<G, D, P, L>
99where
100    G: Fn(Name) -> Event,
101    D: Fn(Name) -> Event,
102    P: FnMut(Item) -> Event,
103    L: Fn() -> Event,
104{
105    fn handle_get(&mut self, name: Name) -> Event {
106        (self.get)(name)
107    }
108
109    fn handle_del(&mut self, name: Name) -> Event {
110        (self.del)(name)
111    }
112
113    fn handle_push(&mut self, item: Item) -> Event {
114        (self.push)(item)
115    }
116
117    fn handle_list(&mut self) -> Event {
118        (self.list)()
119    }
120}
121
122impl<G, D, P, L> RingBuffer for FsRingBuffer<G, D, P, L>
123where
124    G: Fn(Name) -> Event,
125    D: Fn(Name) -> Event,
126    P: FnMut(Item) -> Event,
127    L: Fn() -> Event,
128{
129    fn handle(&mut self, req: Request) -> Event {
130        match req {
131            Request::Get(name) => self.handle_get(name),
132            Request::Del(name) => self.handle_del(name),
133            Request::Push(item) => self.handle_push(item),
134            Request::List => self.handle_list(),
135            Request::Vacuum => remove_broken_buffers(self),
136        }
137    }
138}
139
140#[cfg(test)]
141mod test_lib {
142
143    mod remove_broken_buffers {
144        use std::fs;
145        use std::path::Path;
146
147        use crate::evt::Event;
148        use crate::request::Request;
149        use crate::u::buf::ring_buffer_u8_new_default;
150        use crate::u::buf::ring_buffer_u8_new_default_with_checksum;
151
152        #[test]
153        #[ignore]
154        fn test_without_checksum() {
155            let dirname = Path::new("./test.d/lib/remove_broken_buffers/test_without_checksum.d");
156            fs::remove_dir_all(&dirname).ok();
157            fs::create_dir_all(&dirname).unwrap();
158
159            let mut handler = ring_buffer_u8_new_default(&dirname).unwrap();
160            let filename = dirname.join("42");
161            fs::write(filename, b"cafef00ddeadbeafface864299792458").unwrap();
162            let q: Request = Request::Vacuum;
163            match handler(q) {
164                Event::BrokenItemsRemoved(cnt) => {
165                    assert_eq!(cnt, 0);
166                }
167                e => {
168                    panic!("Unexpected event: {:#?}", e)
169                }
170            }
171        }
172
173        #[test]
174        #[ignore]
175        fn test_invalid() {
176            let dirname = Path::new("./test.d/lib/remove_broken_buffers/test_invalid.d");
177            fs::remove_dir_all(&dirname).ok();
178            fs::create_dir_all(&dirname).unwrap();
179
180            let chk = |_: &[u8]| b"cafef00ddeadbeafface864299792458".to_vec();
181
182            let mut handler =
183                ring_buffer_u8_new_default_with_checksum(&dirname, 7, chk, chk).unwrap();
184            let filename = dirname.join("42");
185            fs::write(filename, b"cafef00ddeadbeafface864299792458").unwrap();
186            let q: Request = Request::Vacuum;
187            match handler(q) {
188                Event::BrokenItemsRemoved(cnt) => {
189                    assert_eq!(cnt, 1);
190                }
191                e => {
192                    panic!("Unexpected event: {:#?}", e)
193                }
194            }
195        }
196
197        #[test]
198        #[ignore]
199        fn test_valid() {
200            let dirname = Path::new("./test.d/lib/remove_broken_buffers/test_valid.d");
201            fs::remove_dir_all(&dirname).ok();
202            fs::create_dir_all(&dirname).unwrap();
203
204            let chk = |_: &[u8]| b"cafef00ddeadbeafface864299792458".to_vec();
205
206            let mut handler =
207                ring_buffer_u8_new_default_with_checksum(&dirname, 32, chk, chk).unwrap();
208            let filename = dirname.join("42");
209            fs::write(filename, b"ZZcafef00ddeadbeafface864299792458").unwrap();
210            let q: Request = Request::Vacuum;
211            match handler(q) {
212                Event::BrokenItemsRemoved(cnt) => {
213                    assert_eq!(cnt, 0);
214                }
215                e => {
216                    panic!("Unexpected event: {:#?}", e)
217                }
218            }
219        }
220    }
221}