diary_cli/
list.rs

1use std::marker::PhantomData;
2
3use lazy_db::*;
4use soulog::*;
5
6pub fn write<T>(list: &[T], f: impl Fn(FileWrapper, &T) -> Result<(), LDBError>, container: &LazyContainer, mut logger: impl Logger) {
7    if_err!((logger) [ListIO, err => ("While clearing container: {err:?}")] retry container.wipe());
8
9    for (i, x) in list.iter().enumerate() {
10        let data_writer = 
11            if_err!((logger) [ListIO, err => ("While writing element of list: {:?}", err)] retry container.data_writer(i.to_string()));
12        if_err!((logger) [ListIO, err => ("While writing element of list: {:?}", err)] {f(data_writer, x)} crash {
13            log!((logger.error) ListIO("{err:#?}") as Fatal);
14            logger.crash()
15        })
16    }
17
18    if_err!((logger) [ListIO, err => ("{:?}", err)] retry {
19        let data_writer = if_err!((logger) [ListIO, err => ("While writing list length: {:?}", err)] retry container.data_writer("length"));
20        LazyData::new_u16(data_writer, list.len() as u16)
21    })
22}
23
24pub fn push(f: impl Fn(FileWrapper) -> Result<(), LDBError>, container: &LazyContainer, mut logger: impl Logger) {
25    let length = load_length(container, logger.hollow());
26
27    let data_writer = if_err!((logger) [ListIO, err => ("While pushing to list: {:?}", err)] retry container.data_writer(length.to_string()));
28    if_err!((logger) [ListIO, err => ("While pushing to list: {:?}", err)] {f(data_writer)} crash {
29        log!((logger.error) ListIO("{err:#?}") as Fatal);
30        logger.crash()
31    });
32
33    if_err!((logger) [ListIO, err => ("{:?}", err)] retry {
34        let data_writer = if_err!((logger) [ListIO, err => ("While writing list length: {:?}", err)] retry container.data_writer("length"));
35        LazyData::new_u16(data_writer, length + 1)
36    })
37}
38
39pub fn pop<T>(f: impl Fn(LazyData) -> Result<T, LDBError>, container: &LazyContainer, mut logger: impl Logger) -> Option<T> {
40    let length = load_length(container, logger.hollow());
41
42    if length == 0 {
43        return None;
44    }
45
46    let idx = (length - 1).to_string();
47    let item = if_err!((logger) [ListIO, err => ("While reading list element: {:?}", err)] retry container.read_data(&idx));
48    let item = if_err!((logger) [ListIO, err => ("While reading list element: {:?}", err)] {f(item)} crash {
49        log!((logger.error) ListIO("{err:#?}") as Fatal);
50        logger.crash()
51    });
52
53    if_err!((logger) {container.remove(idx)} else(err) {
54        log!((logger.vital) ListIO("While removing item: {err:?}; ignoring error...") as Inconvenience)
55    });
56
57    if_err!((logger) [ListIO, err => ("{:?}", err)] retry {
58        let data_writer = if_err!((logger) [ListIO, err => ("While writing list length: {:?}", err)] retry container.data_writer("length"));
59        LazyData::new_u16(data_writer, length - 1)
60    });
61
62    Some(item)
63}
64
65pub fn read<T>(f: impl Fn(LazyData) -> Result<T, LDBError>, container: &LazyContainer, mut logger: impl Logger) -> Box<[T]> {
66    let length = load_length(container, logger.hollow());
67
68    let mut list = Vec::<T>::with_capacity(length as usize);
69
70    for i in 0..length {
71        let item = if_err!((logger) [ListIO, err => ("While reading list element: {:?}", err)] retry container.read_data(i.to_string()));
72        let item = if_err!((logger) [ListIO, err => ("While reading list element: {:?}", err)] {f(item)} crash {
73            log!((logger.error) ListIO("{err:#?}") as Fatal);
74            logger.crash()
75        });
76        list.push(item)
77    }
78
79    list.into_boxed_slice()
80}
81
82pub fn load_length(container: &LazyContainer, mut logger: impl Logger) -> u16 {
83    let length = if_err!((logger) [ListIO, err => ("While reading list length: {:?}", err)] retry container.read_data("length"));
84    if_err!((logger) [ListIO, err => ("While reading list length: {:?}", err)] {length.collect_u16()} crash {
85        log!((logger.error) ListIO("{err:#?}") as Fatal);
86        logger.crash()
87    })
88}
89
90pub struct List<T, L: Logger, F: Fn(LazyData) -> Result<T, LDBError>> {
91    _phantom_marker: PhantomData<T>,
92    read_f: F,
93    container: LazyContainer,
94    logger: L,
95    length: u16,
96    idx: u16,
97}
98
99impl<T, L: Logger, F: Fn(LazyData) -> Result<T, LDBError>> List<T, L, F> {
100    pub fn init(container: LazyContainer, read_f: F, mut logger: L) -> Self {
101        if_err!((logger) [List, err => ("While inititalising list: {err:?}")] retry write_container!((container) length = new_u16(0)));
102        Self {
103            _phantom_marker: PhantomData,
104            container,
105            read_f,
106            logger: logger.hollow(),
107            length: 0,
108            idx: 0,
109        }
110    }
111
112    pub fn load(container: LazyContainer, read_f: F, mut logger: L) -> Self {
113        let length = if_err!((logger) [List, err => ("While loading list: {err:?}")] retry 
114            if_err!((logger) [List, err => ("While loading list: {err:?}")] retry
115                search_container!((container) length)
116            ).collect_u16()
117        );
118
119        Self {
120            _phantom_marker: PhantomData,
121            container,
122            read_f,
123            length,
124            logger: logger.hollow(),
125            idx: 0,
126        }
127    }
128}
129
130impl<T, L:Logger, F: Fn(LazyData) -> Result<T, LDBError>> Iterator for List<T, L, F> {
131    type Item = T;
132
133    fn next(&mut self) -> Option<T> {
134        if self.idx >= self.length { return None };
135        let mut logger = self.logger.hollow();
136        let f: &F = &self.read_f;
137
138        let item = if_err!((logger) [ListIO, err => ("While reading list element: {:?}", err)] retry self.container.read_data(self.idx.to_string()));
139        Some(if_err!((logger) [ListIO, err => ("While reading list element: {:?}", err)] {f(item)} crash {
140            log!((logger.error) ListIO("{err:#?}") as Fatal);
141            logger.crash()
142        }))
143    }
144}