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

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

21
pub trait Device: Sync + Send {
22
    fn load_page(&self, page: u64) -> PRes<ReadPage>;
23

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

29
    fn flush_page(&self, page: &Page) -> PRes<()>;
30

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

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

36
    fn mark_allocated(&self, page: u64) -> PRes<u64>;
37

38
    fn sync(&self) -> PRes<()>;
39

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

42
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()>;
43
}
44

45
trait SizeTool {
46
    fn len(&self) -> PRes<u64>;
47
    fn set_len(&mut self, len: u64) -> PRes<()>;
48
}
49

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

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

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

81
impl ReadPage {
82 1
    pub fn get_size_exp(&mut self) -> u8 {
83 1
        self.exp
84 1
    }
85

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

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

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

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

145
pub trait PageOps {
146
    /// Seek the internal cursor of the page to the specified absolute position
147
    fn seek(&mut self, pos: u32);
148
    fn get_index(&self) -> u64;
149
    fn get_size_exp(&self) -> u8;
150
    fn clone_read(&self) -> ReadPage;
151
    fn clone_write(&self) -> Page;
152
    fn is_free(&self) -> PRes<bool>;
153
    fn cursor_pos(&self) -> usize;
154
}
155

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

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

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

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

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

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

250
impl Page {
251 1
    pub fn set_free(&mut self, free: bool) -> PRes<()> {
252 1
        self.buff[1] = free_flag_set(self.buff[1], free);
253 1
        Ok(())
254 1
    }
255

256 1
    pub fn set_next_free(&mut self, next: u64) {
257 1
        let pre = self.pos;
258 1
        self.pos = 2;
259 1
        InfallibleWriteFormat::write_u64(self, next);
260 1
        self.pos = pre;
261 1
    }
262

263 1
    pub fn get_next_free(&mut self) -> u64 {
264 1
        let pre = self.pos;
265 1
        self.pos = 2;
266 1
        let val = InfallibleReadFormat::read_u64(self);
267 1
        self.pos = pre;
268
        val
269 1
    }
270

271 1
    pub fn set_prev_free(&mut self, next: u64) {
272 1
        let pre = self.pos;
273 1
        self.pos = 10;
274 1
        InfallibleWriteFormat::write_u64(self, next);
275 1
        self.pos = pre;
276 1
    }
277

278 1
    pub fn get_prev_free(&mut self) -> u64 {
279 1
        let pre = self.pos;
280 1
        self.pos = 10;
281 1
        let val = InfallibleReadFormat::read_u64(self);
282 1
        self.pos = pre;
283
        val
284 1
    }
285

286 1
    pub fn reset(&mut self) -> PRes<()> {
287 1
        self.buff = vec![0; self.buff.len()];
288 1
        self.buff[0] = self.exp;
289 1
        Ok(())
290 1
    }
291

292 1
    pub fn make_read(self) -> ReadPage {
293 1
        ReadPage::new(Arc::new(self.buff), 2, self.index, self.exp)
294 1
    }
295
}
296

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

308 1
fn create_page_raw<T: SizeTool + Seek>(fl: &mut T, exp: u8) -> PRes<u64> {
309 1
    let offset = fl.seek(SeekFrom::End(0))?;
310 1
    let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
311 1
    fl.set_len(offset + size)?;
312 1
    Ok(offset)
313 1
}
314

315 1
fn load_page_raw<T: Read + Seek>(fl: &mut T, page: u64, size_exp: u8) -> PRes<Page> {
316 1
    let mut ve;
317
    let size;
318
    {
319 1
        fl.seek(SeekFrom::Start(page))?;
320 1
        size = (1 << size_exp) as u64; //EXP - (size_exp+size_mitigator);
321 1
        ve = vec![0 as u8; size as usize];
322 1
        fl.read_exact(&mut ve[0..size as usize])?;
323
    }
324 1
    Ok(Page::new(ve, 0, page, size_exp))
325 1
}
326

327 1
fn flush_page<T: Write + Seek>(fl: &mut T, page: &Page) -> PRes<()> {
328 1
    fl.seek(SeekFrom::Start(page.index))?;
329 1
    fl.write_all(&page.buff)?;
330 1
    Ok(())
331 1
}
332

333 1
fn create_page<T: Write + Seek>(fl: &mut T, exp: u8) -> PRes<Page> {
334 1
    let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
335 1
    let mut ve = vec![0 as u8; size as usize];
336 1
    ve[0] = exp;
337 1
    ve[size as usize - 1] = exp;
338 1
    let offset = fl.seek(SeekFrom::End(0))?;
339 1
    fl.write_all(&ve)?; //exp
340 1
    Ok(Page::new(ve, 2, offset, exp))
341 1
}
342

343 0
fn mark_allocated<T: Write + Read + Seek>(fl: &mut T, page: u64) -> PRes<u64> {
344 0
    fl.seek(SeekFrom::Start(page + 2))?;
345
    // Free pages are a linked list reading the next page and return
346 0
    let next = fl.read_u64()?;
347 0
    fl.seek(SeekFrom::Start(page + 1))?;
348 0
    let mut moderator = fl.read_u8()?;
349 0
    moderator = free_flag_set(moderator, false);
350 0
    fl.seek(SeekFrom::Start(page + 1))?;
351 0
    fl.write_u8(moderator)?;
352 0
    Ok(next)
353 0
}
354

355 1
fn trim_or_free_page<T: Write + Read + Seek + SizeTool>(
356
    fl: &mut T,
357
    page: u64,
358
    update_list: &mut dyn UpdateList,
359
) -> PRes<()> {
360 1
    fl.seek(SeekFrom::Start(page))?;
361 1
    let exp = fl.read_u8()?;
362 1
    let size = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
363 1
    if page + size == fl.len()? {
364 1
        fl.set_len(page)?;
365 1
        while check_and_trim(fl, update_list)? {}
366
    } else {
367 1
        let old = update_list.update(exp, page)?;
368 1
        fl.seek(SeekFrom::Start(page + 1))?;
369 1
        let mut mitigator = fl.read_u8()?;
370 1
        debug_assert!(!is_free(mitigator), "freeing: {} already freed ", page);
371 1
        mitigator = free_flag_set(mitigator, true);
372 1
        let mut data: [u8; 9] = [0; 9];
373 1
        data[0] = mitigator;
374 1
        write_u64(&mut data[1..9], old);
375 1
        fl.seek(SeekFrom::Start(page + 1))?;
376 1
        fl.write_all(&data)?;
377 1
        if exp >= 5 {
378 1
            fl.write_all(&[0u8; 16])?;
379
        }
380

381 1
        let mut data = [0; 8];
382 1
        write_u64(&mut data, page);
383 1
        fl.seek(SeekFrom::Start(old + 10))?;
384 1
        fl.write_all(&data)?;
385
    }
386 1
    Ok(())
387 1
}
388

389 1
fn check_and_trim<T: Write + Read + Seek + SizeTool>(fl: &mut T, update_list: &mut dyn UpdateList) -> PRes<bool> {
390 1
    let len = fl.seek(SeekFrom::End(0))?;
391 1
    if len == 0 {
392 1
        return Ok(false);
393
    }
394

395 1
    fl.seek(SeekFrom::Start(len - 1))?;
396 1
    let exp = fl.read_u8()?;
397 1
    if exp == 0 {
398 0
        return Ok(false);
399
    }
400 1
    let size = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
401 1
    let mut header = [0u8; 18];
402 1
    let page = len - size;
403 1
    if page == 0 {
404 1
        return Ok(false);
405
    }
406 1
    fl.seek(SeekFrom::Start(page + 1))?;
407 1
    fl.read_exact(&mut header)?;
408 1
    if is_free(header[0]) {
409 1
        let next = read_u64(&header[2..10]);
410 1
        let prev = read_u64(&header[10..18]);
411 1
        if prev == 0 {
412 1
            update_list.remove(exp, page, next)?;
413
        } else {
414 0
            let mut data = [8u8];
415 0
            write_u64(&mut data, next);
416 0
            fl.seek(SeekFrom::Start(prev + 10))?;
417 0
            fl.write_all(&data)?;
418 0
            write_u64(&mut data, prev);
419 0
            fl.seek(SeekFrom::Start(next + 2))?;
420 0
            fl.write_all(&data)?;
421
        }
422 1
        fl.set_len(page)?;
423 1
        Ok(true)
424
    } else {
425 0
        Ok(false)
426
    }
427 1
}
428

429
#[cfg(unix)]
430
pub struct DiscRef {
431
    file: File,
432
    size: Mutex<u64>,
433
}
434

435
#[cfg(unix)]
436
impl DiscRef {
437 1
    pub fn new(file: File) -> PRes<DiscRef> {
438 1
        let len = file.len()?;
439 1
        Ok(DiscRef {
440 1
            file,
441 1
            size: Mutex::new(len),
442 0
        })
443 1
    }
444

445 1
    fn create_page_offset(&self, size: u64) -> PRes<u64> {
446 1
        let mut current = self.size.lock()?;
447 1
        let page = *current;
448 1
        *current += size;
449 1
        Ok(page)
450 1
    }
451 1
    fn trim_if_possible(&self, page: u64, size: u64) -> PRes<bool> {
452 1
        let mut current = self.size.lock()?;
453 1
        if page + size == *current {
454 1
            *current = page;
455 1
            self.file.set_len(page)?;
456 1
            Ok(true)
457
        } else {
458 1
            Ok(false)
459
        }
460 1
    }
461

462 1
    fn check_and_trim(&self, update_list: &mut dyn UpdateList) -> PRes<bool> {
463
        use std::os::unix::prelude::FileExt;
464 1
        let mut lock = self.size.lock()?;
465 1
        let value = *lock;
466 1
        if value == 0 {
467 1
            return Ok(false);
468
        }
469 1
        let mut exp = [0u8];
470 1
        self.file.read_exact_at(&mut exp, value - 1)?;
471 1
        if exp[0] == 0 {
472 0
            return Ok(false);
473
        }
474 1
        let size = (1 << exp[0]) as u64; //EXP - (size_exp+size_mitigator);
475 1
        let mut header = [0u8; 18];
476 1
        let page = value - size;
477 1
        if page == 0 {
478 1
            return Ok(false);
479
        }
480 1
        self.file.read_exact_at(&mut header, page + 1)?;
481 1
        if is_free(header[0]) {
482 1
            let next = read_u64(&header[2..10]);
483 1
            let prev = read_u64(&header[10..18]);
484 1
            if prev == 0 {
485 1
                update_list.remove(exp[0], page, next)?;
486
            } else {
487 0
                let mut data = [8u8];
488 0
                write_u64(&mut data, next);
489 0
                self.file.write_all_at(&data, prev + 10)?;
490 0
                write_u64(&mut data, prev);
491 0
                self.file.write_all_at(&data, next + 2)?;
492
            }
493 1
            *lock = page;
494 1
            self.file.set_len(page)?;
495 1
            Ok(true)
496
        } else {
497 1
            Ok(false)
498
        }
499 1
    }
500
}
501

502
#[cfg(unix)]
503
impl Device for DiscRef {
504 1
    fn load_page(&self, page: u64) -> PRes<ReadPage> {
505
        use std::os::unix::prelude::FileExt;
506 1
        let mut exp = [0u8];
507 1
        self.file.read_exact_at(&mut exp, page)?;
508 1
        let size = (1 << exp[0]) as u64; //EXP - (size_exp+size_mitigator);
509 1
        let mut ve = vec![0 as u8; size as usize];
510 1
        ve[0] = exp[0];
511 1
        self.file.read_exact_at(&mut ve[1..size as usize], page + 1)?;
512
        // add 2 to skip the metadata
513 1
        Ok(ReadPage::new(Arc::new(ve), 2, page, exp[0]))
514 1
    }
515

516 1
    fn load_page_raw(&self, page: u64, size_exp: u8) -> PRes<Page> {
517
        use std::os::unix::prelude::FileExt;
518 1
        let size = (1 << size_exp) as u64; //EXP - (size_exp+size_mitigator);
519 1
        let mut ve = vec![0 as u8; size as usize];
520 1
        self.file.read_exact_at(&mut ve, page)?;
521 1
        Ok(Page::new(ve, 0, page, size_exp))
522 1
    }
523

524 1
    fn flush_page(&self, page: &Page) -> PRes<()> {
525
        use std::os::unix::prelude::FileExt;
526 1
        self.file.write_all_at(&page.buff, page.get_index())?;
527 1
        Ok(())
528 1
    }
529

530 1
    fn create_page_raw(&self, exp: u8) -> PRes<u64> {
531
        use std::os::unix::prelude::FileExt;
532 1
        let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
533 1
        let offset = self.create_page_offset(size)?;
534 1
        let mut ve = [0u8];
535 1
        ve[0] = exp;
536 1
        self.file.write_all_at(&ve, offset + size - 1)?; //exp
537 1
        Ok(offset)
538 1
    }
539

540 1
    fn create_page(&self, exp: u8) -> PRes<Page> {
541
        use std::os::unix::prelude::FileExt;
542 1
        let size: u64 = (1 << exp) as u64; //EXP - (size_exp+size_mitigator);
543 1
        let offset = self.create_page_offset(size)?;
544 1
        let mut ve = vec![0 as u8; size as usize];
545 1
        ve[0] = exp;
546 1
        ve[size as usize - 1] = exp;
547 1
        self.file.write_all_at(&ve, offset)?; //exp
548 1
        Ok(Page::new(ve, 2, offset, exp))
549 1
    }
550

551 1
    fn mark_allocated(&self, page: u64) -> PRes<u64> {
552
        use std::os::unix::prelude::FileExt;
553 1
        let mut next_data = [0u8; 8];
554 1
        self.file.read_exact_at(&mut next_data, page + 2)?;
555
        // Free pages are a linked list reading the next page and return
556 1
        let mut mitigator = [0u8];
557 1
        self.file.read_exact_at(&mut mitigator, page + 1)?;
558 1
        mitigator[0] = free_flag_set(mitigator[0], false);
559 1
        self.file.write_all_at(&mitigator, page + 1)?;
560 1
        Ok(read_u64(&next_data))
561 1
    }
562

563 1
    fn sync(&self) -> PRes<()> {
564 1
        self.file.sync_data()?;
565 1
        Ok(())
566 1
    }
567

568 1
    fn trim_or_free_page(&self, page: u64, update_list: &mut dyn UpdateList) -> PRes<()> {
569
        use std::os::unix::prelude::FileExt;
570 1
        let mut exp = [0u8];
571 1
        self.file.read_exact_at(&mut exp, page)?;
572 1
        let size = (1 << exp[0]) as u64; //EXP - (size_exp+size_mitigator);
573 1
        if !self.trim_if_possible(page, size)? {
574 1
            let old = update_list.update(exp[0], page)?;
575 1
            let mut mitigator = [0u8];
576 1
            self.file.read_exact_at(&mut mitigator, page + 1)?;
577 1
            debug_assert!(!is_free(mitigator[0]), "freeing: {} already freed ", page);
578 1
            mitigator[0] = free_flag_set(mitigator[0], true);
579 1
            let mut data: [u8; 9] = [0; 9];
580 1
            data[0] = mitigator[0];
581 1
            write_u64(&mut data[1..9], old);
582 1
            self.file.write_all_at(&data, page + 1)?;
583 1
            if exp[0] >= 5 {
584 1
                self.file.write_all_at(&[0u8; 16], page + 10)?;
585
            }
586 1
            let mut data = [0; 8];
587 1
            write_u64(&mut data, page);
588 1
            self.file.write_all_at(&data, old + 10)?;
589
        } else {
590 1
            self.trim_end_pages(update_list)?;
591
        }
592 1
        Ok(())
593 1
    }
594

595 1
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()> {
596 1
        while self.check_and_trim(update_list)? {}
597 1
        Ok(())
598 1
    }
599
}
600

601
#[cfg(not(unix))]
602
pub struct FileHandler {
603
    file: File,
604
    metadata_changed: bool,
605
}
606

607
#[cfg(not(unix))]
608
pub struct DiscRef {
609
    file: Mutex<FileHandler>,
610
}
611

612
#[cfg(not(unix))]
613
impl DiscRef {
614
    pub fn new(file: File) -> PRes<DiscRef> {
615
        Ok(DiscRef {
616
            file: Mutex::new(FileHandler {
617
                file,
618
                metadata_changed: false,
619
            }),
620
        })
621
    }
622
}
623

624
#[cfg(not(unix))]
625
impl Device for DiscRef {
626
    fn load_page(&self, page: u64) -> PRes<ReadPage> {
627
        load_page(&mut self.file.lock()?.file, page)
628
    }
629

630
    fn load_page_raw(&self, page: u64, size_exp: u8) -> PRes<Page> {
631
        load_page_raw(&mut self.file.lock()?.file, page, size_exp)
632
    }
633

634
    fn flush_page(&self, page: &Page) -> PRes<()> {
635
        flush_page(&mut self.file.lock()?.file, page)
636
    }
637

638
    fn create_page_raw(&self, exp: u8) -> PRes<u64> {
639
        let lock = &mut self.file.lock()?;
640
        lock.metadata_changed = true;
641
        create_page_raw(&mut lock.file, exp)
642
    }
643

644
    fn create_page(&self, exp: u8) -> PRes<Page> {
645
        let lock = &mut self.file.lock()?;
646
        lock.metadata_changed = true;
647
        create_page(&mut lock.file, exp)
648
    }
649

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

654
    fn sync(&self) -> PRes<()> {
655
        let to_sync;
656
        let metadata_changed;
657
        {
658
            let mut lock = self.file.lock()?;
659
            to_sync = lock.file.try_clone()?;
660
            metadata_changed = lock.metadata_changed;
661
            lock.metadata_changed = false;
662
        }
663
        if metadata_changed {
664
            to_sync.sync_all()?;
665
        } else {
666
            to_sync.sync_data()?;
667
        }
668
        Ok(())
669
    }
670

671
    fn trim_or_free_page(&self, page: u64, update_list: &mut dyn UpdateList) -> PRes<()> {
672
        trim_or_free_page(&mut self.file.lock()?.file, page, update_list)
673
    }
674

675
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()> {
676
        while check_and_trim(&mut self.file.lock()?.file, update_list)? {}
677
        Ok(())
678
    }
679
}
680

681
pub struct MemRef {
682
    data: Mutex<Cursor<Vec<u8>>>,
683
}
684
impl MemRef {
685 1
    pub fn new() -> PRes<MemRef> {
686 1
        Ok(MemRef {
687 1
            data: Mutex::new(Cursor::new(Vec::new())),
688
        })
689 1
    }
690
}
691

692
impl Device for MemRef {
693 1
    fn load_page(&self, page: u64) -> PRes<ReadPage> {
694 1
        load_page(&mut *self.data.lock()?, page)
695 1
    }
696

697 1
    fn load_page_raw(&self, page: u64, size_exp: u8) -> PRes<Page> {
698 1
        load_page_raw(&mut *self.data.lock()?, page, size_exp)
699 1
    }
700

701 1
    fn flush_page(&self, page: &Page) -> PRes<()> {
702 1
        flush_page(&mut *self.data.lock()?, page)
703 1
    }
704

705 1
    fn create_page_raw(&self, exp: u8) -> PRes<u64> {
706 1
        create_page_raw(&mut *self.data.lock()?, exp)
707 1
    }
708

709 1
    fn create_page(&self, exp: u8) -> PRes<Page> {
710 1
        create_page(&mut *self.data.lock()?, exp)
711 1
    }
712

713 0
    fn mark_allocated(&self, page: u64) -> PRes<u64> {
714 0
        mark_allocated(&mut *self.data.lock()?, page)
715 0
    }
716

717 1
    fn sync(&self) -> PRes<()> {
718 1
        Ok(())
719 1
    }
720

721 1
    fn trim_or_free_page(&self, page: u64, update_list: &mut dyn UpdateList) -> PRes<()> {
722 1
        trim_or_free_page(&mut *self.data.lock()?, page, update_list)
723 1
    }
724 0
    fn trim_end_pages(&self, update_list: &mut dyn UpdateList) -> PRes<()> {
725 0
        while check_and_trim(&mut *self.data.lock()?, update_list)? {}
726 0
        Ok(())
727 0
    }
728
}
729
#[cfg(test)]
730
mod tests {
731
    use super::{Device, DiscRef, MemRef, PageOps, UpdateList};
732
    use crate::error::PRes;
733
    use byteorder::{ReadBytesExt, WriteBytesExt};
734
    use tempfile::Builder;
735

736 1
    fn temp_disc_ref(name: &str) -> DiscRef {
737 1
        DiscRef::new(
738 1
            Builder::new()
739
                .prefix(name)
740
                .suffix(".persy")
741
                .tempfile()
742
                .unwrap()
743
                .reopen()
744
                .unwrap(),
745
        )
746
        .unwrap()
747 1
    }
748

749 1
    fn create_load_flush_page_device(device: &mut dyn Device) {
750 1
        let page = device.create_page(5).unwrap().get_index();
751 1
        let pg = device.load_page(page).unwrap();
752 1
        device.flush_page(&mut pg.clone_write()).unwrap();
753 1
    }
754

755 1
    fn set_get_next_free_device(device: &mut dyn Device) {
756 1
        let page = device.create_page(5).unwrap().get_index();
757 1
        let pg = &mut device.load_page(page).unwrap().clone_write();
758 1
        pg.set_next_free(30);
759 1
        device.flush_page(pg).unwrap();
760 1
        let pg1 = &mut device.load_page(page).unwrap().clone_write();
761 1
        let val = pg1.get_next_free();
762 1
        assert_eq!(val, 30);
763 1
    }
764

765 1
    fn get_size_page_device(device: &mut dyn Device) {
766 1
        let page = device.create_page(5).unwrap().get_index();
767 1
        let pg = &mut device.load_page(page).unwrap();
768 1
        let sz = pg.get_size_exp();
769 1
        assert_eq!(sz, 5);
770 1
    }
771

772 1
    fn write_read_page_device(device: &mut dyn Device) {
773 1
        let page = device.create_page(5).unwrap().get_index();
774
        {
775 1
            let pg = &mut device.load_page(page).unwrap().clone_write();
776 1
            pg.write_u8(10).unwrap();
777 1
            device.flush_page(pg).unwrap();
778 1
        }
779
        {
780 1
            let pg = &mut device.load_page(page).unwrap();
781 1
            let va = pg.read_u8().unwrap();
782 1
            assert_eq!(va, 10);
783 1
            let sz = pg.get_size_exp();
784 1
            assert_eq!(sz, 5);
785 1
        }
786 1
    }
787

788
    struct PanicCase {}
789
    impl UpdateList for PanicCase {
790 0
        fn update(&mut self, _: u8, _: u64) -> PRes<u64> {
791 0
            panic!("should not put the free in the free list")
792
        }
793 0
        fn remove(&mut self, _: u8, _: u64, _: u64) -> PRes<()> {
794 0
            panic!("should not put the free in the free list")
795
        }
796
    }
797

798 1
    fn create_load_trim_device(device: &mut dyn Device) {
799 1
        let page = device.create_page(5).unwrap().get_index();
800 1
        let pg = &mut device.load_page(page).unwrap().clone_write();
801 1
        device.flush_page(pg).unwrap();
802 1
        device.trim_or_free_page(page, &mut PanicCase {}).unwrap();
803 1
        assert!(device.load_page(page).is_err());
804 1
    }
805

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

819
    struct IgnoreCase {}
820
    impl UpdateList for IgnoreCase {
821 1
        fn update(&mut self, _: u8, _: u64) -> PRes<u64> {
822 1
            Ok(0)
823 1
        }
824 1
        fn remove(&mut self, _: u8, _: u64, _: u64) -> PRes<()> {
825 1
            Ok(())
826 1
        }
827
    }
828

829 1
    fn create_not_trim_not_last_device(device: &mut dyn Device) {
830 1
        let page = device.create_page(5).unwrap().get_index();
831 1
        let _page_after = device.create_page(5).unwrap();
832 1
        let pg = &mut device.load_page(page).unwrap().clone_write();
833 1
        device.flush_page(pg).unwrap();
834 1
        device.trim_or_free_page(page, &mut IgnoreCase {}).unwrap();
835 1
        let load_page = device.load_page(page);
836 1
        assert!(load_page.is_ok());
837 1
        assert!(load_page.unwrap().is_free().unwrap());
838 1
    }
839

840
    #[test]
841 1
    fn create_load_flush_page_disc() {
842 1
        create_load_flush_page_device(&mut temp_disc_ref("disc_ref.raw"));
843 1
    }
844

845
    #[test]
846 1
    fn create_load_flush_page_memory() {
847 1
        create_load_flush_page_device(&mut MemRef::new().unwrap());
848 1
    }
849

850
    #[test]
851 1
    fn set_get_next_free_disc() {
852 1
        set_get_next_free_device(&mut temp_disc_ref("set_free.raw"));
853 1
    }
854

855
    #[test]
856 1
    fn set_get_next_free_memory() {
857 1
        set_get_next_free_device(&mut MemRef::new().unwrap());
858 1
    }
859

860
    #[test]
861 1
    fn get_size_page_disc() {
862 1
        get_size_page_device(&mut temp_disc_ref("get_size.raw"));
863 1
    }
864
    #[test]
865 1
    fn get_size_page_memory() {
866 1
        get_size_page_device(&mut MemRef::new().unwrap());
867 1
    }
868

869
    #[test]
870 1
    fn write_read_page_disc() {
871 1
        write_read_page_device(&mut temp_disc_ref("write_read.raw"));
872 1
    }
873
    #[test]
874 1
    fn write_read_page_memory() {
875 1
        write_read_page_device(&mut MemRef::new().unwrap());
876 1
    }
877

878
    #[test]
879 1
    fn create_load_trim_disc() {
880 1
        create_load_trim_device(&mut temp_disc_ref("disc_ref_trim.raw"));
881 1
    }
882
    #[test]
883 1
    fn create_load_trim_memory() {
884 1
        create_load_trim_device(&mut MemRef::new().unwrap());
885 1
    }
886

887
    #[test]
888 1
    fn create_two_load_trim_disc() {
889 1
        create_load_two_trim_device(&mut temp_disc_ref("disc_ref_two_trim.raw"));
890 1
    }
891
    #[test]
892 1
    fn create_two_load_trim_memory() {
893 1
        create_load_two_trim_device(&mut MemRef::new().unwrap());
894 1
    }
895

896
    #[test]
897 1
    fn create_not_trim_not_last_disc() {
898 1
        create_not_trim_not_last_device(&mut temp_disc_ref("disc_ref_no_trim.raw"));
899 1
    }
900

901
    #[test]
902 1
    fn create_not_trim_not_last_memory() {
903 1
        create_not_trim_not_last_device(&mut MemRef::new().unwrap());
904 1
    }
905
}

Read our documentation on viewing source code .

Loading