1
use crate::{
2
    error::PRes,
3
    io::{read_u64, write_u64, InfallibleRead, InfallibleWrite, ReadFormat, WriteFormat},
4
};
5
use std::{
6
    cmp,
7
    fs::File,
8
    io::{self, Cursor, Read, Seek, SeekFrom, Write},
9
    sync::{Arc, Mutex},
10
};
11
pub const PAGE_METADATA_SIZE: u32 = 3;
12

13
pub trait UpdateList {
14
    fn update(&mut self, exp: u8, page: u64) -> PRes<u64>;
15
    fn remove(&mut self, exp: u8, page: u64, next: u64) -> PRes<()>;
16
}
17

18
pub trait Device: Sync + Send {
19
    fn load_page(&self, page: u64) -> PRes<ReadPage>;
20

21
    /// Load a page avoiding to skip base page metadata, used for root page or metadata
22
    /// manipulation.
23
    ///
24
    fn load_page_raw(&self, page: u64, size_exp: u8) -> PRes<Page>;
25

26
    fn flush_page(&self, page: &Page) -> PRes<()>;
27

28
    /// Create a page without setting metadata, used by root page
29
    fn create_page_raw(&self, exp: u8) -> PRes<u64>;
30

31
    fn create_page(&self, exp: u8) -> PRes<Page>;
32

33
    fn mark_allocated(&self, page: u64) -> PRes<u64>;
34

35
    fn sync(&self) -> PRes<()>;
36

37
    fn trim_or_free_page(&self, page: u64, update_list: &mut dyn UpdateList) -> PRes<()>;
38

39
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()>;
40
}
41

42
trait SizeTool {
43
    fn len(&self) -> PRes<u64>;
44
    fn set_len(&mut self, len: u64) -> PRes<()>;
45
}
46

47
impl SizeTool for File {
48 1
    fn len(&self) -> PRes<u64> {
49 1
        Ok(self.metadata()?.len())
50 1
    }
51
    fn set_len(&mut self, len: u64) -> PRes<()> {
52
        Ok(File::set_len(self, len)?)
53
    }
54
}
55

56
impl SizeTool for Cursor<Vec<u8>> {
57 1
    fn len(&self) -> PRes<u64> {
58 1
        Ok(self.get_ref().len() as u64)
59 1
    }
60 1
    fn set_len(&mut self, len: u64) -> PRes<()> {
61 1
        self.get_mut().resize(len as usize, 0);
62 1
        Ok(())
63 1
    }
64
}
65

66
pub struct ReadPage {
67
    buff: Arc<Vec<u8>>,
68
    index: u64,
69
    exp: u8,
70
    pos: usize,
71
}
72
impl ReadPage {
73 1
    pub fn new(buff: Arc<Vec<u8>>, pos: usize, index: u64, exp: u8) -> ReadPage {
74 1
        ReadPage { buff, index, exp, pos }
75 1
    }
76
}
77

78
impl ReadPage {
79 1
    pub fn get_size_exp(&mut self) -> u8 {
80 1
        self.exp
81 1
    }
82

83 1
    pub fn slice(&self, len: usize) -> &[u8] {
84 1
        let final_len = self.pos + len;
85 1
        debug_assert!(final_len < self.buff.len() - 1);
86 1
        &self.buff[self.pos..final_len]
87 1
    }
88
}
89

90
impl Read for ReadPage {
91 1
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
92 1
        let len = self.buff.len() - 1;
93 1
        let amt = cmp::min(self.pos, len);
94 1
        let read = Read::read(&mut &self.buff[(amt as usize)..len], buf)?;
95 1
        self.pos += read;
96 1
        Ok(read)
97 1
    }
98
}
99
impl InfallibleRead for ReadPage {
100 1
    fn read_exact(&mut self, buf: &mut [u8]) {
101 1
        Read::read_exact(self, buf).expect("in memory buff never fail");
102 1
    }
103
}
104

105
impl PageOps for ReadPage {
106 1
    fn seek(&mut self, pos: u32) -> PRes<()> {
107 1
        self.pos = (pos + 2) as usize;
108 1
        Ok(())
109 1
    }
110
    fn get_index(&self) -> u64 {
111
        self.index
112
    }
113 1
    fn get_size_exp(&self) -> u8 {
114 1
        self.exp
115 1
    }
116 1
    fn clone_read(&self) -> ReadPage {
117 1
        ReadPage::new(self.buff.clone(), 2, self.index, self.exp)
118 1
    }
119 1
    fn clone_write(&self) -> Page {
120 1
        Page::new(self.buff.as_ref().clone(), 2, self.index, self.exp)
121 1
    }
122 1
    fn is_free(&self) -> PRes<bool> {
123 1
        Ok((self.buff[1] & 0b1000_0000) != 0)
124 1
    }
125 1
    fn cursor_pos(&self) -> usize {
126 1
        if self.pos >= 2 {
127 1
            self.pos - 2
128
        } else {
129 0
            0
130
        }
131 1
    }
132
}
133

