1use std::{marker::PhantomData, num::NonZeroU64};
2
3use crate::config::{Config, ConfigPrivate};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[repr(transparent)]
17pub struct Key(NonZeroU64);
18
19impl Key {
20 pub(crate) unsafe fn new_unchecked<C: Config>(slot_id: u32, generation: Generation<C>) -> Self {
24 debug_assert!(0 < slot_id && slot_id <= C::SLOT_MASK);
25 let raw = u64::from(generation.to_u32()) << C::SLOT_BITS | u64::from(slot_id);
26 Self(unsafe { NonZeroU64::new_unchecked(raw) })
28 }
29
30 pub(crate) fn page_no<C: Config>(self) -> PageNo<C> {
31 let slot_id = self.slot_id::<C>();
32
33 let base = 32 - C::INITIAL_PAGE_SIZE.trailing_zeros() - 1;
63 let lz_repr = slot_id.leading_zeros();
64
65 let page_no = base.wrapping_sub(lz_repr);
68
69 PageNo::new(page_no)
70 }
71
72 pub(crate) fn slot_id<C: Config>(self) -> u32 {
73 self.0.get() as u32 & C::SLOT_MASK
74 }
75
76 pub(crate) fn generation<C: Config>(self) -> Generation<C> {
77 let generation = (self.0.get() >> C::SLOT_BITS) as u32 & C::GENERATION_MASK;
78 Generation::new(generation)
79 }
80}
81
82impl From<NonZeroU64> for Key {
83 fn from(raw: NonZeroU64) -> Self {
84 Self(raw)
85 }
86}
87
88impl From<Key> for NonZeroU64 {
89 fn from(key: Key) -> NonZeroU64 {
90 key.0
91 }
92}
93
94impl TryFrom<u64> for Key {
95 type Error = std::num::TryFromIntError;
96
97 fn try_from(raw: u64) -> Result<Self, Self::Error> {
98 NonZeroU64::try_from(raw).map(Into::into)
99 }
100}
101
102impl From<Key> for u64 {
103 fn from(key: Key) -> u64 {
104 key.0.get()
105 }
106}
107
108#[repr(transparent)]
111pub(crate) struct PageNo<C> {
112 value: u32,
113 _config: PhantomData<C>,
114}
115
116impl<C> Copy for PageNo<C> {}
117
118impl<C> Clone for PageNo<C> {
119 fn clone(&self) -> Self {
120 *self
121 }
122}
123
124impl<C: Config> PageNo<C> {
125 pub(crate) fn new(value: u32) -> Self {
126 Self {
127 value,
128 _config: PhantomData,
129 }
130 }
131
132 pub(crate) fn to_usize(self) -> usize {
133 self.value as usize
134 }
135
136 pub(crate) fn start_slot_id(self) -> u32 {
137 let shift = C::INITIAL_PAGE_SIZE.trailing_zeros() + self.value;
138 1 << shift
139 }
140
141 pub(crate) fn capacity(self) -> u32 {
142 C::INITIAL_PAGE_SIZE * 2u32.pow(self.value)
143 }
144}
145
146impl<C> PartialEq for PageNo<C> {
147 fn eq(&self, other: &Self) -> bool {
148 self.value == other.value
149 }
150}
151
152#[repr(transparent)]
155pub(crate) struct Generation<C> {
156 value: u32,
157 _config: PhantomData<C>,
158}
159
160impl<C> Copy for Generation<C> {}
161
162impl<C> Clone for Generation<C> {
163 fn clone(&self) -> Self {
164 *self
165 }
166}
167
168impl<C: Config> Generation<C> {
169 pub(crate) fn new(value: u32) -> Self {
170 Self {
171 value,
172 _config: PhantomData,
173 }
174 }
175
176 pub(crate) fn to_u32(self) -> u32 {
177 self.value
178 }
179
180 pub(crate) fn inc(self) -> Self {
181 Self {
182 value: (self.value + 1) & C::GENERATION_MASK,
183 _config: PhantomData,
184 }
185 }
186}
187
188impl<C> PartialEq for Generation<C> {
189 fn eq(&self, other: &Self) -> bool {
190 self.value == other.value
191 }
192}
193
194#[test]
195#[allow(clippy::clone_on_copy)]
196fn test_roundtrip() {
197 let nz = NonZeroU64::new(42).unwrap();
198 assert_eq!(NonZeroU64::from(Key::from(nz)), nz);
199
200 let pn = PageNo::<crate::DefaultConfig>::new(42);
201 assert!(pn.clone() == pn);
202
203 let gn = Generation::<crate::DefaultConfig>::new(42);
204 assert!(gn.clone() == gn);
205}