aboutsummaryrefslogtreecommitdiff
path: root/tests/common/mod.rs
blob: fd98539991f360ff866187147e8efaa8b4bdbd3c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#[cfg(test)]
#[allow(dead_code)]

extern crate growthring;
use growthring::wal::{WALFile, WALStore, WALPos, WALBytes};
use std::collections::{HashMap, hash_map::Entry};
use std::cell::RefCell;
use std::rc::Rc;

/*
thread_local! {
    //pub static RNG: RefCell<rand::rngs::StdRng> = RefCell::new(<rand::rngs::StdRng as rand::SeedableRng>::from_seed([0; 32]));
    pub static RNG: RefCell<rand::rngs::ThreadRng> = RefCell::new(rand::thread_rng());
}

pub fn gen_rand_letters(i: usize) -> String {
    //let mut rng = rand::thread_rng();
    RNG.with(|rng| {
        (0..i).map(|_| (rng.borrow_mut().gen::<u8>() % 26 + 'a' as u8) as char).collect()
    })
}
*/

struct FileContentEmul(RefCell<Vec<u8>>);

impl FileContentEmul {
    pub fn new() -> Self { FileContentEmul(RefCell::new(Vec::new())) }
}

impl std::ops::Deref for FileContentEmul {
    type Target = RefCell<Vec<u8>>;
    fn deref(&self) -> &Self::Target {&self.0}
}

/// Emulate the a virtual file handle.
pub struct WALFileEmul {
    file: Rc<FileContentEmul>
}

impl WALFile for WALFileEmul {
    fn allocate(&self, offset: WALPos, length: usize) -> Result<(), ()> {
        let offset = offset as usize;
        if offset + length > self.file.borrow().len() {
            self.file.borrow_mut().resize(offset + length, 0)
        }
        for v in &mut self.file.borrow_mut()[offset..offset + length] { *v = 0 }
        Ok(())
    }

    fn truncate(&self, length: usize) -> Result<(), ()> {
        self.file.borrow_mut().resize(length, 0);
        Ok(())
    }

    fn write(&self, offset: WALPos, data: WALBytes) {
        let offset = offset as usize;
        &self.file.borrow_mut()[offset..offset + data.len()].copy_from_slice(&data);
    }

    fn read(&self, offset: WALPos, length: usize) -> Option<WALBytes> {
        let offset = offset as usize;
        let file = self.file.borrow();
        if offset + length > file.len() { None }
        else {
            Some((&file[offset..offset + length]).to_vec().into_boxed_slice())
        }
    }
}

pub struct WALStoreEmulState{
    files: HashMap<String, Rc<FileContentEmul>>,
}

impl WALStoreEmulState {
    pub fn new() -> Self { WALStoreEmulState { files: HashMap::new() } }
}

/// Emulate the persistent storage state.
pub struct WALStoreEmul<'a>(&'a mut WALStoreEmulState);

impl<'a> WALStoreEmul<'a> {
    pub fn new(state: &'a mut WALStoreEmulState) -> Self {
        WALStoreEmul(state)
    }
}

impl<'a> WALStore for WALStoreEmul<'a> {
    type FileNameIter = std::vec::IntoIter<String>;

    fn open_file(&mut self, filename: &str, touch: bool) -> Option<Box<dyn WALFile>> {
        match self.0.files.entry(filename.to_string()) {
            Entry::Occupied(e) => Some(Box::new(WALFileEmul { file: e.get().clone() })),
            Entry::Vacant(e) => if touch {
                Some(Box::new(
                    WALFileEmul { file: e.insert(Rc::new(FileContentEmul::new())).clone() }))
            } else {
                None
            }
        }
    }

    fn remove_file(&mut self, filename: &str) -> Result<(), ()> {
        self.0.files.remove(filename).ok_or(()).and_then(|_| Ok(()))
    }

    fn enumerate_files(&self) -> Self::FileNameIter {
        let mut logfiles = Vec::new();
        for (fname, _) in self.0.files.iter() {
            logfiles.push(fname.clone())
        }
        logfiles.into_iter()
    }

    fn apply_payload(&mut self, payload: WALBytes) {
        println!("apply_payload(payload={})", std::str::from_utf8(&payload).unwrap())
    }
}