134 1
#[derive(Clone)]
135
pub struct Page {
136 1
    buff: Vec<u8>,
137 1
    index: u64,
138 1
    exp: u8,
139 1
    pos: usize,
140
}
141

142
pub trait PageOps {
143
    fn seek(&mut self, pos: u32) -> PRes<()>;
144
    fn get_index(&self) -> u64;
145
    fn get_size_exp(&self) -> u8;
146
    fn clone_read(&self) -> ReadPage;
147
    fn clone_write(&self) -> Page;
148
    fn is_free(&self) -> PRes<bool>;
149
    fn cursor_pos(&self) -> usize;
150
}
151

152 1
fn free_flag_set(mut cur: u8, free: bool) -> u8 {
153 1
    if free {
154 1
        cur |= 0b1000_0000;
155
    } else {
156 1
        cur &= !0b1000_0000;
157
    }
158 1
    cur
159 1
}
160 1
fn is_free(cur: u8) -> bool {
161 1
    cur & 0b1000_0000 != 0
162 1
}
163
impl Page {
164 1
    pub fn new(buff: Vec<u8>, pos: usize, index: u64, exp: u8) -> Page {
165 1
        Page { buff, index, exp, pos }
166 1
    }
167
    pub fn clone_resetted(&self) -> Page {
168
        let mut page = self.clone();
169
        page.pos = 2;
170
        page
171
    }
172
}
173

174
impl Read for Page {
175 1
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
176 1
        let len = self.buff.len() - 1;
177 1
        let amt = cmp::min(self.pos, len);
178 1
        let read = Read::read(&mut &self.buff[(amt as usize)..len], buf)?;
179 1
        self.pos += read;
180 1
        Ok(read)
181 1
    }
182
}
183

184
impl InfallibleRead for Page {
185 1
    fn read_exact(&mut self, buf: &mut [u8]) {
186 1
        Read::read_exact(self, buf).expect("in memory buff never fail");
187 1
    }
188
}
189

190
impl Write for Page {
191 1
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
192 1
        let pre = self.pos;
193 1
        let len = self.buff.len() - 1;
194 1
        if pre + (*buf).len() > len {
195 0
            panic!(
196 0
                "Over page allowed content size:{}, data size: {}",
197
                len,
198 0
                pre + (*buf).len()
199
            );
200
        }
201 1
        let pos = cmp::min(self.pos, len);
202 1
        let amt = (&mut self.buff[(pos as usize)..len]).write(buf)?;
203 1
        self.pos += amt;
204 1
        Ok(amt)
205 1
    }
206

207
    fn flush(&mut self) -> io::Result<()> {
208
        self.buff.flush()
209
    }
210
}
211
impl InfallibleWrite for Page {
212 1
    fn write_all(&mut self, buf: &[u8]) {
213 1
        Write::write_all(self, buf).expect("in memory write should never fail")
214 1
    }
215
}
216

217
impl PageOps for Page {
218 1
    fn seek(&mut self, pos: u32) -> PRes<()> {
219 1
        self.pos = (pos + 2) as usize;
220 1
        Ok(())
221 1
    }
222 1
    fn get_index(&self) -> u64 {
223 1
        self.index
224 1
    }
225 1
    fn get_size_exp(&self) -> u8 {
226 1
        self.exp
227 1
    }
228
    fn clone_read(&self) -> ReadPage {
229
        ReadPage::new(Arc::new(self.buff.clone()), 2, self.index, self.exp)
230
    }
231
    fn clone_write(&self) -> Page {
232
        self.clone_resetted()
233
    }
234 1
    fn is_free(&self) -> PRes<bool> {
235 1
        Ok(is_free(self.buff[1]))
236 1
    }
237
    fn cursor_pos(&self) -> usize {
238
        if self.pos >= 2 {
239
            self.pos - 2
240
        } else {
241
            0
242
        }
243
    }
244
}
245

