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