1use std::ops::Range;
2
3use memmap2::Mmap;
4use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes};
5
6use crate::MAX_PAGE_SIZE;
7
8use super::Result;
9
10#[derive(Debug)]
11pub enum Values<T> {
12 Owned(Box<[T]>),
13 Ref(Box<Mmap>),
14}
15
16impl<T> Values<T> {
17 const PER_PAGE: usize = MAX_PAGE_SIZE / Self::SIZE_OF_T;
18 const SIZE_OF_T: usize = size_of::<T>();
19
20 pub fn get(&self, index: usize) -> Result<Option<&T>>
21 where
22 T: TryFromBytes + IntoBytes + Immutable + KnownLayout,
23 {
24 let index = Self::index_to_decoded_index(index);
25
26 Ok(match self {
27 Self::Owned(a) => a.get(index),
28 Self::Ref(m) => {
29 let range = Self::index_to_byte_range(index);
30 let source = &m[range];
31 Some(T::try_ref_from_bytes(source)?)
32 }
33 })
34 }
35
36 pub fn as_arr(&self) -> &[T] {
37 match self {
38 Self::Owned(a) => a,
39 Self::Ref(_) => unreachable!(),
40 }
41 }
42
43 pub fn as_mmap(&self) -> &Mmap {
44 match self {
45 Self::Owned(_) => unreachable!(),
46 Self::Ref(m) => m,
47 }
48 }
49
50 #[inline]
51 fn index_to_byte_range(index: usize) -> Range<usize> {
52 let index = Self::index_to_byte_index(index) as usize;
53 index..(index + Self::SIZE_OF_T)
54 }
55
56 #[inline]
57 fn index_to_byte_index(index: usize) -> u64 {
58 (index * Self::SIZE_OF_T) as u64
59 }
60
61 #[inline(always)]
62 fn index_to_decoded_index(index: usize) -> usize {
63 index % Self::PER_PAGE
64 }
65}
66
67impl<T> From<Box<[T]>> for Values<T> {
68 fn from(value: Box<[T]>) -> Self {
69 Self::Owned(value)
70 }
71}
72
73impl<T> From<Mmap> for Values<T> {
74 fn from(value: Mmap) -> Self {
75 Self::Ref(Box::new(value))
76 }
77}
78
79impl<T> Default for Values<T> {
80 fn default() -> Self {
81 Self::Owned(vec![].into_boxed_slice())
82 }
83}