246
impl Page {
247 1
    pub fn set_free(&mut self, free: bool) -> PRes<()> {
248 1
        self.buff[1] = free_flag_set(self.buff[1], free);
249 1
        Ok(())
250 1
    }
251

252 1
    pub fn set_next_free(&mut self, next: u64) -> PRes<()> {
253 1
        let pre = self.pos;
254 1
        self.pos = 2;
255 1
        self.write_u64(next)?;
256 1
        self.pos = pre;
257 1
        Ok(())
258 1
    }
259

260 1
    pub fn get_next_free(&mut self) -> PRes<u64> {
261 1
        let pre = self.pos;
262 1
        self.pos = 2;
263 1
        let val = self.read_u64()?;
264 1
        self.pos = pre;
265 1
        Ok(val)
266 1
    }
267

268 1
    pub fn reset(&mut self) -> PRes<()> {
269 1
        self.buff = vec![0; self.buff.len()];
270 1
        self.buff[0] = self.exp;
271 1
        Ok(())
272 1
    }
273

274 1
    pub fn make_read(self) -> ReadPage {
275 1
        ReadPage::new(Arc::new(self.buff), 2, self.index, self.exp)
276 1
    }
277
}
278

279 1
fn load_page<T: Read + Seek>(fl: &mut T, page: u64) -> PRes<ReadPage> {
280
    // add 2 to skip the metadata
281 1
    fl.seek(SeekFrom::Start(page))?;
282 1
    let exp = fl.read_u8()?;
283 1
    let size = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
284 1
    let mut ve = vec![0 as u8; size as usize];
285 1
    ve[0] = exp;
286 1
    fl.read_exact(&mut ve[1..size as usize])?;
287 1
    Ok(ReadPage::new(Arc::new(ve), 2, page, exp))
288 1
}
289

290 1
fn create_page_raw<T: SizeTool + Seek>(fl: &mut T, exp: u8) -> PRes<u64> {
291 1
    let offset = fl.seek(SeekFrom::End(0))?;
292 1
    let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
293 1
    fl.set_len(offset + size)?;
294 1
    Ok(offset)
295 1
}
296

297 1
fn load_page_raw<T: Read + Seek>(fl: &mut T, page: u64, size_exp: u8) -> PRes<Page> {
298 1
    let mut ve;
299
    let size;
300
    {
301 1
        fl.seek(SeekFrom::Start(page))?;
302 1
        size = (1 << size_exp) as u64; //EXP - (size_exp+size_mitigator);
303 1
        ve = vec![0 as u8; size as usize];
304 1
        fl.read_exact(&mut ve[0..size as usize])?;
305
    }
306 1
    Ok(Page::new(ve, 0, page, size_exp))
307 1
}
308

309 1
fn flush_page<T: Write + Seek>(fl: &mut T, page: &Page) -> PRes<()> {
310 1
    fl.seek(SeekFrom::Start(page.index))?;
311 1
    fl.write_all(&page.buff)?;
312 1
    Ok(())
313 1
}
314

315 1
fn create_page<T: Write + Seek>(fl: &mut T, exp: u8) -> PRes<Page> {
316 1
    let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
317 1
    let mut ve = vec![0 as u8; size as usize];
318 1
    ve[0] = exp;
319 1
    ve[size as usize - 1] = exp;
320 1
    let offset = fl.seek(SeekFrom::End(0))?;
321 1
    fl.write_all(&ve)?; //exp
322 1
    Ok(Page::new(ve, 2, offset, exp))
323 1
}
324

325 0
fn mark_allocated<T: Write + Read + Seek>(fl: &mut T, page: u64) -> PRes<u64> {
326 0
    fl.seek(SeekFrom::Start(page + 2))?;
327
    // Free pages are a linked list reading the next page and return
328 0
    let next = fl.read_u64()?;
329 0
    fl.seek(SeekFrom::Start(page + 1))?;
330 0
    let mut moderator = fl.read_u8()?;
331 0
    moderator = free_flag_set(moderator, false);
332 0
    fl.seek(SeekFrom::Start(page + 1))?;
333 0
    fl.write_u8(moderator)?;
334 0
    Ok(next)
335 0
}
336

