feophantlib/engine/io/row_formats/
item_pointer.rs1use crate::engine::io::format_traits::{Parseable, Serializable};
7use crate::engine::io::page_formats::{PageOffset, PageOffsetError};
8use crate::engine::io::ConstEncodedSize;
9
10use super::super::page_formats::{UInt12, UInt12Error};
11use bytes::{Buf, BufMut, Bytes, BytesMut};
12use std::convert::TryFrom;
13use std::fmt;
14use std::mem::size_of;
15use std::num::TryFromIntError;
16use thiserror::Error;
17
18#[derive(Clone, Copy, Debug, PartialEq)]
19pub struct ItemPointer {
20 pub page: PageOffset,
21 pub count: UInt12,
22}
23
24impl ItemPointer {
25 pub fn new(page: PageOffset, count: UInt12) -> ItemPointer {
26 ItemPointer { page, count }
27 }
28}
29
30impl ConstEncodedSize for ItemPointer {
31 fn encoded_size() -> usize {
32 size_of::<usize>() + UInt12::encoded_size()
33 }
34}
35
36impl fmt::Display for ItemPointer {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 writeln!(f, "\tItemPointer")?;
39 writeln!(f, "\tPage: {}", self.page)?;
40 writeln!(f, "\tCount: {}", self.count)
41 }
42}
43
44impl Parseable<ItemPointerError> for ItemPointer {
45 type Output = Self;
46 fn parse(buffer: &mut impl Buf) -> Result<Self, ItemPointerError> {
47 let po = PageOffset::parse(buffer)?;
48 let items = UInt12::parse_packed(buffer, 1)?;
49 Ok(ItemPointer::new(po, items[0]))
50 }
51}
52
53impl Serializable for ItemPointer {
54 fn serialize(&self, buffer: &mut impl BufMut) {
55 self.page.serialize(buffer);
56 UInt12::serialize_packed(buffer, &[self.count]);
57 }
58}
59
60#[derive(Debug, Error, PartialEq)]
61pub enum ItemPointerError {
62 #[error(transparent)]
63 PageOffsetError(#[from] PageOffsetError),
64 #[error(transparent)]
65 TryFromIntError(#[from] TryFromIntError),
66 #[error(transparent)]
67 UInt12Error(#[from] UInt12Error),
68}
69
70#[cfg(test)]
71mod tests {
72 use std::mem::size_of;
73
74 use super::*;
75
76 #[test]
77 fn sizes_match() -> Result<(), Box<dyn std::error::Error>> {
78 let test = ItemPointer::new(PageOffset(1), UInt12::new(2)?);
79 let calc_len = ItemPointer::encoded_size();
80
81 let mut buffer = BytesMut::new();
82 test.serialize(&mut buffer);
83
84 assert_eq!(calc_len, buffer.freeze().len());
85 Ok(())
86 }
87
88 #[test]
89 fn test_item_pointer_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
90 let test = ItemPointer::new(PageOffset(1), UInt12::new(1).unwrap());
91
92 let mut buffer = BytesMut::new();
93 test.serialize(&mut buffer);
94 let test_reparse = ItemPointer::parse(&mut buffer.freeze())?;
95
96 assert_eq!(test, test_reparse);
97 Ok(())
98 }
99
100 #[test]
101 fn test_item_pointer_error_conditions() -> Result<(), Box<dyn std::error::Error>> {
102 let parse = ItemPointer::parse(&mut Bytes::new());
103
104 assert_eq!(
105 Err(ItemPointerError::PageOffsetError(
106 PageOffsetError::BufferTooShort(size_of::<usize>(), 0)
107 )),
108 parse
109 );
110
111 let parse = ItemPointer::parse(&mut Bytes::from_static(&[0, 0, 0, 0, 0, 0, 0, 0, 1]));
112
113 assert_eq!(
114 Err(ItemPointerError::UInt12Error(UInt12Error::InsufficentData(
115 0
116 ))),
117 parse
118 );
119 Ok(())
120 }
121
122 #[test]
123 fn test_encoded_size() {
124 match size_of::<usize>() {
125 4 => assert_eq!(6, ItemPointer::encoded_size()),
126 8 => assert_eq!(10, ItemPointer::encoded_size()),
127 _ => panic!("You're on your own on this arch."),
128 }
129 }
130}