1use super::crc32::crc32;
30
31pub const PAGE_SIZE: usize = 4096;
33
34pub const HEADER_SIZE: usize = 32;
36
37pub const CONTENT_SIZE: usize = PAGE_SIZE - HEADER_SIZE;
39
40pub const MAX_CELLS: usize = (CONTENT_SIZE - 4) / 6; pub const MAGIC_BYTES: [u8; 4] = [0x52, 0x44, 0x44, 0x42]; pub const DB_VERSION: u32 = 0x00010000;
48
49#[repr(u8)]
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum PageType {
55 Free = 0,
57 BTreeLeaf = 1,
59 BTreeInterior = 2,
61 Overflow = 3,
63 Vector = 4,
65 FreelistTrunk = 5,
67 Header = 6,
69 GraphNode = 7,
71 GraphEdge = 8,
73 GraphAdjacency = 9,
75 GraphMeta = 10,
77 NativeMeta = 11,
79 Vault = 12,
81}
82
83impl PageType {
84 pub fn from_u8(value: u8) -> Option<Self> {
86 match value {
87 0 => Some(Self::Free),
88 1 => Some(Self::BTreeLeaf),
89 2 => Some(Self::BTreeInterior),
90 3 => Some(Self::Overflow),
91 4 => Some(Self::Vector),
92 5 => Some(Self::FreelistTrunk),
93 6 => Some(Self::Header),
94 7 => Some(Self::GraphNode),
95 8 => Some(Self::GraphEdge),
96 9 => Some(Self::GraphAdjacency),
97 10 => Some(Self::GraphMeta),
98 11 => Some(Self::NativeMeta),
99 12 => Some(Self::Vault),
100 _ => None,
101 }
102 }
103}
104
105#[repr(u8)]
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108pub enum PageFlag {
109 Dirty = 0x01,
111 Locked = 0x02,
113 Loaded = 0x04,
115 Pinned = 0x08,
117 Encrypted = 0x10,
119}
120
121#[derive(Debug, Clone, Copy)]
139pub struct PageHeader {
140 pub page_type: PageType,
142 pub flags: u8,
144 pub cell_count: u16,
146 pub free_start: u16,
148 pub free_end: u16,
150 pub page_id: u32,
152 pub parent_id: u32,
154 pub right_child: u32,
156 pub lsn: u64,
158 pub checksum: u32,
160}
161
162impl PageHeader {
163 pub fn new(page_type: PageType, page_id: u32) -> Self {
165 Self {
166 page_type,
167 flags: 0,
168 cell_count: 0,
169 free_start: HEADER_SIZE as u16,
170 free_end: PAGE_SIZE as u16,
171 page_id,
172 parent_id: 0,
173 right_child: 0,
174 lsn: 0,
175 checksum: 0,
176 }
177 }
178
179 pub fn to_bytes(&self) -> [u8; HEADER_SIZE] {
181 let mut buf = [0u8; HEADER_SIZE];
182
183 buf[0] = self.page_type as u8;
184 buf[1] = self.flags;
185 buf[2..4].copy_from_slice(&self.cell_count.to_le_bytes());
186 buf[4..6].copy_from_slice(&self.free_start.to_le_bytes());
187 buf[6..8].copy_from_slice(&self.free_end.to_le_bytes());
188 buf[8..12].copy_from_slice(&self.page_id.to_le_bytes());
189 buf[12..16].copy_from_slice(&self.parent_id.to_le_bytes());
190 buf[16..20].copy_from_slice(&self.right_child.to_le_bytes());
191 buf[20..28].copy_from_slice(&self.lsn.to_le_bytes());
192 buf[28..32].copy_from_slice(&self.checksum.to_le_bytes());
193
194 buf
195 }
196
197 pub fn from_bytes(buf: &[u8; HEADER_SIZE]) -> Result<Self, PageError> {
199 let page_type = PageType::from_u8(buf[0]).ok_or(PageError::InvalidPageType(buf[0]))?;
200
201 Ok(Self {
202 page_type,
203 flags: buf[1],
204 cell_count: u16::from_le_bytes([buf[2], buf[3]]),
205 free_start: u16::from_le_bytes([buf[4], buf[5]]),
206 free_end: u16::from_le_bytes([buf[6], buf[7]]),
207 page_id: u32::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]),
208 parent_id: u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
209 right_child: u32::from_le_bytes([buf[16], buf[17], buf[18], buf[19]]),
210 lsn: u64::from_le_bytes([
211 buf[20], buf[21], buf[22], buf[23], buf[24], buf[25], buf[26], buf[27],
212 ]),
213 checksum: u32::from_le_bytes([buf[28], buf[29], buf[30], buf[31]]),
214 })
215 }
216
217 #[inline]
219 pub fn has_flag(&self, flag: PageFlag) -> bool {
220 self.flags & (flag as u8) != 0
221 }
222
223 #[inline]
225 pub fn set_flag(&mut self, flag: PageFlag) {
226 self.flags |= flag as u8;
227 }
228
229 #[inline]
231 pub fn clear_flag(&mut self, flag: PageFlag) {
232 self.flags &= !(flag as u8);
233 }
234
235 #[inline]
237 pub fn free_space(&self) -> usize {
238 if self.free_end <= self.free_start {
239 0
240 } else {
241 (self.free_end - self.free_start) as usize
242 }
243 }
244}
245
246#[derive(Debug, Clone)]
248pub enum PageError {
249 InvalidPageType(u8),
251 ChecksumMismatch { expected: u32, actual: u32 },
253 InvalidSize(usize),
255 PageFull,
257 CellOutOfBounds(usize),
259 InvalidCellPointer(u16),
261 OverflowRequired,
263}
264
265impl std::fmt::Display for PageError {
266 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
267 match self {
268 Self::InvalidPageType(t) => write!(f, "Invalid page type: {}", t),
269 Self::ChecksumMismatch { expected, actual } => {
270 write!(
271 f,
272 "Checksum mismatch: expected 0x{:08X}, got 0x{:08X}",
273 expected, actual
274 )
275 }
276 Self::InvalidSize(s) => write!(f, "Invalid page size: {} (expected {})", s, PAGE_SIZE),
277 Self::PageFull => write!(f, "Page is full"),
278 Self::CellOutOfBounds(i) => write!(f, "Cell index {} out of bounds", i),
279 Self::InvalidCellPointer(p) => write!(f, "Invalid cell pointer: {}", p),
280 Self::OverflowRequired => write!(f, "Value too large, overflow page required"),
281 }
282 }
283}
284
285impl std::error::Error for PageError {}
286
287#[derive(Clone)]
291pub struct Page {
292 data: [u8; PAGE_SIZE],
294}
295
296#[path = "page/impl.rs"]
297mod page_impl;
298impl Default for Page {
299 fn default() -> Self {
300 Self::new(PageType::Free, 0)
301 }
302}
303
304impl std::fmt::Debug for Page {
305 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
306 if let Ok(header) = self.header() {
307 f.debug_struct("Page")
308 .field("page_type", &header.page_type)
309 .field("page_id", &header.page_id)
310 .field("cell_count", &header.cell_count)
311 .field("free_space", &header.free_space())
312 .field("lsn", &header.lsn)
313 .finish()
314 } else {
315 f.debug_struct("Page")
316 .field("data", &"[invalid header]")
317 .finish()
318 }
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[test]
327 fn test_page_header_roundtrip() {
328 let header = PageHeader {
329 page_type: PageType::BTreeLeaf,
330 flags: 0x05,
331 cell_count: 42,
332 free_start: 100,
333 free_end: 4000,
334 page_id: 12345,
335 parent_id: 99,
336 right_child: 0,
337 lsn: 0xDEADBEEF,
338 checksum: 0x12345678,
339 };
340
341 let bytes = header.to_bytes();
342 let decoded = PageHeader::from_bytes(&bytes).unwrap();
343
344 assert_eq!(decoded.page_type, header.page_type);
345 assert_eq!(decoded.flags, header.flags);
346 assert_eq!(decoded.cell_count, header.cell_count);
347 assert_eq!(decoded.free_start, header.free_start);
348 assert_eq!(decoded.free_end, header.free_end);
349 assert_eq!(decoded.page_id, header.page_id);
350 assert_eq!(decoded.parent_id, header.parent_id);
351 assert_eq!(decoded.right_child, header.right_child);
352 assert_eq!(decoded.lsn, header.lsn);
353 assert_eq!(decoded.checksum, header.checksum);
354 }
355
356 #[test]
357 fn test_page_new() {
358 let page = Page::new(PageType::BTreeLeaf, 42);
359 let header = page.header().unwrap();
360
361 assert_eq!(header.page_type, PageType::BTreeLeaf);
362 assert_eq!(header.page_id, 42);
363 assert_eq!(header.cell_count, 0);
364 assert_eq!(header.free_start, HEADER_SIZE as u16);
365 assert_eq!(header.free_end, PAGE_SIZE as u16);
366 }
367
368 #[test]
369 fn test_page_checksum() {
370 let mut page = Page::new(PageType::BTreeLeaf, 1);
371 page.update_checksum();
372 assert!(page.verify_checksum().is_ok());
373
374 page.data[100] ^= 0xFF;
376 assert!(page.verify_checksum().is_err());
377 }
378
379 #[test]
380 fn test_page_insert_cell() {
381 let mut page = Page::new(PageType::BTreeLeaf, 1);
382
383 let key = b"hello";
384 let value = b"world";
385
386 let index = page.insert_cell(key, value).unwrap();
387 assert_eq!(index, 0);
388 assert_eq!(page.cell_count(), 1);
389
390 let (read_key, read_value) = page.read_cell(0).unwrap();
391 assert_eq!(read_key, key.to_vec());
392 assert_eq!(read_value, value.to_vec());
393 }
394
395 #[test]
396 fn test_page_multiple_cells() {
397 let mut page = Page::new(PageType::BTreeLeaf, 1);
398
399 for i in 0..10 {
400 let key = format!("key{:03}", i);
401 let value = format!("value{}", i);
402 page.insert_cell(key.as_bytes(), value.as_bytes()).unwrap();
403 }
404
405 assert_eq!(page.cell_count(), 10);
406
407 for i in 0..10 {
408 let (key, value) = page.read_cell(i).unwrap();
409 assert_eq!(key, format!("key{:03}", i).as_bytes());
410 assert_eq!(value, format!("value{}", i).as_bytes());
411 }
412 }
413
414 #[test]
415 fn test_page_search_key() {
416 let mut page = Page::new(PageType::BTreeLeaf, 1);
417
418 for i in [10, 20, 30, 40, 50] {
420 let key = format!("{:03}", i);
421 page.insert_cell(key.as_bytes(), b"v").unwrap();
422 }
423
424 assert_eq!(page.search_key(b"020"), Ok(1));
426 assert_eq!(page.search_key(b"040"), Ok(3));
427
428 assert_eq!(page.search_key(b"015"), Err(1));
430 assert_eq!(page.search_key(b"000"), Err(0));
431 assert_eq!(page.search_key(b"060"), Err(5));
432 }
433
434 #[test]
435 fn test_page_full() {
436 let mut page = Page::new(PageType::BTreeLeaf, 1);
437
438 let large_value = vec![0xAB; 500];
440 let mut count = 0;
441
442 loop {
443 let key = format!("key{:05}", count);
444 match page.insert_cell(key.as_bytes(), &large_value) {
445 Ok(_) => count += 1,
446 Err(PageError::PageFull) => break,
447 Err(e) => panic!("Unexpected error: {:?}", e),
448 }
449 }
450
451 assert!(count > 0);
452 assert!(count < 10); }
454
455 #[test]
456 fn test_header_page() {
457 let page = Page::new_header_page(100);
458
459 assert!(page.verify_header_page().is_ok());
460 assert_eq!(page.read_page_count(), 100);
461 assert_eq!(page.read_freelist_head(), 0);
462 }
463
464 #[test]
465 fn test_page_flags() {
466 let mut header = PageHeader::new(PageType::BTreeLeaf, 1);
467
468 assert!(!header.has_flag(PageFlag::Dirty));
469 assert!(!header.has_flag(PageFlag::Locked));
470
471 header.set_flag(PageFlag::Dirty);
472 assert!(header.has_flag(PageFlag::Dirty));
473 assert!(!header.has_flag(PageFlag::Locked));
474
475 header.set_flag(PageFlag::Locked);
476 assert!(header.has_flag(PageFlag::Dirty));
477 assert!(header.has_flag(PageFlag::Locked));
478
479 header.clear_flag(PageFlag::Dirty);
480 assert!(!header.has_flag(PageFlag::Dirty));
481 assert!(header.has_flag(PageFlag::Locked));
482 }
483
484 #[test]
485 fn test_free_space_calculation() {
486 let page = Page::new(PageType::BTreeLeaf, 1);
487 let header = page.header().unwrap();
488
489 assert_eq!(header.free_space(), PAGE_SIZE - HEADER_SIZE);
491 }
492
493 #[test]
498 fn test_all_page_types() {
499 let page_types = [
501 PageType::Free,
502 PageType::BTreeLeaf,
503 PageType::BTreeInterior,
504 PageType::Overflow,
505 PageType::Vector,
506 PageType::FreelistTrunk,
507 PageType::Header,
508 PageType::GraphNode,
509 PageType::GraphEdge,
510 PageType::GraphAdjacency,
511 PageType::GraphMeta,
512 PageType::NativeMeta,
513 PageType::Vault,
514 ];
515
516 for (i, &pt) in page_types.iter().enumerate() {
517 let page = Page::new(pt, i as u32);
518 assert_eq!(page.page_type().unwrap(), pt);
519 assert_eq!(page.page_id(), i as u32);
520 }
521 }
522
523 #[test]
524 fn test_page_type_from_u8() {
525 assert_eq!(PageType::from_u8(0), Some(PageType::Free));
526 assert_eq!(PageType::from_u8(1), Some(PageType::BTreeLeaf));
527 assert_eq!(PageType::from_u8(2), Some(PageType::BTreeInterior));
528 assert_eq!(PageType::from_u8(10), Some(PageType::GraphMeta));
529 assert_eq!(PageType::from_u8(11), Some(PageType::NativeMeta));
530 assert_eq!(PageType::from_u8(12), Some(PageType::Vault));
531 assert_eq!(PageType::from_u8(13), None);
532 assert_eq!(PageType::from_u8(255), None);
533 }
534
535 #[test]
536 fn test_page_from_slice_valid() {
537 let original = Page::new(PageType::BTreeLeaf, 123);
538 let slice = original.as_bytes();
539 let restored = Page::from_slice(slice).unwrap();
540
541 assert_eq!(restored.page_id(), 123);
542 assert_eq!(restored.page_type().unwrap(), PageType::BTreeLeaf);
543 }
544
545 #[test]
546 fn test_page_from_slice_invalid_size() {
547 let short_slice = [0u8; 100];
548 let result = Page::from_slice(&short_slice);
549 assert!(matches!(result, Err(PageError::InvalidSize(100))));
550
551 let long_slice = [0u8; 5000];
552 let result = Page::from_slice(&long_slice);
553 assert!(matches!(result, Err(PageError::InvalidSize(5000))));
554 }
555
556 #[test]
557 fn test_page_parent_and_child() {
558 let mut page = Page::new(PageType::BTreeInterior, 10);
559
560 page.set_parent_id(5);
561 page.set_right_child(15);
562
563 assert_eq!(page.parent_id(), 5);
564 assert_eq!(page.right_child(), 15);
565
566 let header = page.header().unwrap();
568 assert_eq!(header.parent_id, 5);
569 assert_eq!(header.right_child, 15);
570 }
571
572 #[test]
573 fn test_cell_pointer_bounds() {
574 let page = Page::new(PageType::BTreeLeaf, 1);
575
576 let result = page.get_cell_pointer(0);
578 assert!(matches!(result, Err(PageError::CellOutOfBounds(0))));
579
580 let result = page.get_cell_pointer(100);
581 assert!(matches!(result, Err(PageError::CellOutOfBounds(100))));
582 }
583
584 #[test]
585 fn test_cell_pointer_invalid_value() {
586 let mut page = Page::new(PageType::BTreeLeaf, 1);
587
588 let result = page.set_cell_pointer(0, 10);
590 assert!(matches!(result, Err(PageError::InvalidCellPointer(10))));
591
592 let result = page.set_cell_pointer(0, PAGE_SIZE as u16 + 1);
594 assert!(matches!(result, Err(PageError::InvalidCellPointer(_))));
595 }
596
597 #[test]
598 fn test_empty_key_value() {
599 let mut page = Page::new(PageType::BTreeLeaf, 1);
600
601 page.insert_cell(b"", b"value").unwrap();
603 let (key, value) = page.read_cell(0).unwrap();
604 assert!(key.is_empty());
605 assert_eq!(value, b"value");
606
607 page.insert_cell(b"key", b"").unwrap();
609 let (key, value) = page.read_cell(1).unwrap();
610 assert_eq!(key, b"key");
611 assert!(value.is_empty());
612
613 page.insert_cell(b"", b"").unwrap();
615 let (key, value) = page.read_cell(2).unwrap();
616 assert!(key.is_empty());
617 assert!(value.is_empty());
618 }
619
620 #[test]
621 fn test_large_value_overflow() {
622 let mut page = Page::new(PageType::BTreeLeaf, 1);
623
624 let huge_value = vec![0xAB; CONTENT_SIZE];
626 let result = page.insert_cell(b"key", &huge_value);
627 assert!(matches!(result, Err(PageError::OverflowRequired)));
628 }
629
630 #[test]
631 fn test_checksum_stability() {
632 let mut page = Page::new(PageType::BTreeLeaf, 42);
633 page.insert_cell(b"test", b"data").unwrap();
634
635 page.update_checksum();
636 let checksum1 = page.header().unwrap().checksum;
637
638 page.update_checksum();
640 let checksum2 = page.header().unwrap().checksum;
641
642 assert_eq!(checksum1, checksum2);
643 }
644
645 #[test]
646 fn test_checksum_changes_with_content() {
647 let mut page1 = Page::new(PageType::BTreeLeaf, 1);
648 let mut page2 = Page::new(PageType::BTreeLeaf, 1);
649
650 page1.insert_cell(b"key1", b"value1").unwrap();
651 page2.insert_cell(b"key2", b"value2").unwrap();
652
653 page1.update_checksum();
654 page2.update_checksum();
655
656 assert_ne!(
657 page1.header().unwrap().checksum,
658 page2.header().unwrap().checksum
659 );
660 }
661
662 #[test]
663 fn test_free_space_decreases_with_cells() {
664 let mut page = Page::new(PageType::BTreeLeaf, 1);
665 let initial_free = page.header().unwrap().free_space();
666
667 page.insert_cell(b"key", b"value").unwrap();
668 let after_first = page.header().unwrap().free_space();
669
670 page.insert_cell(b"another_key", b"another_value").unwrap();
671 let after_second = page.header().unwrap().free_space();
672
673 assert!(after_first < initial_free);
674 assert!(after_second < after_first);
675 }
676
677 #[test]
678 fn test_search_empty_page() {
679 let page = Page::new(PageType::BTreeLeaf, 1);
680
681 assert_eq!(page.search_key(b"anything"), Err(0));
683 }
684
685 #[test]
686 fn test_search_single_cell() {
687 let mut page = Page::new(PageType::BTreeLeaf, 1);
688 page.insert_cell(b"middle", b"v").unwrap();
689
690 assert_eq!(page.search_key(b"middle"), Ok(0));
692
693 assert_eq!(page.search_key(b"aaa"), Err(0));
695
696 assert_eq!(page.search_key(b"zzz"), Err(1));
698 }
699
700 #[test]
701 fn test_binary_data() {
702 let mut page = Page::new(PageType::BTreeLeaf, 1);
703
704 let binary_key = [0x00, 0x01, 0x02, 0xFF, 0xFE];
706 let binary_value = [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00];
707
708 page.insert_cell(&binary_key, &binary_value).unwrap();
709
710 let (key, value) = page.read_cell(0).unwrap();
711 assert_eq!(key, binary_key.to_vec());
712 assert_eq!(value, binary_value.to_vec());
713 }
714
715 #[test]
716 fn test_max_cells_stress() {
717 let mut page = Page::new(PageType::BTreeLeaf, 1);
718
719 let mut inserted = 0;
721 for i in 0..MAX_CELLS {
722 let key = format!("{:04}", i);
723 if page.insert_cell(key.as_bytes(), b"x").is_ok() {
724 inserted += 1;
725 } else {
726 break;
727 }
728 }
729
730 for i in 0..inserted {
732 let (key, _) = page.read_cell(i).unwrap();
733 assert_eq!(key, format!("{:04}", i).as_bytes());
734 }
735 }
736
737 #[test]
738 fn test_content_mut() {
739 let mut page = Page::new(PageType::BTreeLeaf, 1);
740
741 let content = page.content_mut();
743 content[0] = 0xAB;
744 content[1] = 0xCD;
745
746 let content = page.content();
748 assert_eq!(content[0], 0xAB);
749 assert_eq!(content[1], 0xCD);
750 }
751
752 #[test]
753 fn test_page_bytes_roundtrip() {
754 let mut page = Page::new(PageType::BTreeLeaf, 999);
755 page.insert_cell(b"key", b"value").unwrap();
756 page.update_checksum();
757
758 let bytes = *page.as_bytes();
760 let restored = Page::from_bytes(bytes);
761
762 assert_eq!(restored.page_id(), 999);
763 assert!(restored.verify_checksum().is_ok());
764
765 let (key, value) = restored.read_cell(0).unwrap();
766 assert_eq!(key, b"key");
767 assert_eq!(value, b"value");
768 }
769
770 #[test]
771 fn test_header_page_operations() {
772 let mut page = Page::new_header_page(1000);
773
774 assert!(page.verify_header_page().is_ok());
775 assert_eq!(page.read_page_count(), 1000);
776 assert_eq!(page.read_freelist_head(), 0);
777
778 page.write_page_count(2000);
780 assert_eq!(page.read_page_count(), 2000);
781
782 page.write_freelist_head(42);
784 assert_eq!(page.read_freelist_head(), 42);
785 }
786
787 #[test]
788 fn test_page_flags_multiple() {
789 let mut header = PageHeader::new(PageType::BTreeLeaf, 1);
790
791 header.set_flag(PageFlag::Dirty);
793 header.set_flag(PageFlag::Locked);
794 header.set_flag(PageFlag::Encrypted);
795
796 assert!(header.has_flag(PageFlag::Dirty));
797 assert!(header.has_flag(PageFlag::Locked));
798 assert!(header.has_flag(PageFlag::Encrypted));
799 assert!(!header.has_flag(PageFlag::Pinned));
800
801 header.clear_flag(PageFlag::Locked);
803 assert!(header.has_flag(PageFlag::Dirty));
804 assert!(!header.has_flag(PageFlag::Locked));
805 assert!(header.has_flag(PageFlag::Encrypted));
806 }
807
808 #[test]
809 fn test_page_error_display() {
810 let errors = [
811 PageError::InvalidPageType(99),
812 PageError::ChecksumMismatch {
813 expected: 0x1234,
814 actual: 0x5678,
815 },
816 PageError::InvalidSize(100),
817 PageError::PageFull,
818 PageError::CellOutOfBounds(5),
819 PageError::InvalidCellPointer(10),
820 PageError::OverflowRequired,
821 ];
822
823 for error in &errors {
824 let _msg = format!("{}", error);
826 }
827 }
828
829 #[test]
830 fn test_cell_count_consistency() {
831 let mut page = Page::new(PageType::BTreeLeaf, 1);
832
833 assert_eq!(page.cell_count(), 0);
834
835 page.insert_cell(b"a", b"1").unwrap();
836 assert_eq!(page.cell_count(), 1);
837
838 page.insert_cell(b"b", b"2").unwrap();
839 assert_eq!(page.cell_count(), 2);
840
841 page.insert_cell(b"c", b"3").unwrap();
842 assert_eq!(page.cell_count(), 3);
843
844 page.set_cell_count(0);
846 assert_eq!(page.cell_count(), 0);
847 }
848
849 #[test]
850 fn test_free_start_end_consistency() {
851 let mut page = Page::new(PageType::BTreeLeaf, 1);
852
853 let initial_start = page.free_start();
854 let initial_end = page.free_end();
855
856 assert_eq!(initial_start, HEADER_SIZE as u16);
857 assert_eq!(initial_end, PAGE_SIZE as u16);
858
859 page.insert_cell(b"test_key", b"test_value").unwrap();
860
861 let after_start = page.free_start();
862 let after_end = page.free_end();
863
864 assert!(after_start > initial_start);
866 assert!(after_end < initial_end);
868 }
869}