337 1
fn trim_or_free_page<T: Write + Read + Seek + SizeTool>(
338
    fl: &mut T,
339
    page: u64,
340
    update_list: &mut dyn UpdateList,
341
) -> PRes<()> {
342 1
    fl.seek(SeekFrom::Start(page))?;
343 1
    let exp = fl.read_u8()?;
344 1
    let size = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
345 1
    if page + size == fl.len()? {
346 1
        fl.set_len(page)?;
347 1
        while check_and_trim(fl, update_list)? {}
348
    } else {
349 1
        let old = update_list.update(exp, page)?;
350 1
        fl.seek(SeekFrom::Start(page + 1))?;
351 1
        let mut mitigator = fl.read_u8()?;
352 1
        debug_assert!(!is_free(mitigator), "freeing: {} already freed ", page);
353 1
        mitigator = free_flag_set(mitigator, true);
354 1
        let mut data: [u8; 9] = [0; 9];
355 1
        data[0] = mitigator;
356 1
        write_u64(&mut data[1..9], old);
357 1
        fl.seek(SeekFrom::Start(page + 1))?;
358 1
        fl.write_all(&data)?;
359 1
        if exp >= 5 {
360 1
            fl.write_all(&[0u8; 16])?;
361
        }
362

363 1
        let mut data = [0; 8];
364 1
        write_u64(&mut data, page);
365 1
        fl.seek(SeekFrom::Start(old + 9))?;
366 1
        fl.write_all(&data)?;
367
    }
368 1
    Ok(())
369 1
}
370

371 1
fn check_and_trim<T: Write + Read + Seek + SizeTool>(fl: &mut T, update_list: &mut dyn UpdateList) -> PRes<bool> {
372 1
    let len = fl.seek(SeekFrom::End(0))?;
373 1
    if len == 0 {
374 1
        return Ok(false);
375
    }
376

377 1
    fl.seek(SeekFrom::Start(len - 1))?;
378 1
    let exp = fl.read_u8()?;
379 1
    if exp == 0 {
380 0
        return Ok(false);
381
    }
382 1
    let size = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
383 1
    let mut header = [0u8; 18];
384 1
    let page = len - size;
385 1
    if page == 0 {
386 1
        return Ok(false);
387
    }
388 1
    fl.seek(SeekFrom::Start(page + 1))?;
389 1
    fl.read_exact(&mut header)?;
390 1
    if is_free(header[0]) {
391 1
        let next = read_u64(&header[2..10]);
392 1
        let prev = read_u64(&header[10..18]);
393 1
        if prev == 0 {
394 1
            update_list.remove(exp, page, next)?;
395
        } else {
396 0
            let mut data = [8u8];
397 0
            write_u64(&mut data, next);
398 0
            fl.seek(SeekFrom::Start(prev + 10))?;
399 0
            fl.write_all(&data)?;
400 0
            write_u64(&mut data, prev);
401 0
            fl.seek(SeekFrom::Start(next + 2))?;
402 0
            fl.write_all(&data)?;
403
        }
404 1
        fl.set_len(page)?;
405 1
        Ok(true)
406
    } else {
407 0
        Ok(false)
408
    }
409 1
}
410

411
#[cfg(unix)]
412
pub struct DiscRef {
413
    file: File,
414
    size: Mutex<u64>,
415
}
416

417
#[cfg(unix)]
418
impl DiscRef {
419 1
    pub fn new(file: File) -> PRes<DiscRef> {
420 1
        let len = file.len()?;
421 1
        Ok(DiscRef {
422 1
            file,
423 1
            size: Mutex::new(len),
424 0
        })
425 1
    }
426

427 1
    fn create_page_offset(&self, size: u64) -> PRes<u64> {
428 1
        let mut current = self.size.lock()?;
429 1
        let page = *current;
430 1
        *current += size;
431 1
        return Ok(page);
432 1
    }
433 1
    fn trim_if_possible(&self, page: u64, size: u64) -> PRes<bool> {
434 1
        let mut current = self.size.lock()?;
435 1
        if page + size == *current {
436 1
            *current = page;
437 1
            self.file.set_len(page)?;
438 1
            Ok(true)
439
        } else {
440 1
            Ok(false)
441
        }
442 1
    }
443

444 1
    fn check_and_trim(&self, update_list: &mut dyn UpdateList) -> PRes<bool> {
445
        use std::os::unix::prelude::FileExt;
446 1
        let mut lock = self.size.lock()?;
447 1
        let value = *lock;
448 1
        if value == 0 {
449 1
            return Ok(false);
450
        }
451 1
        let mut exp = [0u8];
452 1
        self.file.read_exact_at(&mut exp, value - 1)?;
453 1
        if exp[0] == 0 {
454 0
            return Ok(false);
455
        }
456 1
        let size = (1 << exp[0]) as u64; //EXP - (size_exp+size_mitigator);
457 1
        let mut header = [0u8; 18];
458 1
        let page = value - size;
459 1
        if page == 0 {
460 1
            return Ok(false);
461
        }
462 1
        self.file.read_exact_at(&mut header, page + 1)?;
463 1
        if is_free(header[0]) {
464 1
            let next = read_u64(&header[2..10]);
465 1
            let prev = read_u64(&header[10..18]);
466 1
            if prev == 0 {
467 1
                update_list.remove(exp[0], page, next)?;
468
            } else {
469 0
                let mut data = [8u8];
470 0
                write_u64(&mut data, next);
471 0
                self.file.write_all_at(&data, prev + 10)?;
472 0
                write_u64(&mut data, prev);
473 0
                self.file.write_all_at(&data, next + 2)?;
474
            }
475 1
            *lock = page;
476 1
            self.file.set_len(page)?;
477 1
            Ok(true)
478
        } else {
479 1
            Ok(false)
480
        }
481 1
    }
482
}
483

