bbolt_rs/common/page/
mod.rs1use crate::common::PgId;
2use bytemuck::{Pod, Zeroable};
3use freelist::FREE_LIST_PAGE_FLAG;
4use meta::META_PAGE_FLAG;
5use std::borrow::Cow;
6use std::cmp::Ordering;
7use std::marker::PhantomData;
8use std::mem;
9use std::ops::{Deref, DerefMut};
10use tree::branch::BRANCH_PAGE_FLAG;
11use tree::leaf::LEAF_PAGE_FLAG;
12
13pub mod freelist;
14pub mod meta;
15pub mod tree;
16
17pub const PAGE_HEADER_SIZE: usize = mem::size_of::<PageHeader>();
18
19pub trait CoerciblePage {
22 fn page_flag() -> u16;
24
25 #[inline]
27 fn set_flag(page: &mut PageHeader) {
28 page.flags = Self::page_flag();
29 }
30
31 fn own(bytes: *mut u8) -> Self;
35
36 #[inline]
38 unsafe fn unchecked_ref<'a>(mapped_page: &'a RefPage<'_>) -> &'a Self
39 where
40 Self: Sized,
41 {
42 &*(mapped_page as *const RefPage as *const Self)
43 }
44
45 #[inline]
47 unsafe fn unchecked_mut<'a>(mapped_page: &'a mut MutPage<'_>) -> &'a mut Self
48 where
49 Self: Sized,
50 {
51 &mut *(mapped_page as *mut MutPage<'_> as *mut Self)
52 }
53
54 #[inline]
56 fn mut_into<'a>(mapped_page: &'a mut MutPage<'_>) -> &'a mut Self
57 where
58 Self: Sized,
59 {
60 Self::set_flag(mapped_page);
61 unsafe { Self::unchecked_mut(mapped_page) }
62 }
63
64 #[inline]
66 fn coerce_ref<'a>(mapped_page: &'a RefPage<'_>) -> Option<&'a Self>
67 where
68 Self: Sized,
69 {
70 if mapped_page.flags == Self::page_flag() {
71 Some(unsafe { Self::unchecked_ref(mapped_page) })
72 } else {
73 None
74 }
75 }
76
77 #[inline]
79 fn coerce_mut<'a>(mapped_page: &'a mut MutPage<'_>) -> Option<&'a mut Self>
80 where
81 Self: Sized,
82 {
83 if mapped_page.flags == Self::page_flag() {
84 Some(unsafe { Self::unchecked_mut(mapped_page) })
85 } else {
86 None
87 }
88 }
89}
90
91#[derive(Copy, Clone, Eq, PartialEq)]
94pub struct RefPage<'tx> {
95 bytes: *const u8,
96 phantom: PhantomData<&'tx [u8]>,
97}
98
99impl<'tx> RefPage<'tx> {
100 pub fn new(bytes: *const u8) -> RefPage<'tx> {
101 RefPage {
102 bytes,
103 phantom: PhantomData,
104 }
105 }
106}
107
108impl<'tx> Deref for RefPage<'tx> {
109 type Target = PageHeader;
110
111 fn deref(&self) -> &Self::Target {
112 unsafe { &*(self.bytes as *const PageHeader) }
113 }
114}
115
116pub struct MutPage<'tx> {
119 bytes: *mut u8,
120 phantom: PhantomData<&'tx mut [u8]>,
121}
122
123impl<'tx> MutPage<'tx> {
124 pub fn new(bytes: *mut u8) -> MutPage<'tx> {
125 MutPage {
126 bytes,
127 phantom: PhantomData,
128 }
129 }
130}
131
132impl<'tx> AsRef<RefPage<'tx>> for MutPage<'tx> {
133 fn as_ref(&self) -> &RefPage<'tx> {
134 unsafe { &*(self as *const MutPage<'tx> as *const RefPage<'tx>) }
135 }
136}
137
138impl<'tx> Deref for MutPage<'tx> {
139 type Target = PageHeader;
140
141 fn deref(&self) -> &Self::Target {
142 unsafe { &*(self.bytes as *const PageHeader) }
143 }
144}
145
146impl<'tx> DerefMut for MutPage<'tx> {
147 fn deref_mut(&mut self) -> &mut Self::Target {
148 unsafe { &mut *(self.bytes as *mut PageHeader) }
149 }
150}
151
152#[repr(C)]
156#[derive(Debug, Copy, Clone, Default, Pod, Zeroable)]
157pub struct PageHeader {
158 pub id: PgId,
160 pub flags: u16,
162 pub count: u16,
164 pub overflow: u32,
167}
168
169impl PartialOrd for PageHeader {
170 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
171 Some(self.cmp(other))
172 }
173}
174
175impl Ord for PageHeader {
176 fn cmp(&self, other: &Self) -> Ordering {
177 self.id.cmp(&other.id)
178 }
179}
180
181impl PartialEq for PageHeader {
182 fn eq(&self, other: &Self) -> bool {
183 self.id == other.id
184 }
185}
186
187impl Eq for PageHeader {}
188
189impl PageHeader {
190 #[inline]
191 pub fn set_branch(&mut self) {
192 self.flags = BRANCH_PAGE_FLAG;
193 }
194
195 #[inline]
196 pub fn set_leaf(&mut self) {
197 self.flags = LEAF_PAGE_FLAG;
198 }
199
200 #[inline]
201 pub fn set_meta(&mut self) {
202 self.flags = META_PAGE_FLAG;
203 }
204
205 #[inline]
206 pub fn set_free_list(&mut self) {
207 self.flags = FREE_LIST_PAGE_FLAG;
208 }
209
210 pub fn fast_check(&self, id: PgId) {
211 assert_eq!(
212 self.id, id,
213 "Page expected to be {}, but self identifies as {}",
214 id, self.id
215 );
216 assert!(
217 self.flags == BRANCH_PAGE_FLAG
218 || self.flags == LEAF_PAGE_FLAG
219 || self.flags == META_PAGE_FLAG
220 || self.flags == FREE_LIST_PAGE_FLAG,
221 "page {}: has unexpected type/flags {}",
222 self.id,
223 self.flags
224 );
225 }
226
227 #[inline]
228 pub fn is_branch(&self) -> bool {
229 self.flags & BRANCH_PAGE_FLAG != 0
230 }
231
232 #[inline]
233 pub fn is_leaf(&self) -> bool {
234 self.flags & LEAF_PAGE_FLAG != 0
235 }
236
237 #[inline]
238 pub fn is_meta(&self) -> bool {
239 self.flags & META_PAGE_FLAG != 0
240 }
241
242 #[inline]
243 pub fn is_free_list(&self) -> bool {
244 self.flags & FREE_LIST_PAGE_FLAG != 0
245 }
246
247 pub fn page_type(&self) -> Cow<'static, str> {
249 if self.is_branch() {
250 Cow::Borrowed("branch")
251 } else if self.is_leaf() {
252 Cow::Borrowed("leaf")
253 } else if self.is_meta() {
254 Cow::Borrowed("meta")
255 } else if self.is_free_list() {
256 Cow::Borrowed("freelist")
257 } else {
258 Cow::Owned(format!("unknown<{:#02x}>", self.flags))
259 }
260 }
261}
262
263#[derive(Debug, Eq, PartialEq)]
265pub struct PageInfo {
266 pub id: u64,
267 pub t: Cow<'static, str>,
268 pub count: u64,
269 pub overflow_count: u64,
270}