scdb/internal/
utils.rs

1use std::io;
2#[cfg(windows)]
3use std::mem;
4use std::path::Path;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7pub(crate) const TRUE_AS_BYTE: u8 = 1;
8pub(crate) const FALSE_AS_BYTE: u8 = 0;
9
10#[cfg(windows)]
11use winapi::um::sysinfoapi::{GetSystemInfo, LPSYSTEM_INFO, SYSTEM_INFO};
12
13/// Returns the Operating system's virtual memory's page size in bytes
14#[cfg(unix)]
15#[inline]
16pub(crate) fn get_vm_page_size() -> u32 {
17    unsafe { libc::sysconf(libc::_SC_PAGE_SIZE) as u32 }
18}
19
20/// Returns the Operating system's virtual memory's page size in bytes
21#[cfg(windows)]
22#[inline]
23pub(crate) fn get_vm_page_size() -> u32 {
24    unsafe {
25        let mut info: SYSTEM_INFO = mem::zeroed();
26        GetSystemInfo(&mut info as LPSYSTEM_INFO);
27
28        info.dwPageSize as u32
29    }
30}
31
32/// Returns the current timestamp in seconds from unix epoch
33pub(crate) fn get_current_timestamp() -> u64 {
34    let start = SystemTime::now();
35    let since_the_epoch = start
36        .duration_since(UNIX_EPOCH)
37        .expect("System time is poorly configured");
38    since_the_epoch.as_secs()
39}
40
41/// Creates the database folder if it does not exist
42pub(crate) fn initialize_db_folder(store_path: &Path) -> io::Result<()> {
43    std::fs::create_dir_all(store_path)
44}
45
46/// Extracts a byte array of size N from a byte array slice
47pub(crate) fn slice_to_array<const N: usize>(data: &[u8]) -> io::Result<[u8; N]> {
48    data.try_into()
49        .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
50}
51
52/// Converts a byte array into a boolean
53#[inline]
54pub(crate) fn byte_array_to_bool(data: &[u8]) -> bool {
55    data == [TRUE_AS_BYTE]
56}
57
58/// Converts a boolean into a byte array
59#[inline]
60pub(crate) fn bool_to_byte_array(value: bool) -> &'static [u8; 1] {
61    if value {
62        &[TRUE_AS_BYTE]
63    } else {
64        &[FALSE_AS_BYTE]
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use std::path::Path;
72
73    #[test]
74    fn get_vm_page_size_returns_page_size() {
75        assert!(get_vm_page_size() > 0)
76    }
77
78    #[test]
79    fn get_current_timestamp_gets_now() {
80        let some_time_in_october_2022 = 1666023836u64;
81        let now = get_current_timestamp();
82        assert!(
83            now > some_time_in_october_2022,
84            "got = {}, expected = {}",
85            now,
86            some_time_in_october_2022
87        );
88    }
89
90    #[test]
91    fn initialize_db_folder_creates_non_existing_db_folder() {
92        let store_path = Path::new("test_utils_db");
93        std::fs::remove_dir_all(store_path).unwrap_or(());
94        assert!(!Path::exists(store_path));
95
96        initialize_db_folder(store_path).expect("initializes db folder");
97
98        assert!(Path::exists(store_path));
99        std::fs::remove_dir_all(store_path).expect("removes the test_db_utils folder");
100    }
101
102    #[test]
103    fn slice_to_array_works() {
104        let data: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
105        let expected = [3u8, 4u8, 5u8, 6u8];
106        let got = slice_to_array::<4>(&data[3..7]).expect("extract 4 bytes starting at index 3");
107        assert_eq!(
108            &got, &expected,
109            "got = {:?}, expected = {:?}",
110            &got, &expected
111        );
112    }
113
114    #[test]
115    fn byte_array_to_bool_works() {
116        let test_data: [(&[u8], bool); 4] = [
117            (&[1][..], true),
118            (&[0][..], false),
119            (&[1, 1][..], false),
120            (&[0, 0, 0, 1, 0, 1][..], false),
121        ];
122
123        for (arr, expected) in test_data {
124            assert_eq!(byte_array_to_bool(arr), expected);
125        }
126    }
127}