484
#[cfg(unix)]
485
impl Device for DiscRef {
486 1
    fn load_page(&self, page: u64) -> PRes<ReadPage> {
487
        use std::os::unix::prelude::FileExt;
488 1
        let mut exp = [0u8];
489 1
        self.file.read_exact_at(&mut exp, page)?;
490 1
        let size = (1 << exp[0]) as u64; //EXP - (size_exp+size_mitigator);
491 1
        let mut ve = vec![0 as u8; size as usize];
492 1
        ve[0] = exp[0];
493 1
        self.file.read_exact_at(&mut ve[1..size as usize], page + 1)?;
494
        // add 2 to skip the metadata
495 1
        Ok(ReadPage::new(Arc::new(ve), 2, page, exp[0]))
496 1
    }
497

498 1
    fn load_page_raw(&self, page: u64, size_exp: u8) -> PRes<Page> {
499
        use std::os::unix::prelude::FileExt;
500 1
        let size = (1 << size_exp) as u64; //EXP - (size_exp+size_mitigator);
501 1
        let mut ve = vec![0 as u8; size as usize];
502 1
        self.file.read_exact_at(&mut ve, page)?;
503 1
        Ok(Page::new(ve, 0, page, size_exp))
504 1
    }
505

506 1
    fn flush_page(&self, page: &Page) -> PRes<()> {
507
        use std::os::unix::prelude::FileExt;
508 1
        self.file.write_all_at(&page.buff, page.get_index())?;
509 1
        Ok(())
510 1
    }
511

512 1
    fn create_page_raw(&self, exp: u8) -> PRes<u64> {
513
        use std::os::unix::prelude::FileExt;
514 1
        let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
515 1
        let offset = self.create_page_offset(size)?;
516 1
        let mut ve = [0u8];
517 1
        ve[0] = exp;
518 1
        self.file.write_all_at(&ve, offset + size - 1)?; //exp
519 1
        Ok(offset)
520 1
    }
521

522 1
    fn create_page(&self, exp: u8) -> PRes<Page> {
523
        use std::os::unix::prelude::FileExt;
524 1
        let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
525 1
        let offset = self.create_page_offset(size)?;
526 1
        let mut ve = vec![0 as u8; size as usize];
527 1
        ve[0] = exp;
528 1
        ve[size as usize - 1] = exp;
529 1
        self.file.write_all_at(&ve, offset)?; //exp
530 1
        Ok(Page::new(ve, 2, offset, exp))
531 1
    }
532

533 1
    fn mark_allocated(&self, page: u64) -> PRes<u64> {
534
        use std::os::unix::prelude::FileExt;
535 1
        let mut next_data = [0u8; 8];
536 1
        self.file.read_exact_at(&mut next_data, page + 2)?;
537
        // Free pages are a linked list reading the next page and return
538 1
        let mut mitigator = [0u8];
539 1
        self.file.read_exact_at(&mut mitigator, page + 1)?;
540 1
        mitigator[0] = free_flag_set(mitigator[0], false);
541 1
        self.file.write_all_at(&mitigator, page + 1)?;
542 1
        Ok(read_u64(&next_data))
543 1
    }
544

545 1
    fn sync(&self) -> PRes<()> {
546 1
        self.file.sync_data()?;
547 1
        Ok(())
548 1
    }
549

550 1
    fn trim_or_free_page(&self, page: u64, update_list: &mut dyn UpdateList) -> PRes<()> {
551
        use std::os::unix::prelude::FileExt;
552 1
        let mut exp = [0u8];
553 1
        self.file.read_exact_at(&mut exp, page)?;
554 1
        let size = (1 << exp[0]) as u64; //EXP - (size_exp+size_mitigator);
555 1
        if !self.trim_if_possible(page, size)? {
556 1
            let old = update_list.update(exp[0], page)?;
557 1
            let mut mitigator = [0u8];
558 1
            self.file.read_exact_at(&mut mitigator, page + 1)?;
559 1
            debug_assert!(!is_free(mitigator[0]), "freeing: {} already freed ", page);
560 1
            mitigator[0] = free_flag_set(mitigator[0], true);
561 1
            let mut data: [u8; 9] = [0; 9];
562 1
            data[0] = mitigator[0];
563 1
            write_u64(&mut data[1..9], old);
564 1
            self.file.write_all_at(&data, page + 1)?;
565 1
            if exp[0] >= 5 {
566 1
                self.file.write_all_at(&[0u8; 16], page + 10)?;
567
            }
568
        } else {
569 1
            self.trim_end_pages(update_list)?;
570
        }
571 1
        Ok(())
572 1
    }
573

574 1
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()> {
575 1
        while self.check_and_trim(update_list)? {}
576 1
        Ok(())
577 1
    }
578
}
579

