flex_page/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(target_family = "wasm", feature(wasi_ext))]
3
4mod file_ext;
5pub mod page_no;
6
7use file_ext::FileExt;
8use std::fmt;
9use std::fs::File;
10use std::io::{ErrorKind, Result};
11use std::sync::atomic::{AtomicU64, Ordering};
12
13pub struct Pages<const SIZE: usize> {
14    /// Total Page number
15    len: AtomicU64,
16    pub file: File,
17}
18
19impl<const SIZE: usize> Pages<SIZE> {
20    /// Create a new `Pages` instance.
21    pub fn open(file: File) -> Result<Self> {
22        let block_size = SIZE as u64;
23        let file_len = file.metadata()?.len();
24        // So that, There is no residue bytes.
25        if file_len % block_size != 0 {
26            return Err(ErrorKind::InvalidData.into());
27        }
28        Ok(Self {
29            file,
30            len: (file_len / block_size).into(),
31        })
32    }
33
34    /// Read a page, without locking.
35    pub fn read(&self, num: u64) -> Result<[u8; SIZE]> {
36        debug_assert!(num < self.len() as u64);
37        let mut buf = [0; SIZE];
38        self.file.read_exact_at(&mut buf, SIZE as u64 * num)?;
39        Ok(buf)
40    }
41
42    #[inline]
43    pub fn write(&self, num: u64, buf: [u8; SIZE]) -> Result<()> {
44        debug_assert!(num < self.len() as u64);
45        self.file.write_all_at(&buf, SIZE as u64 * num)
46    }
47
48    /// Increase page number by `count`
49    pub fn alloc(&self, count: u64) -> Result<u64> {
50        let old_len = self.len.fetch_add(count, Ordering::SeqCst);
51        self.file.set_len(SIZE as u64 * (old_len + count))?;
52        Ok(old_len)
53    }
54
55    pub fn create(&self, buf: [u8; SIZE]) -> Result<u64> {
56        let num = self.len.fetch_add(1, Ordering::SeqCst);
57        self.write(num, buf)?;
58        Ok(num)
59    }
60
61    #[inline]
62    #[allow(clippy::len_without_is_empty)]
63    pub fn len(&self) -> u64 {
64        self.len.load(Ordering::SeqCst)
65    }
66
67    #[inline]
68    pub fn set_len(&self, len: u64) -> Result<()> {
69        self.len.store(len, Ordering::SeqCst);
70        self.file.set_len(SIZE as u64 * len)
71    }
72}
73
74impl<const SIZE: usize> fmt::Debug for Pages<SIZE> {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        f.debug_struct("Pages")
77            .field("len", &self.len)
78            .field("block size", &SIZE)
79            .finish()
80    }
81}