580
#[cfg(not(unix))]
581
pub struct FileHandler {
582
    file: File,
583
    metadata_changed: bool,
584
}
585

586
#[cfg(not(unix))]
587
pub struct DiscRef {
588
    file: Mutex<FileHandler>,
589
}
590

591
#[cfg(not(unix))]
592
impl DiscRef {
593
    pub fn new(file: File) -> PRes<DiscRef> {
594
        Ok(DiscRef {
595
            file: Mutex::new(FileHandler {
596
                file,
597
                metadata_changed: false,
598
            }),
599
        })
600
    }
601
}
602

603
#[cfg(not(unix))]
604
impl Device for DiscRef {
605
    fn load_page(&self, page: u64) -> PRes<ReadPage> {
606
        load_page(&mut self.file.lock()?.file, page)
607
    }
608

609
    fn load_page_raw(&self, page: u64, size_exp: u8) -> PRes<Page> {
610
        load_page_raw(&mut self.file.lock()?.file, page, size_exp)
611
    }
612

613
    fn flush_page(&self, page: &Page) -> PRes<()> {
614
        flush_page(&mut self.file.lock()?.file, page)
615
    }
616

617
    fn create_page_raw(&self, exp: u8) -> PRes<u64> {
618
        let lock = &mut self.file.lock()?;
619
        lock.metadata_changed = true;
620
        create_page_raw(&mut lock.file, exp)
621
    }
622

623
    fn create_page(&self, exp: u8) -> PRes<Page> {
624
        let lock = &mut self.file.lock()?;
625
        lock.metadata_changed = true;
626
        create_page(&mut lock.file, exp)
627
    }
628

629
    fn mark_allocated(&self, page: u64) -> PRes<u64> {
630
        mark_allocated(&mut self.file.lock()?.file, page)
631
    }
632

633
    fn sync(&self) -> PRes<()> {
634
        let to_sync;
635
        let metadata_changed;
636
        {
637
            let mut lock = self.file.lock()?;
638
            to_sync = lock.file.try_clone()?;
639
            metadata_changed = lock.metadata_changed;
640
            lock.metadata_changed = false;
641
        }
642
        if metadata_changed {
643
            to_sync.sync_all()?;
644
        } else {
645
            to_sync.sync_data()?;
646
        }
647
        Ok(())
648
    }
649

650
    fn trim_or_free_page(&self, page: u64, update_list: &mut dyn UpdateList) -> PRes<()> {
651
        trim_or_free_page(&mut self.file.lock()?.file, page, update_list)
652
    }
653

654
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()> {
655
        while check_and_trim(&mut self.file.lock()?.file, update_list)? {}
656
        Ok(())
657
    }
658
}
659

660
pub struct MemRef {
661
    data: Mutex<Cursor<Vec<u8>>>,
662
}
663
impl MemRef {
664 1
    pub fn new() -> PRes<MemRef> {
665 1
        Ok(MemRef {
666 1
            data: Mutex::new(Cursor::new(Vec::new())),
667
        })
668 1
    }
669
}
670

671
impl Device for MemRef {
672 1
    fn load_page(&self, page: u64) -> PRes<ReadPage> {
673 1
        load_page(&mut *self.data.lock()?, page)
674 1
    }
675

676 1
    fn load_page_raw(&self, page: u64, size_exp: u8) -> PRes<Page> {
677 1
        load_page_raw(&mut *self.data.lock()?, page, size_exp)
678 1
    }
679

680 1
    fn flush_page(&self, page: &Page) -> PRes<()> {
681 1
        flush_page(&mut *self.data.lock()?, page)
682 1
    }
683

684 1
    fn create_page_raw(&self, exp: u8) -> PRes<u64> {
685 1
        create_page_raw(&mut *self.data.lock()?, exp)
686 1
    }
687

688 1
    fn create_page(&self, exp: u8) -> PRes<Page> {
689 1
        create_page(&mut *self.data.lock()?, exp)
690 1
    }
691

692 0
    fn mark_allocated(&self, page: u64) -> PRes<u64> {
693 0
        mark_allocated(&mut *self.data.lock()?, page)
694 0
    }
695

696 1
    fn sync(&self) -> PRes<()> {
697 1
        Ok(())
698 1
    }
699

700 1
    fn trim_or_free_page(&self, page: u64, update_list: &mut dyn UpdateList) -> PRes<()> {
701 1
        trim_or_free_page(&mut *self.data.lock()?, page, update_list)
702 1
    }
703 0
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()> {
704 0
        while check_and_trim(&mut *self.data.lock()?, update_list)? {}
705 0
        Ok(())
706 0
    }
707
}
708
#[cfg(test)]
709
mod tests {
710
    use super::{Device, DiscRef, MemRef, PageOps, UpdateList};
711
    use crate::error::PRes;
712
    use byteorder::{ReadBytesExt, WriteBytesExt};
713
    use tempfile::Builder;
714

715 1
    fn temp_disc_ref(name: &str) -> DiscRef {
716 1
        DiscRef::new(
717 1
            Builder::new()
718
                .prefix(name)
719
                .suffix(".persy")
720
                .tempfile()
721
                .unwrap()
722
                .reopen()
723
                .unwrap(),
724
        )
725
        .unwrap()
726 1
    }
727

728 1
    fn create_load_flush_page_device(device: &mut dyn Device) {
729 1
        let page = device.create_page(5).unwrap().get_index();
730 1
        let pg = device.load_page(page).unwrap();
731 1
        device.flush_page(&mut pg.clone_write()).unwrap();
732 1
    }
733

734 1
    fn set_get_next_free_device(device: &mut dyn Device) {
735 1
        let page = device.create_page(5).unwrap().get_index();
736 1
        let pg = &mut device.load_page(page).unwrap().clone_write();
737 1
        pg.set_next_free(30).unwrap();
738 1
        device.flush_page(pg).unwrap();
739 1
        let pg1 = &mut device.load_page(page).unwrap().clone_write();
740 1
        let val = pg1.get_next_free().unwrap();
741 1
        assert_eq!(val, 30);
742 1
    }
743

744 1
    fn get_size_page_device(device: &mut dyn Device) {
745 1
        let page = device.create_page(5).unwrap().get_index();
746 1
        let pg = &mut device.load_page(page).unwrap();
747 1
        let sz = pg.get_size_exp();
748 1
        assert_eq!(sz, 5);
749 1
    }
750

751 1
    fn write_read_page_device(device: &mut dyn Device) {
752 1
        let page = device.create_page(5).unwrap().get_index();
753
        {
754 1
            let pg = &mut device.load_page(page).unwrap().clone_write();
755 1
            pg.write_u8(10).unwrap();
756 1
            device.flush_page(pg).unwrap();
757 1
        }
758
        {
759 1
            let pg = &mut device.load_page(page).unwrap();
760 1
            let va = pg.read_u8().unwrap();
761 1
            assert_eq!(va, 10);
762 1
            let sz = pg.get_size_exp();
763 1
            assert_eq!(sz, 5);
764 1
        }
765 1
    }
766

767
    struct PanicCase {}
768
    impl UpdateList for PanicCase {
769 0
        fn update(&mut self, _: u8, _: u64) -> PRes<u64> {
770 0
            panic!("should not put the free in the free list")
771
        }
772 0
        fn remove(&mut self, _: u8, _: u64, _: u64) -> PRes<()> {
773 0
            panic!("should not put the free in the free list")
774
        }
775
    }
776

777 1
    fn create_load_trim_device(device: &mut dyn Device) {
778 1
        let page = device.create_page(5).unwrap().get_index();
779 1
        let pg = &mut device.load_page(page).unwrap().clone_write();
780 1
        device.flush_page(pg).unwrap();
781 1
        device.trim_or_free_page(page, &mut PanicCase {}).unwrap();
782 1
        assert!(device.load_page(page).is_err());
783 1
    }
784

785 1
    fn create_load_two_trim_device(device: &mut dyn Device) {
786 1
        let _not_free = device.create_page(5).unwrap().get_index();
787 1
        let page = device.create_page(5).unwrap().get_index();
788 1
        let pg = &mut device.load_page(page).unwrap().clone_write();
789 1
        device.flush_page(pg).unwrap();
790 1
        let page_1 = device.create_page(5).unwrap().get_index();
791 1
        let pg = &mut device.load_page(page_1).unwrap().clone_write();
792 1
        device.flush_page(pg).unwrap();
793 1
        device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
794 1
        device.trim_or_free_page(page_1, &mut IgnoreCase {}).unwrap();
795 1
        assert!(device.load_page(page).is_err());
796 1
    }
797

798
    struct IgnoreCase {}
799
    impl UpdateList for IgnoreCase {
800 1
        fn update(&mut self, _: u8, _: u64) -> PRes<u64> {
801 1
            Ok(0)
802 1
        }
803 1
        fn remove(&mut self, _: u8, _: u64, _: u64) -> PRes<()> {
804 1
            Ok(())
805 1
        }
806
    }
807

808 1
    fn create_not_trim_not_last_device(device: &mut dyn Device) {
809 1
        let page = device.create_page(5).unwrap().get_index();
810 1
        let _page_after = device.create_page(5).unwrap();
811 1
        let pg = &mut device.load_page(page).unwrap().clone_write();
812 1
        device.flush_page(pg).unwrap();
813 1
        device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
814 1
        let load_page = device.load_page(page);
815 1
        assert!(load_page.is_ok());
816 1
        assert!(load_page.unwrap().is_free().unwrap());
817 1
    }
818

819
    #[test]
820 1
    fn create_load_flush_page_disc() {
821 1
        create_load_flush_page_device(&mut temp_disc_ref("disc_ref.raw"));
822 1
    }
823

824
    #[test]
825 1
    fn create_load_flush_page_memory() {
826 1
        create_load_flush_page_device(&mut MemRef::new().unwrap());
827 1
    }
828

829
    #[test]
830 1
    fn set_get_next_free_disc() {
831 1
        set_get_next_free_device(&mut temp_disc_ref("set_free.raw"));
832 1
    }
833

834
    #[test]
835 1
    fn set_get_next_free_memory() {
836 1
        set_get_next_free_device(&mut MemRef::new().unwrap());
837 1
    }
838

839
    #[test]
840 1
    fn get_size_page_disc() {
841 1
        get_size_page_device(&mut temp_disc_ref("get_size.raw"));
842 1
    }
843
    #[test]
844 1
    fn get_size_page_memory() {
845 1
        get_size_page_device(&mut MemRef::new().unwrap());
846 1
    }
847

848
    #[test]
849 1
    fn write_read_page_disc() {
850 1
        write_read_page_device(&mut temp_disc_ref("write_read.raw"));
851 1
    }
852
    #[test]
853 1
    fn write_read_page_memory() {
854 1
        write_read_page_device(&mut MemRef::new().unwrap());
855 1
    }
856

857
    #[test]
858 1
    fn create_load_trim_disc() {
859 1
        create_load_trim_device(&mut temp_disc_ref("disc_ref_trim.raw"));
860 1
    }
861
    #[test]
862 1
    fn create_load_trim_memory() {
863 1
        create_load_trim_device(&mut MemRef::new().unwrap());
864 1
    }
865

866
    #[test]
867 1
    fn create_two_load_trim_disc() {
868 1
        create_load_two_trim_device(&mut temp_disc_ref("disc_ref_two_trim.raw"));
869 1
    }
870
    #[test]
871 1
    fn create_two_load_trim_memory() {
872 1
        create_load_two_trim_device(&mut MemRef::new().unwrap());
873 1
    }
874

875
    #[test]
876 1
    fn create_not_trim_not_last_disc() {
877 1
        create_not_trim_not_last_device(&mut temp_disc_ref("disc_ref_no_trim.raw"));
878 1
    }
879

880
    #[test]
881 1
    fn create_not_trim_not_last_memory() {
882 1
        create_not_trim_not_last_device(&mut MemRef::new().unwrap());
883 1
    }
884
}

Read our documentation on viewing source code .

Loading